<?xml version="1.0" encoding="ISO-8859-1"?>
<rss version="2.0"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
 xmlns:admin="http://webns.net/mvcb/"
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>Mindoo Blog</title>
<description>Cutting edge technologies - About Java, Lotus Notes and iPhone</description>
<link>http://www.mindoo.de/web/blog.nsf/</link>
<language>en-us</language>
<lastBuildDate>Wed, 13 Mar 2013 14:53:59 +0200</lastBuildDate>
<item>
<title>My EntwicklerCamp 2013 slides: Dojo 1.8 and AMD (German)</title>
<pubDate>Wed, 13 Mar 2013 14:53:59 +0200</pubDate>
<description>
<![CDATA[ 
The closing session of EntwicklerCamp 2013 has just finished. Here are the slides for my EntwicklerCamp 2013 session about "Dojo 1.8 and AMD": Download archive: Slides as ZIP-Archive To a ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/13.03.2013145359KLEJBB.htm</link>
<category>Entwicklercamp 2013</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/13.03.2013145359KLEJBB.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/13.03.2013145359KLEJBB.htm</guid>
<content:encoded><![CDATA[ The closing session of EntwicklerCamp 2013 has just finished. <br /> <br /> Here are the slides for my EntwicklerCamp 2013 session about "Dojo 1.8 and AMD":  <br /><br />  <div align=center><a href="http://www.mindoo.de/web/ec13/slides.nsf/content/index.html#/" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/dojo18.jpg/$file/dojo18.jpg"></a> </div> <br /><br /> <br /> Download archive: <br /> <a href="http://www.mindoo.com/web/blog.nsf/dx/ec13-slides.zip/$file/ec13-slides.zip">Slides as ZIP-Archive</a> <br /> <br /> <br /> To all English speaking readers: Google Translate is your friend - the slides are in German :-) <br /> <br /> My plan is to translate them to English though and publish my demos as soon as possible.   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/13.03.2013145359KLEJBB.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/13.03.2013145359KLEJBB.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Quick tip: Fixing Dojo drag and drop issues in a Windows 8 VMWare on the Mac</title>
<pubDate>Thu, 7 Mar 2013 07:33:56 +0200</pubDate>
<description>
<![CDATA[ 
I am currently setting up a new dev environment with Windows 8 and Notes/Domino 9 to work on demos for my Dojo 1.8/AMD session at Entwicklercamp next week. To my surprise, I noticed yesterday, that d ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/07.03.2013073356KLE9QA.htm</link>
<category>Webdev</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/07.03.2013073356KLE9QA.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/07.03.2013073356KLE9QA.htm</guid>
<content:encoded><![CDATA[ I am currently setting up a new dev environment with Windows 8 and Notes/Domino 9 to work on demos for my <a href=/web/blog.nsf/dx/30.09.2012212824KLEQUC.htm target=_blank>Dojo 1.8/AMD session at Entwicklercamp</a> next week. <br /> <br />To my surprise, I noticed yesterday, that drag and drop operations on Dojo widgets did not work as expected. For example, I could not drag the splitters of a <a href="http://dojotoolkit.org/reference-guide/1.8/dijit/layout/BorderContainer.html" target=_blank>BorderContainer</a> layout widget and the columns of a <a href="http://dojotoolkit.org/reference-guide/1.8/dojox/grid/LazyTreeGrid.html" target=_blank>LazyTreeGrid</a> could not get resized. <br />It seemed as if mouse events got lost, but I only got that effect in Firefox and Chrome. In IE, everything was working fine. <br /> <br />After a bit of Googling, I found out that VMWare Fusion emulates some kind of touch device for Windows 8 and that this can get disabled by setting <br /> <br /><code>touchscreen.vusb.present = "FALSE"</code> <br /> <br />in the VMX file of the VMWare image. I tried it and it helped, drag and drop is now working again. <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/07.03.2013073356KLE9QA.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/07.03.2013073356KLE9QA.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Download links for IBM Connect 2013 session slides</title>
<pubDate>Thu, 31 Jan 2013 09:12:53 +0200</pubDate>
<description>
<![CDATA[ 
As in previous years, I copied the download URLs of all the already available session slides from the socialbizonline.com website. Unfortunately, a lot of slides are still missing and some are only pr ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/31.01.2013091253KLEBN5.htm</link>
<category>Lotusphere 2013</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/31.01.2013091253KLEBN5.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/31.01.2013091253KLEBN5.htm</guid>
<content:encoded><![CDATA[ As in previous years, I copied the download URLs of all the already available session slides from the <a href=http://www.socialbizonline.com target=_blank>socialbizonline.com</a> website. <br />Unfortunately, a lot of slides are still missing and some are only provided in black and white mode with 2-on-1 page. <br /> <br />Use your preferred download manager to download the files. I use <a href=https://addons.mozilla.org/en/firefox/addon/downthemall/ target=_blank>DownThemAll</a> for this purpose. You need to be logged in to the website to access the files. <br /> <br />Here are the download links: <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/Connect2013_PDFs.html/$file/Connect2013_PDFs.html" target="_blank">Connect2013_PDFs.html</a> <br /> <br />And here is the spreadsheet I used to format the links: <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/Connect2013_PDFs.ods/$file/Connect2013_PDFs.ods" target="_blank">Connect2013_PDFs.ods</a> <br /> <br />Have fun with it on your flight back home! <br /> <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/31.01.2013091253KLEBN5.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/31.01.2013091253KLEBN5.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Fast Notes view reading via Java API:New ViewNavigator cache methods in 8.5.3</title>
<pubDate>Thu, 17 Jan 2013 08:53:08 +0200</pubDate>
<description>
<![CDATA[ 
Preface A posting about new API methods in 8.5.3 may look a bit weird, now that the Notes/Domino R9 beta is already out for one month. I wanted to blog about this topic for one year now, actually sin ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm</link>
<category>Notesdev</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm</guid>
<content:encoded><![CDATA[ <strong>Preface</strong> <br /><br /> A posting about new API methods in 8.5.3 may look a bit weird, now that the Notes/Domino R9 beta is already out for one month. I wanted to blog about this topic for one year now, actually since last year's Lotusphere conference, where the new API methods got presented by IBM (in session "AD112 What's new in the IBM Lotus Domino Objects: Version 8.5.3 in Demos"), but could not find the time and have always expected that IBM dev would write a wiki article about it - which they haven't so far. <br /> <strong><br /> Let's get started!</strong>  <br /><br /> This blog article is about getting better view reading performance for both Java and LotusScript based applications. As discussed back in 2010 in two blog posts<br /> <br /> <a href="http://www.mindoo.com/web/blog.nsf/dx/31.03.2010220936KLERN4.htm" target="_blank">Fast Notes view reading via C API: A comparison C vs. Notes.jar</a> <br /> <a href="http://www.mindoo.com/web/blog.nsf/dx/25.04.2010235255KLETNN.htm" target="_blank">Fast Notes view reading via C API Part 2: How to read views 99.7% faster than Notes.jar </a> <br /> <br /> it is possible to <strong>get an extreme performance boost traversing view data</strong> by using raw C API methods instead of Java/LotusScript, which both bypass ECL checks that cost performance and in addition they are able to fetch multiple view entries at once (in one server transaction) instead of one at a time. <br /> <br /> Not everyone likes developing C code and compiling it for each platform an application should run on. So IBM decided to add a few methods to the 8.5.2 Java API so that everyone can get better performance. <br />  <br />Most of the improvements have been documented in the Designer wiki article <a href="http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Fast_Retrieval_of_View_Data_Using_the_ViewNavigator_Cache" target="_blank">Fast Retrieval of View Data Using the ViewNavigator Cache - V8.52</a>. <br /> Improvements have been made in the ViewNavigator class so that the methods <code>ViewNavigator.getNext()</code> and <code>ViewNavigator.getPrev()</code> can use an internal cache to preload up to 400 view entries. <br /> <br /> All you have to do is: <br /> <br /> <code><font color="#008000">//decide how many entries should be preloaded</font> <br /> int numCacheEntries=400; <br /> <br /> <font color="#008000">//get a view from a database</font> <br /> View lookupView=db.getView("myview"); <br /> <br /> <font color="#008000">//disable auto updating</font> <br /> lookupView.setAutoUpdate(false); <br /> <br /> <font color="#008000">//get a ViewNavigator instance for all the view entries</font> <br /> ViewNavigator nav=lookupView.createViewNav(); <br /> <br /> <font color="#008000">//and set the size of the preloading cache:</font> <br /> nav.setBufferMaxEntries(numCacheEntries); <br /> <br /> <font color="#008000">//and then traverse the view:</font> <br /> ViewEntry currEntry=nav.getFirst(); <br /> while (currEntry!=null) { <br />  &nbsp; &nbsp; &nbsp; &nbsp;if (currEntry.isValid()) { <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;doSomethingWithTheEntry(currEntry); <br />  &nbsp; &nbsp; &nbsp; &nbsp;} <br />  &nbsp; &nbsp; &nbsp; &nbsp;ViewEntry nextEntry=nav.getNext(); <br />  &nbsp; &nbsp; &nbsp; &nbsp;<font color="#008000">//don't forget to recycle!</font> <br />  &nbsp; &nbsp; &nbsp; &nbsp;currEntry.recycle(); <br />  &nbsp; &nbsp; &nbsp; &nbsp;currEntry=nextEntry; <br /> } <br /> <br /> nav.recycle(); <br /> lookupView.recycle();</code> <br /> <br /> This sample code reads all the entries of a view from start to end. For categorized views, entries get read as if they all were expanded, so we read parent entries first, then their child entries, next the children's child entries. <br /> <strong><br /> Reading subsets of a view</strong> <br /><br /> If reading the whole view is too much, you might just as well read a specific view category: <br /> <br /><code>ViewNavigator subCategoryNav=lookupView. <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; createViewNavFromCategory("topcategory\\subcategory_level1");</code><br /> <br /> or read unread documents: <br /> <br /><code>ViewNavigator unreadEntriesNav=lookupView.createViewNavFromAllUnread("Firstname Lastname/Company");</code><br />  <br />or start reading document entries beginning with a specific letter (first column must be sorted, e.g. by lastname): <br /> <br /><code>ViewEntry firstEntry=lookupView.getEntryByKey("L", false); <br />if (firstEntry!=null) { <br />&nbsp; &nbsp; &nbsp; &nbsp; ViewNavigator subEntriesNav=lookupView.createViewNavFrom(firstEntry); <br />&nbsp; &nbsp; &nbsp; &nbsp;  <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//we use a cache size of 50; use more if you expect more results</font><br />  &nbsp; &nbsp; &nbsp; &nbsp;subEntriesNav.setBufferMaxEntries(50); <br />  <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//traverse the view:</font><br />  &nbsp; &nbsp; &nbsp; &nbsp;<font color="#008000">//...</font>  <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; firstEntry.recycle(); <br />&nbsp; &nbsp; &nbsp; &nbsp; subEntriesNav.recycle(); <br />}</code> <br /><strong><br /> Undocumented feature: ViewNavigatort.skip(int entriesToSkip)</strong>  <br /><br /> There is one more new method in 8.5.2 that is missing in IBM's wiki article: <br /> <br /><code>int start=50; <br /> <br /><font color="#008000">//try to skip 50 entries and return the entries actually skipped</font>  <br />int skippedEntries = viewNav.skip(start); <br /> <br />if (skippedEntries==start) { <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//read the current entry after the skip operation</font>  <br />&nbsp; &nbsp; &nbsp; &nbsp; ViewEntry currEntry=viewNav.getCurrent(); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//work with currEntry</font>  <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//...</font>  <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; currEntry.recycle(); <br />}</code> <br /> <br />This method skips a number of entries from the current position (e.g. from the first entry) and is very fast, because view traversal is done in C and no column data is decoded. It returns the number of entries that were actually skipped. <br />If <code>skippedEntries</code> is less than <code>start</code>, the view does not contain enough rows, so there is nothing relevant to read. <br /> <br />The <code>skip</code> method is used in the XPages Extension Library to find relevant data for a view navigator based REST service: the code first skips "start" entries and then reads the next "count" entries from the view and returns their data as JSON. <br /> <br />Another use case for this method is counting view entries: <br />The funny thing is, that both <code>ViewNavigator.getCount()</code> and <code>ViewNavigator.skip(Integer.MAX_VALUE)</code> both the return the same count, but <strong>the latter is much faster</strong>. <br /> <br /><strong>New in 8.5.3: Better performance for other traversal methods</strong> <br /> <br />While 8.5.2 only provided improved performance for <code>ViewNavigator.getNext()</code> and <code>ViewNavigator.getPrev()</code>, 8.5.3 adds better performance for all the other traversal methods, e.g. <br /> <br /><code>public ViewEntry getNextSibling(); <br />public ViewEntry getPrevSibling(); <br />public ViewEntry getNextCategory(); <br />public ViewEntry getPrevCategory(); <br />public ViewEntry getNextDocument(); <br />public ViewEntry getPrevDocument(); <br />public ViewEntry getParent(); <br />public ViewEntry getChild();</code> <br /> <br />To activate the cache, there is a new method in <code>ViewNavigator</code> that defines the cache size and the cache filling strategy: <br /> <br /><code>public void setCacheGuidance(int maxEntries, int readMode);</code> <br /> <br />which replaces the previous <code>setBufferMaxEntries</code> method (you can still use the old method, but the new method can do the same and more). <br /> <br /><code>readMode</code> can either be the constant <br /> <br /><code>ViewNavigator.VN_CACHEGUIDANCE_READALL</code> <br />or <br /><code>ViewNavigator.VN_CACHEGUIDANCE_READSELECTIVE</code>. <br /> <br />With the first constant, the ViewNavigator fills the cache like it did in 8.5.2, that means it preloads the next <code>maxEntries</code> entries of the view as if a categorized view would be totally expanded. <br /> <br />The second constant however fills the cache with entries based on the getter method that you call next (see examples below; you can reset the cache size and mode at any time). <br /> <br /><strong>Reading category entries</strong> <br /> <br />So to quickly read all categories of a view, you could do <br /> <br /><code><font color="#008000">//decide how many entries should be preloaded</font> <br /> int numCacheEntries=400; <br /> <br /> <font color="#008000">//get a view from a database</font> <br /> View lookupView=db.getView("myview"); <br /> <br /> <font color="#008000">//disable auto updating</font> <br /> lookupView.setAutoUpdate(false); <br /> <br /> <font color="#008000">//get a ViewNavigator instance for all the view entries</font> <br /> ViewNavigator nav=lookupView.createViewNav(); <br /> <br />ViewEntry currEntry=nav.getFirst(); <br /> <br />if (currEntry!=null) { <br />&nbsp; &nbsp; &nbsp; &nbsp; if (!currEntry.isCategory()) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//make sure currEntry is a category or null</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ViewEntry firstCategory=nav.getNextCategory(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry.recycle(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry=firstCategory; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//set cache strategy to optimize getNextCategory() calls,</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//fills the cache with the result of 400 getNextCategory() calls</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; nav.setCacheGuidance(numCacheEntries, ViewNavigator.VN_CACHEGUIDANCE_READSELECTIVE); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; while (currEntry!=null) &nbsp;{ <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doSomethingWithTheCategory(currEntry); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//move to next category; refills the cache after 400 categories</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ViewEntry nextEntry=nav.getNextCategory(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry.recycle(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry = nextEntry; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />} <br />nav.recycle(); <br />lookupView.recycle(); <br /></code> <br /> <br /><strong>Reading direct child entries</strong> <br /> <br />In our web development projects, the most important use case for the new cache support in 8.5.3 is to read the direct child entries in a view. <br />We often do this to populate a lazy loading JavaScript tree or tree table: When the user expands a tree entry, the next tree level gets loaded and displayed. <br /> <br />This is demonstrated in the following snippet. <code>parentEntryPos</code> would contain the position of the expanded parent entry. <br /> <br /><code><font color="#008000">//get a view from a database</font> <br /> View lookupView=db.getView("myview"); <br /> <br /> <font color="#008000">//disable auto updating</font> <br /> lookupView.setAutoUpdate(false); <br /> <br /> <font color="#008000">//position of parent view entry to read direct child entries or null to load the first level</font> <br /> String parentEntryPos="3.1.2"; <br /> <br /><font color="#008000">//get a ViewNavigator instance for all the view entries</font> <br /> ViewNavigator nav=lookupView.createViewNav(); <br /> <br />boolean foundFirstEntry=false; <br />if (parentEntryPos!=null &amp;&amp; !"".equals(parentEntryPos) &nbsp;{ <br />&nbsp; &nbsp; &nbsp; &nbsp; if (nav.gotoPos(parentEntryPos, '.')) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (nav.gotoFirstChild()) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foundFirstEntry=true; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />} <br />else { <br />&nbsp; &nbsp; &nbsp; &nbsp; if (nav.gotoFirst()) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foundFirstEntry=true; <br />} <br /> <br />if (foundFirstEntry) { <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//get the first entry to read:</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; ViewEntry currEntry=nav.getCurrent(); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//get the maximum number of siblings to find the right cache size:</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; int maxNumSiblings=currEntry.getSiblingCount(); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//set cache strategy to optimize getNextSibling() calls</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//fills the cache with the result of maxNumSiblings getNextSibling() calls</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; nav.setCacheGuidance(maxNumSiblings, ViewNavigator.VN_CACHEGUIDANCE_READSELECTIVE); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; if (currEntry!=null) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (currEntry!=null) &nbsp;{ <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//not 100% sure that the user can see the child entries;</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//currChildCount may contain hidden documents:</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int currChildCount=currEntry.getChildCount(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean hasChildren=false; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (currChildCount > 0) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasChildren=true; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">Read the position of the current entry in the view:</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String currEntryPos=currEntry.getPosition('.'); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doSomethingWithTheSibling(currEntry, currEntryPos, hasChildren); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//move to next sibling</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ViewEntry nextEntry=nav.getNextSibling(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry.recycle(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currEntry = nextEntry; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />} <br /> <br />nav.recycle(); <br />lookupView.recycle(); <br /></code> <br /> <br />Of course, the code can be further improved to ignore the first <code>start</code> entries and stop after reading <code>count</code> entries. <br /> <br />Unfortunately, there is no method <code>skipSiblings(int siblingsToSkip)</code> in <code>ViewNavigator</code> to quickly skip sibling entries in a view level. We requested this as a feature, but things are not moving very fast in this area of the product. ;-) <br /> <br /><strong>Child and sibling counts in Domino: an eye opener</strong> <br /> <br />When you look at that last snippet, you might wonder if reading the sibling or child count and the entry position is a wise decision. <br />Same did I at first. I thought reading count information of ViewEntries would probably take a long time, because Domino has to go through all the entries to calculate the right amount. <br /> <br /><span style="text-decoration:underline">The good news is</span>: <br />Reading child and sibling counts in Domino is actually very fast. <br /> <br /><span style="text-decoration:underline">The bad news is:</span> <br />The count returned is not exactly what you might expect. :-) <br /> <br />I guess a picture is worth a thousand words: <br /> <br /><img  alt="Image:Fast Notes view reading via Java API:New ViewNavigator cache methods in 8.5.3" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm/content/M2?OpenElement" /> <br /> <br />What you see is a view in <a href="http://www.seancull.co.uk/Public/seancull.nsf/dx/jake-howletts-codestore.net-fake-names-40000-names-in-a-domino-directory-1010-.htm" target=_blank>Sean Cull's Fakenames database</a> with 40.000 fake user records. I added columns for both the child count and the entry positions. <br />Domino returns a child count of 8, but we can only see 6 entries and there seem to be gaps in the view: the entries 1.4 and 1.5 are missing. <br /> <br />The reason is that I added reader fields to those documents, so that I'm not allowed to see them anymore.  <br /> <br />And since checking if a user is allowed to see a document is a pretty heavy operation of comparing reader fields, the user's roles in the database's ACL and the group documents in the server directory, Domino does not do this just to calculate a count. <br />Domino simply returns a count value instead, that is stored in the view index and is only a <strong>maximum of available child/sibling entries</strong>. <br />It's the amount of entries the server can see. <br /> <br /><strong>Please note that reading count values is not always a cheap operation</strong>. When working with <code>ViewEntryCollection</code>, <code>DocumentCollection</code> or <code>NoteCollection</code>, Domino will go through all entries in many cases, which takes a lot of time.  <br /> <br /><strong>Troubleshooting cache usage</strong> <br /> <br />If you are not sure if your cache settings are actually used, you can enable client_clock debugging via Notes.ini as described <a href="http://www.lntoolbox.com/en/notesini-reference/bycategory/2215-clientclock.html" target=_blank>here</a> or <a href="http://www.poettgen.eu/internet/blogs/netzgoetter.nsf/dx/messung-der-notesdomino-peformance-mit-client_clock.htm?opendocument&amp;comments" target=_blank>here (in German language)</a>. <br />While traversing view entries, you should see much less RPC calls to the server when using the cache than without using it. <br /> <br /><strong>Backward compatibility</strong> <br /> <br />If you want to use the new cache guidance functionality, but your code needs to run on older Domino servers as well, you should not call the new method directly. Your code would not compile in older versions and throw an exception when it runs. <br /> <br />Use Java reflection instead to check if <code>setCacheGuidance</code> actually exists: <br /> <br /><code>public static boolean setCacheGuidance(ViewNavigator viewNav, int maxEntries, int readMode) throws NotesException { <br />&nbsp; &nbsp; &nbsp; &nbsp; try { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Method setCacheGuidance=ViewNavigator.class.getMethod("setCacheGuidance", Integer.TYPE, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Integer.TYPE); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setCacheGuidance.invoke(viewNav, maxEntries, readMode); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (SecurityException e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//ignore, must be 8.5.2 or below</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (NoSuchMethodException e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//ignore, must be 8.5.2 or below</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (IllegalArgumentException e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//ignore, must be 8.5.2 or below</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (IllegalAccessException e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//ignore, must be 8.5.2 or below</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (InvocationTargetException e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (e.getCause() instanceof NotesException) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw (NotesException) e.getCause(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#008000">//ignore, must be 8.5.2 or below</font> <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; return false; <br />}</code> <br /> <br /><strong>ViewEntryCollection improvements?</strong> <br /> <br />Talking about <code>ViewEntryCollection</code>, there have been plans to add cache support in this class as well. This would be useful to quickly read the results of a fulltext search (e.g. up to 5000 entries by default). <br />Unfortunately, the current R9 beta does not contain anything new in this area, so there is no big hope that it will get added in R9. <br /> <br /><strong>More on this topic</strong> <br /> <br />If this topic is interesting for you and you attend IBM Connect 2013, mark this session in your schedule: <br /> <br /><span style="text-decoration:underline">AD211 - What's New In The IBM Domino Objects?</span> <br />Elizabeth Sawyer - IBM; James Cooper - IBM <br /> <br /><em>The Domino Objects for Release 9.0 debuts a major set of classes for Calendar &amp; Scheduling as well as additional performance features for View Navigation. &nbsp;Join us as we explore the powerful new capabilities coming soon to application developers through discussion and demonstration of &nbsp;representative use cases.</em> <br /> <br /> <br />I'm pretty sure that they will also demonstrate something new in the R9 API, for example <code>public Vector getColumnValues(int columnNumber)</code> in the <code>View</code> class that you can find in the beta version and that should work like @DbColumn. :-) <br /> <br /> <br />That's it for today. I hope this article is helpful and you can speed up your applications! <br /> <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/17.01.2013085308KLEB9S.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Our session got accepted for IBM Connect: BOF211 Leverage OSGi plug-ins in Your XPages Applications! </title>
<pubDate>Wed, 9 Jan 2013 08:20:41 +0200</pubDate>
<description>
<![CDATA[ 
Today we got the information that our Birds of a Feather session submission (BOF) has been accepted for IBM Connect 2013. Here is the abstract: BOF211 Leverage OSGi plug-ins in Your XPages Applica ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/09.01.2013082041KLEAMH.htm</link>
<category>IBM Connect</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/09.01.2013082041KLEAMH.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/09.01.2013082041KLEAMH.htm</guid>
<content:encoded><![CDATA[ Today we got the information that our Birds of a Feather session submission (BOF) has been accepted for IBM Connect 2013. <br /> <br /> Here is the abstract: <br /> <strong><em><br /> BOF211 Leverage OSGi plug-ins in Your XPages Applications!</em></strong> <em><br /> Tammo Riedinger, Mindoo GmbH; Karsten Lehmann, Mindoo GmbH</em> <br /> <em><br /> Hear how XPages apps can be extended with your own visual controls and data can be leveraged from external databases! We want to talk about code sharing of libraries between multiple XPages apps, Notes Client plugins and standalone applications.We also want to discuss, how custom server processes and even complete applications can be added to IBM Lotus Domino on top of OSGI, due to its highly modular and extensible nature. The only limit is your imagination! </em><br /> <br /> <br /> That's quite similar to the description that we had submitted as a normal session, which unfortunately did not get accepted by the track managers. BOF sessions however get voted by the conference attendees. <br /> <br /> What you <span style="text-decoration:underline">don't</span> get in our BOF session compared to the normal one:  <ul> <li>slides  </li><li>demos</li></ul><br /> What you <span style="text-decoration:underline">will</span> get in our BOF session compared to the normal one:  <ul> <li>discussion  </li><li>exchange of experiences</li></ul><br /> and hopefully a small breakfast buffet with coffee in front of the room, in case we get a 7am slot for the BOF (hear us IBM? We once did a BOF with no breakfast, that was hard :-) &nbsp;). <br /> <br /> This is how IBM describes Birds of a Feather sessions:  <ul> <li>A Connect 2013 BOF is a relaxed, &nbsp;interactive discussion, with no media or AV. This is a 'chalk-talk' style meeting, and the purpose of the discussion is to gather input, feedback, and learn from each other. Again, no room AV is to be used, no exceptions please.  </li><li>The role of the facilitator is to do just that -- facilitate discussion. All in attendance should be given an opportunity to become engaged. This is not a 'one to many' session. Remember -- at Connect, "Everyone has a voice" !  </li><li>Flip-charts and markers will be provided upon request. Any other session tools, props, etc are the responsibility of the facilitator(s).</li></ul><br /> Great to be part of the conference! See you in Orlando! <br />   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/09.01.2013082041KLEAMH.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/09.01.2013082041KLEAMH.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework</title>
<pubDate>Sat, 3 Nov 2012 14:14:02 +0200</pubDate>
<description>
<![CDATA[ 
Last week we had a conference call with IBM. They provide free VMware images of several IBM products for business partners to be used for demo and development purpose, including IBM Connections 4, alr ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm</link>
<category>Free Tools</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm</guid>
<content:encoded><![CDATA[ Last week we had a conference call with IBM. They provide free VMware images of several IBM products for business partners to be used for demo and development purpose, including IBM Connections 4, already set up for the well known <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/marybeth/entry/meet_our_hannover_business_user?lang=en" target=_blank>Renovations company</a>. <br /> Those images very pretty large, with several GB's of data and the fastest and easiest way to get our hands on the images was to set up an FTP server and have the IBM'ers upload the files. <br /> <br /> That was a good occasion to build a small proof-of-concept that I had already thought of 1-2 years ago: <strong><br /> <br /> An FTP server running on top of Domino</strong> <br /> <br /> The implementation is actually quite easy: We simply take an existing FTP server and integrate it into the OSGi framework of the Domino server as a plug-in. <br /> I selected the <a href=http://mina.apache.org/ftpserver/ target=_blank>Apache FtpServer</a> for this purpose, because it's available as open source with Apache License and easy to set up. <br /> <br /> The first task was to find all necessary libraries to run the server. The FtpServer project is available via Apache's <a href=http://maven.apache.org/ target=_blank>Maven</a> repositories. Maven is a powerful build system that takes care of all code dependencies. <br /> Although Maven can often be a real PITA, creating a build means basically just to download the source code and use the command <br /> <br /> <code>mvn clean install</code> <br /> <br /> or <br /> <br /> <code>mvn clean install -DskipTests</code> <br /> <br /> The option "-DskipTests" skips the automatic test case execution during the build process and reduces build time. <br /> <br /> As <a href=https://twitter.com/Klehmann79/status/218339356723777538 target=_blank>tweeted</a> a few months ago, there is a way to tweak Maven's pom.xml file to let it generate all required Jar files and copy them to a target directory. <br /> You just need to add this snippet to the pom.xml file: <br /> <br /> <code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />artifactId<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>maven-dependency-plugin<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/artifactId<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />executions<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />execution<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />phase<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>install<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/phase<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />goals<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />goal<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>copy-dependencies<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/goal<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/goals<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />configuration<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />outputDirectory<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>${project.build.directory}/lib<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/outputDirectory<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/configuration<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/execution<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/executions<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /> <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br /> I then copied all generated Jar files into a new plug-in: <br /> <br>  <div align=center><img  alt="Image:XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm/content/M2?OpenElement" /></div> <br /><br /> <br /> <br /> and exported the relevant packages in the plug-in's manifest file: <br /> <br>  <div align=center><img  alt="Image:XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm/content/M3?OpenElement" /></div> <br /><br /> <br /> Next, I created a plug-in "com.mindoo.ftp" that uses the code from "org.apache.ftpserver" and creates the actual FTP server instance. <br /> It reads the server configuration and user account data from a small Notes database and writes log documents into another one. <br /> <br /> For now, the FTP server reads and writes its files from disk and not from document attachments in NSF databases, although that would be technically possible and might be an option for the future. <br /> <br /> I decided not to use NSF for the files, because a) this is just a proof-of-concept and b) the FTP server should be able to resume uploaded and downloaded files. The standard Notes Java API does not provide any real streaming functionality (EmbeddedObject.getInputStream() internally just writes the file to disk first, which would kill performance). <br />  <br /> Streaming of attachments out of NSF is possible via <a href="http://www-12.lotus.com/ldd/doc/tools/c/6.0.2/api60ref.nsf/ef2467c10609eaa8852561cc0067a76f/4c81dd1f5e6cb4f185256bf20052a417?OpenDocument" target=_blank>NSFNoteExtractWithCallback</a> in the C API (we used this in the <a href=http://www.mindplan.com/ target=_blank>MindPlan</a> application to let the user cancel attachment extraction) and there may be a similar method to import attachments via stream. <br /> <strong><br /> Server Configuration</strong> <br /> <br /> Our configuration database looks like this - nothing fancy yet: <br /> <br>  <div align=center><img  alt="Image:XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm/content/M4?OpenElement" /></div> <br /><br /> <br /> I added fields for the most relevant server settings to the configuration form, e.g. the server's TCP/IP port, a blacklist to block IP addresses and subnets as well as parameters to use the server behind a NAT router (I tried running it from inside a VMware image). <br /> <br>  <div align=center><img  alt="Image:XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm/content/M5?OpenElement" /></div> <br /><br /> <br /> For users, we can configure their home directory, set a password (we only save a one-way hash generated by @Password) and set a few options to limit the user's access to the server, e.g. define an access period and remove write permissions. <br /> <br>  <div align=center><img  alt="Image:XPages series #15: Free FTP server on top of Domino&#8217;s OSGi framework" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm/content/M6?OpenElement" /></div> <br /><strong><br /> Running the server</strong> <br /> <br /> The FTP server plugins should be deployed into the Domino server's HTTP task OSGi framework and start when the HTTP server gets started. <br /> Unfortunately, in 8.5.3 this is not that easy. There is no such extension point that can be used to automatically start a plug-in on HTTP task startup, like <a href="http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fextension-points%2Forg_eclipse_ui_startup.html" target=_blank>org.eclipse.ui.startup</a> for RCP applications (we have an open feature request for 8.5.4). Everything is started lazily when it is used for the first time. Bad for a server that needs to listen for incoming connections on a TCP/IP port. <br /> <br /> However, the XPages runtime provides one extension point that we can use: <br /> <br /> <code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp;<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />extension <br />  &nbsp; &nbsp; &nbsp; &nbsp;point="com.ibm.commons.Extension"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />service <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;class="com.mindoo.ftp.startup.StartupHandler" <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;type="com.ibm.designer.runtime.extensions.RuntimeInitializationEvent"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/service<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />  &nbsp; &nbsp; &nbsp; &nbsp;<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/extension<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /> <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br /> This way, our plugin gets started the first time an XPage is called. That's a first step, but we need to automate this XPage invocation somehow, to be sure that the server is running after the HTTP task or the whole server is restarted. <br /> <br /> Fortunately, tweeting about this issue helped. Thanks to <a href=https://twitter.com/muenzpraeger/status/262063854467571712 target=_blank>René Winkelmeyer</a>, I could come up with a solution that leverages the XPages preload feature of Domino 8.5.3 to automatically start the FTP server plugin. <br /> All you have to do is add the following lines to the server's Notes.ini: <br /> <br /> <code>XPagesPreload=1 <br /> XPagesPreloadDB=mindoo-ftp-config.nsf/ftplauncher.xsp</code> <br /> <br /> "ftplauncher.xsp" is a small dummy XPage in our configuration database. You can use any other XPage instead, since the purpose is just to start the OSGi framework. <br /> <strong><br /> DOTS</strong> <br /> <br /> There is an alternative OSGi implementation that can run as part of the Domino server installation: DOTS, also known as <a href=http://www.openntf.org/projects/pmt.nsf/ProjectLookup/OSGI%20Tasklet%20Service%20for%20IBM%20Lotus%20Domino target=_blank>Domino Tasklet Service for IBM Lotus Domino</a>. <br /> In constrast to the HTTP OSGi framework, DOTS contains an extension point to launch plug-ins on framework startup. <br /> <br /> I did not choose DOTS to run the FTP server, because as of 8.5.3, DOTS is not part of the Domino server and needs to be deployed manually. In addition, by using the HTTP OSGi framework instead of DOTS, we can directly call plug-in methods from XPages applications, which might be useful for some applications. <br /> <strong><br /> Server console commands</strong> <br /> <br /> I added three server console commands to control the FTP server from the server console: <br /> <br /> <code>tell http osgi mftp restart &nbsp;- &nbsp;stops and starts the server <br /> tell http osgi mftp stop &nbsp;- &nbsp;stops the server <br /> tell http osgi mftp start &nbsp;- &nbsp;starts the server</code> <br /> <br /> And of course, the FTP server gets restarted on <br /> <br /> <code>restart task http</code> <br /> <br /> which restarts the whole HTTP task. <br /> <br /> Adding and modifying users does not require a server restart. The lists of blocked IP's and subnets in the server configurations does also get automatically re-read when somebody tries to log into the server. <br /> All other options currently require a restart of the FTP server. <br /> <strong><br /> Free as in beer</strong> <br /> <br /> This proof-of-concept is made available for free. I am sure there are other cool use cases for OSGi based background tasks in Domino. In particular, a scheduler plug-in might be a good thing. <br /> <strong><br /> Setup instructions</strong> <br /> <br /> The download archive contains an update site with the plugin code that needs to be deployed onto the Domino server just like the <a href="http://www-10.lotus.com/ldd/ddwiki.nsf/dx/XPages_Extension_Library_Deployment" target=_blank>XPages Extension Library</a> : create an NSF update site database, import the plug-ins and features, configure the Notes.ini variable OSGI_HTTP_DYNAMIC_BUNDLES and restart the HTTP task. <br /> <br /> The default paths for the configuration database is "mindoo-ftp-config.nsf" and "mindoo-ftp-config-log.nsf" for the log database. <br /> <br /> An alternative configuration database path can be configured via the Notes.ini variable "$mndFTPConfig=configdb.nsf". For the log database, the variable is called "$mndFTPLog=logdb.nsf". <br /> <br /> And finally, the base directory of the FTP server can be set via "$mndFTPBaseDir=c:\temp\mftp". <br /> <br /> Hope this tool is useful!  <br /> <br />Here is the download link: <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/mftp.zip/$file/mftp.zip" title="mftp.zip">mftp.zip</a> <br /><br>  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/03.11.2012141402KLEHJC.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/03.11.2012141402KLEHJC.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Session accepted for Entwicklercamp 2013: Dojo 1.8 and AMD</title>
<pubDate>Sun, 30 Sep 2012 21:28:24 +0200</pubDate>
<description>
<![CDATA[ 
I just received confirmation that my session submission for next years developer conference Entwicklercamp 2013 in Gelsenkirchen, Germany (11th - 13th of March) got accepted. The session is about th ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/30.09.2012212824KLEQUC.htm</link>
<category>Entwicklercamp 2013</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/30.09.2012212824KLEQUC.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/30.09.2012212824KLEQUC.htm</guid>
<content:encoded><![CDATA[ I just received confirmation that my session submission for next years developer conference <a href=http://www.entwicklercamp.de/ target=_blank>Entwicklercamp 2013</a> in Gelsenkirchen, Germany (11th - 13th of March) got accepted. <br /> <br /> The session is about the new <a href=http://dojotoolkit.org/ target=_blank>Dojo toolkit 1.8</a> that we have already used in a <a href="http://www.mindoo.com/web/blog.nsf/dx/18.09.2012001300KLEU38.htm" title="18.09.2012001300KLEU38.htm" target="_blank">customer project</a> since its release in August 2012. <br /> Sessions at Entwicklercamp are held in German language, so here is the translated abstract and the original one in German. <span style="text-decoration:underline"><br /> <br /> Dojo 1.8 and AMD</span> <br /> <br /> The session provides an introduction to web application development with version 1.8 of the Dojo toolkit.<br /> <br /> It covers available UI elements for web and mobile development, declarative and programmatic web ui design as well as the new AMD module system, that can be used to build highly modular web applications. <br />  <br /> With short demos, additional tools will be presented, that can be used to impress customers and colleagues.<br /> <span style="text-decoration:underline"><br /> <br /> Dojo 1.8 und AMD</span> <br /> <br /> Die Session gibt einen Einstieg in die Webapplikationsentwicklung mit dem Dojo Toolkit in der Version 1.8. <br /> <br /> Behandelt werden die zur Verfügung stehenden grafischen Elemente für Web und Mobile, deklarative und programmatische Weboberflächengestaltung sowie das neue AMD-Modulsystem, mit dem sich äußerst modulare Applikationen aufbauen lassen. <br /> <br /> Im Rahmen von Kurzdemos werden darüber hinaus noch weitere Tools vorgestellt, mit denen man Kunden und Kollegen zum Staunen bringen kann. <br />   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/30.09.2012212824KLEQUC.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/30.09.2012212824KLEQUC.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Customer project: Dojo 1.8 based portal on top of XPages and Domino 8.5.3</title>
<pubDate>Tue, 18 Sep 2012 00:13:00 +0200</pubDate>
<description>
<![CDATA[ 
The last months have been incredibly busy for us at Mindoo and I could not find much time for blogging. Tweeting about my findings on the web is just so much easier than to write a complete blog artic ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/18.09.2012001300KLEU38.htm</link>
<category>Webdev</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/18.09.2012001300KLEU38.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/18.09.2012001300KLEU38.htm</guid>
<content:encoded><![CDATA[ The last months have been incredibly busy for us at Mindoo and I could not find much time for blogging. <a href=https://twitter.com/Klehmann79 target=_blank><span style="text-decoration:underline">Tweeting</span></a> about my findings on the web is just so much easier than to write a complete blog article. <br /> <br /> We spent most of our time working on web applications for desktop browsers and the iPad (including Retina support), based on our favorite web toolkits <a href=http://www.sencha.com/products/extjs/ target=_blank><span style="text-decoration:underline">Ext.JS</span></a> from Sencha as well as the <a href=https://dojotoolkit.org/ target=_blank><span style="text-decoration:underline">Dojo toolkit</span></a>. <br /> Since we like cutting edge development, we prefer to use the latest versions of toolkits. For Sencha Touch, this means 2.0.x, Ext.JS is available in version 4.1.x and for Dojo it's the brand new version 1.8 that we already used for a portal framework development during the past 3 weeks. <strong><br /> <br /> Portal framework</strong> <br /> <br /> This portal framework is a customer project, so there is not much code I can share (I will try to write blog entries about specific technologies). <br />But I can describe the basic ideas in this blog post and provide some links to useful toolkits that helped us building the app. <br /> <br /> The portal leverages Dojo's <a href="https://dojotoolkit.org/reference-guide/1.8/dojox/layout/GridContainer.html" target=_blank><span style="text-decoration:underline">dojox.layout.GridContainer</span></a> (click <a href="http://www.skynet.ie/~sos/misc/dojo/dojox/widget/tests/test_PortletInGridContainer.html?theme=soria" target=_blank><span style="text-decoration:underline">here</span></a> for a portal sample app) to build the portal UI. Portlets can have two different render modes: <strong>IFrame</strong> and <strong>inline</strong> rendering. In IFrame rendering mode, the portlet content is completely independent from the parent page; in inline rendering mode, the portlet code can directly render its content into the container node of a <a href="https://dojotoolkit.org/reference-guide/1.8/dojox/widget/Portlet.html" target=_blank><span style="text-decoration:underline">dojox.widget.Portlet</span></a> within the portal page. <br /> <br /> The portal page acts as a communication mediator between the portlets (both with IFrame and inline rendering). Portlets can send JSON based messages to the portal, which - depending on the message content - can send a response to the portlet (e.g. to return loaded portlet state information), forward the message to another portlet (to update another portlets state) or send out a broadcast message to all portlets in the page (e.g. to publish selection changes in a Dojo grid). <br /> <br />More or less, the portal acts like a Composite Application on steroids. :-) <br />&nbsp;<strong><br /> Cross-domain security</strong> <br /> <br /> While sending messages between portlets with inline rendering is quite easy, we needed to find a way to cross the IFrame boundaries in order to send data from IFrame content to the main page back and forth. <br /> This is not that easy, because browsers prevent this kind of communication to avoid cross-domain security issues. <br /> <br /> Fortunately, there is <a href=http://easyxdm.net/ target=_blank><span style="text-decoration:underline">easyxdm</span></a>, a Javascript library that contains several solutions for cross-domain communication and automatically picks the right one for the current browser. <strong><br /> <br /> Portlet content rendering</strong><br /> <br /> Loading the portlet content for IFrame rendering mode is quite easy. All you need to do is create an IFRAME node with JavaScript and set its <strong>src</strong> attribute to the remote content URL. <br /> This way, portlet content can get generated in external databases or even on different servers (including servers that are not Domino based). <br /> <br /> This works quite well on desktop browsers. They have a good internet connection and plenty of RAM, so it's not a problem to load newer or older Dojo versions or other toolkits as part of the IFrame content. <br /> Scrolling content that is larger than the portlet viewport is quite easy as well. This is all handled automatically by the desktop browser. <br /> <br /> Unfortunately, this approach did not work well on mobile devices. Scrolling content with a Swipe gesture did not work at all and we noticed rendering issues: in many cases, the IFrame content did not render properly. <br /> That lead us to the development of inline rendering mode: The whole portal content is stored in one DOM tree and shares the portal's Dojo 1.8 framework. <br /> This is good and bad at the same time: Page load is faster, but portlets needs to be developed in a way that they don't interfere with each other and only load required resources once (like JavaScript code or CSS files). <br />  <br />In addition to adding the inline rendering mode, additional tweaks had to be applied to the portal rendering in order to support drag&amp;drop of portlets on the iPad (Dojo's GridContainer layout is pretty hardcoded to mouse events) and change the portal column width with a pinch gesture. <br />To drag&amp;drop portlets, we implemented a special edit mode, comparable to the "jiggle mode" in the springboard on iOS devices: Portlets in edit mode get a <a href=http://jsfiddle.net/nfang/AxfdC/ target=_blank>CSS based jiggle animation</a> to illustrate that they can get moved with a swipe gesture (tap on the portlet and drag it to the target location). <br /> <br /><strong>Dynamic classloading</strong> <br /><br /> To implement the inline rendering mode of portlets in a clean way, we built the whole portal framework on top of Dojo's new <a href="http://www.sitepen.com/blog/2012/06/25/amd-the-definitive-source/" target=_blank><span style="text-decoration:underline">AMD classloader architecture</span></a>. This lets us define classes, implement class inheritance and lazily load portlet code so that it gets loaded when it is required for the first time, speeding up overall page load. <br />By following a <a href=http://dojotoolkit.org/documentation/tutorials/1.8/modules/ target=_blank>tutorial</a> on the Dojo website, we could also load specific classes from different locations than the portal page itself. This enables us to separate the portal code from the actual portlet code, making the application reusable and easy to extend. <br /> <br />In addition, we used the <a href=http://ensure.codeplex.com/ target=_blank><span style="text-decoration:underline">Ensure</span></a> library to coordinate the loading of resources that are required for the portlet rendering process: Portlets send a JSON message to the portal with a list of required HTML, JS and CSS files and the portal only loads files that have not been fetched for other portlets before. <br /> When all resources are loaded, <strong>Ensure </strong>calls our callback function which then notifies the portlet that all resources have been loaded and content rendering can start. <br /> <strong><br /> Modality</strong> <br /> <br /> Portlets can be configured to be modal. A modal portlet gets displayed in a Dojo dialog on desktop browsers (including dialog-in-dialog) and gets opened in a separate <a href="http://dojotoolkit.org/reference-guide/1.8/dojox/mobile/View.html" target=_blank><span style="text-decoration:underline">dojox.mobile.View</span></a> with transition effect on the iPad in order to use all the real estate on the iPad screen. Since portlets can exchange data via the portal page mediator, this can be used to provide special settings portlets to configure one portlet from another one. <br />Our first 'real life' portlets use this modality feature to display a list of documents in a document library database. A click on a list entry displays detail information of the entry in a separate dialog / mobile view including the full document richtext with inline images and attachments (leveraging a <a href="http://www.iminstant.com/iminstant/iminstant.nsf/d6plinks/CTYR-7H6S6R" target=_blank>nice hidden url syntax of Domino</a>). <br />Both the list and detail portlet use Dojo's powerful <a href="http://blog.balfes.net/2011/02/15/django-template-language/" target=_blank>Django template language</a> to generate the HTML content. <br /><strong><br /> Backend</strong> <br /> <br /> The portal and portlet code and data are stored in a Lotus Domino 8.5.3 server.  <br /><br /> As you might know, Lotus Domino 8.5.3 contains Dojo version 1.6.x as part of the XPages runtime environment. That version is already pretty outdated and not sufficient for our portal framework usecase (e.g. no <a href="http://dojotoolkit.org/reference-guide/1.8/dojox/mobile/ScrollablePane.html" target=_blank>dojox.mobile.ScrollablePane</a>).  <br />There is some hope that 8.5.4 will contain Dojo 1.8, but we could not wait until Q1/2013 for the 8.5.4 release (the world out there does not wait for IBM dev).<br /> Replacing the existing Dojo version of the server with a newer one is more or less a hack and not supported as well, so we decided to render the whole portal UI in our own code and develop a set of REST services to communicate between frontend and backend code. <br /> <br /> Content rendering is done in an <a href="http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm" target="_blank">XAgent style XPage</a>. The page loads one or more files from the database design (added in the Java perspective of Domino Designer), parses placeholders in the text content with a regular expression (e.g. to include other files or insert paths and multilingual text phrases coming from property files in the database design) and sends the output to the browser. <br /> <br /> We've got REST services to load/store information about all the portlets on the portal page. Each portlet has a state and appearance information as a JSON object (the latter e.g. to store in which column of the portal a portlet should be displayed).  <br />The REST services are implemented with a Java control similar to IBM's rest service in the Extension Library (using the XPages extensibility API), but we removed the SSJS functionality from the control and directly call Java code (that's much cleaner than writing SSJS code that then calls our Java classes). <br /><br /> For each portlet instance, we create a Notes document in the database. There is a document to store the overall state of the portal page itself and there are configuration documents in the database to configure which portlets can be added to the page by the current user. <br /> By replacing the backend storage code, portlet data can optionally be stored temporarily in the user session (sessionScope, viewScope). And since the whole framework is developed in a modular way, the portal UI can also be replaced by something else, e.g. to display new tabs instead of portlets. Actually, we don't use the terms "portal" and "portlet" in the framework. They are called "WorkbenchPage" and "ViewPart", similar to Eclipse terminology and displaying them in a portal layout is just a single use case. &nbsp;<br />  <br /><strong>Summary</strong> <br /><br /> Developing this application was really fun, especially the iPad and CSS animation part. <br />The only thing that was a real PITA was to get the whole stuff working on Internet Explorer 7 (fortunately, only the desktop part, not iPad mode). <br /> <br />Hopefully, some of the concepts and links in this article are helpful for others as well, although there is not a single line of code in it. :-) <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/18.09.2012001300KLEU38.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/18.09.2012001300KLEU38.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>New address of Mindoo GmbH in Karlsruhe, Germany</title>
<pubDate>Sat, 30 Jun 2012 14:14:23 +0200</pubDate>
<description>
<![CDATA[ 
Please note that we have moved. As of 1st of July 2012, our new company address in Karlsruhe, Germany is Mindoo GmbH Haid-und-Neu-Straße 7 76131 Karlsruhe Germany ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/30.06.2012141423KLEGD2.htm</link>
<category>Mindoo</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/30.06.2012141423KLEGD2.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/30.06.2012141423KLEGD2.htm</guid>
<content:encoded><![CDATA[ Please note that we have moved. <br /> As of 1st of July 2012, our new company address in Karlsruhe, Germany is <strong><br /> <br /> Mindoo GmbH</strong> <strong><br /> Haid-und-Neu-Straße 7</strong> <strong><br /> 76131 Karlsruhe</strong> <strong><br /> Germany</strong>   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/30.06.2012141423KLEGD2.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/30.06.2012141423KLEGD2.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>XPages series #14: Using MongoDB&#8217;s geo-spatial indexing in XPages apps part 2</title>
<pubDate>Fri, 27 Apr 2012 19:00:09 +0200</pubDate>
<description>
<![CDATA[ 
This is part 2 of an article about using MongoDB in Notes/Domino. Click here for part 1. Diving into the code: client side The UI stuff is stored in an NSF database with basic page layout defined i ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/27.04.2012190009KLEMXN.htm</link>
<category>XPages</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/27.04.2012190009KLEMXN.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/27.04.2012190009KLEMXN.htm</guid>
<content:encoded><![CDATA[ This is part 2 of an article about using MongoDB in Notes/Domino. <a href="http://www.mindoo.com/web/blog.nsf/dx/27.04.2012185938KLEMXB.htm" target="_blank">Click here for part 1</a>. <br /> <br /> <br /><strong>Diving into the code: client side</strong> <br /> <br />The UI stuff is stored in an NSF database with basic page layout defined in an XPage and the client-side application logic code stored as Dojo class file in the Java perspective of Domino Designer. <br /> <br /> <div align=center><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-dbdesign-small.jpg/$file/nosql-mongodb-dbdesign-small.jpg"></div> <br /> <br />The Dojo class location is defined and the class is loaded with the following code in the XPage "start.xsp": <br /> <br /><code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:this.resources<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:dojoModulePath prefix="mongo"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:this.url<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />!&#91;CDATA&#91;#{javascript:'/dojo/mongo';}&#93;&#93;><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:this.url<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:dojoModulePath<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:dojoModule name="mongo.test.PageHandler"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:dojoModule<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/this.resources<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br />After that, the class can be instantiated in a script block: <br /> <br /><code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:scriptBlock type="text/javascript"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:this.value<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />!&#91;CDATA&#91; <br />&nbsp; &nbsp; &nbsp; &nbsp; dojo.addOnLoad(function() { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window.pageHandler=new mongo.test.PageHandler(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window.pageHandler.init(); <br />&nbsp; &nbsp; &nbsp; &nbsp; }); <br />&nbsp; &nbsp; &nbsp; &nbsp; &#93;&#93;<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:this.value<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:scriptBlock<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br />In the init() method, the page handler class registers event code for the form fields and buttons in the UI and creates the Dojo grid components (<code>dojox.grid.LazyTreeGrid</code>) to display the database content. <br /> <br />Now let's take a look at two UI operations in detail, to see how the UI communicates with the server-side code. <br /> <br /><strong>Adding data to the database</strong> <br /> <br />When places get added through the Administration tab, we first use the servlet "/mongogeo" to convert the addresses into coordinates: <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-addentries-geo-large.jpg/$file/nosql-mongodb-addentries-geo-large.jpg" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-addentries-geo-small.jpg/$file/nosql-mongodb-addentries-geo-small.jpg"></a></div> <br /> <br />What we get back is the JSON response of &nbsp;the <a href="https://developers.google.com/maps/documentation/geocoding/" target="_blank">Google Geocoding API</a>. It does not only contain the coordinates of an address, but other quite useful information like the name of the federal state, the country code and coordinates of a bounding box (for general addresses like city names that don't have exact coordinates). <br /> <br />Next, a POST operation to "/mongotest/addplaces" creates the actual place documents in the database followed by a reload operation of our Dojo grid to reflect the new data in the UI: <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-addentries-restoverview-large.jpg/$file/nosql-mongodb-addentries-restoverview-large.jpg" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-addentries-restoverview-small.jpg/$file/nosql-mongodb-addentries-restoverview-small.jpg"></a></div> <br /> <br /><strong>Query the database</strong> <br /> <br />The REST service "/mongotest/queryplaces" is used both for reading all places (on the Administration tab) and finding the nearest places for a certain position (on the Search tab). For the latter, we specify additional longitude/latitude arguments in the URL: <br /> <br /><code>http://localhost/dev/ec12/nosql/mongodb/geo.nsf/mongotest/queryplaces?distance=3&amp;<span style="color:#ff0000"><strong>longitude=8.3799444&amp;latitude=49.009148</strong></span>&amp;type=Shop&amp;start=0&amp;count=100</code> <br /> <br />Dynamic sorting can be applied to the result with and without longitude/latitude arguments by specifying a sort parameter. <br />If no sort parameter and no position is specified, places are sorted by name as default sorting. For queries with longitude/latitude parameters, the distance between both points is used as default sorting. <br /> <br /><code>http://localhost/dev/ec12/nosql/mongodb/geo.nsf/mongotest/queryplaces?distance=3&amp;longitude=8.3799444&amp;latitude=49.009148&amp;type=Shop&amp;start=0&amp;count=100&amp;<span style="color:#ff0000"><strong>sort=name</strong></span></code> <br /> <br />In the UI, data can be sorted by clicking one of the grid column headers. <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-queryplaces-large.jpg/$file/nosql-mongodb-queryplaces-large.jpg" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-queryplaces-small.jpg/$file/nosql-mongodb-queryplaces-small.jpg"></a></div> <br /> <br /> <br />Enough technical details, let's come to an end with this long blog article! :-) <br /> <br />If you would like to try out the sample in your own environment, here are the setup instructions: <br /> <br /> <br /><strong>Setup instructions - Prerequisites</strong> <br /> <br />I expect that you have downloaded and installed the latest version of <a href="http://www.mongodb.org/downloads" target="_blank">MongoDB</a> for your operating system. The sample was built for version 2.0.3 and I just found out that 2.0.4 is already available. <br /> <br />The server code is using <code>localhost</code> and port 27017 by default, but this can be changed by setting the environment variable <code>NOSQL_MONGO_SERVER</code> to something like "hostname1,hostname2:27123,hostname3", a comma separated list with hostname and optional port. The Mongo driver will use the list of servers for failover in case a server goes down. <br /> <br /><strong>Plugin installation</strong> <br /> <br />Download and extract the archive file from the specified download link. <br /> <br />Then follow the instructions in the Domino wiki article <a href="http://www-10.lotus.com/ldd/ddwiki.nsf/dx/XPages_Extension_Library_Deployment" target="_blank">XPages Extension Library Deployment in Domino 8.5.3 and IBM XWork Server</a> to create an NSF based update site database on the Domino server and import the update site from the download archive into the update site database, followed by a HTTP task restart (<code>restart task http</code>). <br /> <br /><strong>Database installation</strong> <br /> <br />Copy the sample database from the download archive to your Domino server and sign it with your Notes ID. Now open the database in the browser. <br /> <br />There is a section "Initialization" on the Administration tab which lets you import a set of default addresses (from Mindoo's home town Karlsruhe, Germany). This step is optional. <br /> <br /><strong>Download link</strong> <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/NoSQL-MongoDB.zip/$file/NoSQL-MongoDB.zip">Click here</a> to download the sample application <br /> <br /> <br /> <br />Phew... That was a long text. Thanks for reading until here! <br /> <br />And stay tuned for an article about my second demo from Entwicklercamp 2012: <br /> <br /> <div align=center><strong>Using Neo4J to solve the travelling salesman problem in XPages apps</strong></div> <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/27.04.2012190009KLEMXN.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/27.04.2012190009KLEMXN.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>XPages series #14: Using MongoDB&#8217;s geo-spatial indexing in XPages apps part 1</title>
<pubDate>Fri, 27 Apr 2012 18:59:38 +0200</pubDate>
<description>
<![CDATA[ 
This article presents the first demo of my session about NoSQL databases at the German Entwicklercamp conference in March 2012. It demonstrates how the document-oriented NoSQL database MongoDB can be ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/27.04.2012185938KLEMXB.htm</link>
<category>XPages</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/27.04.2012185938KLEMXB.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/27.04.2012185938KLEMXB.htm</guid>
<content:encoded><![CDATA[ This article presents the first demo of my <a href="http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm" target="_blank">session about NoSQL databases</a> at the German Entwicklercamp conference in March 2012. It demonstrates how the document-oriented NoSQL database <a href="http://www.mongodb.org/" target="_blank">MongoDB</a> can be used in an XPages web application for the IBM Lotus Domino server. <br /> <br /><strong>The rise of location based services</strong> <br /> <br /><a href="http://en.wikipedia.org/wiki/Location-based_service" target="_blank">Location based services</a> have become quite popular in the past years: Most of the smartphones carry a GPS sensor, and there are a lot of popular apps out there (e.g. <a href="https://foursquare.com/" target="_blank">Foursquare</a>, <a href="http://www.yelp.com/" target="_blank">Yelp</a>) that use cloud services to find people, restaurants and places nearby. <br /> <br />For a number of reasons (mostly scalability/performance related), the NSF database of Lotus Notes/Domino is not the best choice to implement these kind of applications/services. MongoDB is much more suited for this use case and the article shows how you can integrate MongoDB into Notes/Domino to combine both worlds and get the best from both of them. <br /> <br />The Dojo based web application that I am going to discuss in detail uses <a href="http://www.mongodb.org" target="_blank">MongoDB's</a> <a href="http://www.mongodb.org/display/DOCS/Geospatial+Indexing" target="_blank">geospatial indexing feature</a> to easily find the nearest points of interest for a mobile web user. <br /> <br />Here is how our application looks like: <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-admin-large.jpg/$file/nosql-mongodb-admin-large.jpg" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-admin-small.jpg/$file/nosql-mongodb-admin-small.jpg"></a></div> <br /> <br />The "Administration" tab provides a user interface to add/remove places to/from the MongoDB database. A place is stored as a document in a MongoDB document collection and consists of a name, a type (e.g. shop/gas station) and the position information as &#91;longitude, latitude&#93; value pair. <br /> <br />The database can be queried on the "Search" tab by entering an address, a distance in kilometers and an optional type. The address will automatically get converted to &#91;longitude, latitude&#93; coordinates by using the <a href="https://developers.google.com/maps/documentation/geocoding/" target="_blank">Google Geocoding API</a>, which is then used to find places within the specified distance. <br /> <br />Our MongoDB document collection is indexed in a way so that we can quickly query the database for places that surround the current user's position and sort them by ascending distance between both points. <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-search-large.jpg/$file/nosql-mongodb-search-large.jpg" target="_blank"><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-search-small.jpg/$file/nosql-mongodb-search-small.jpg"></a></div> <br /> <br />Since geospatial indexing is a built-in feature of MongoDB, the solution is very easy to implement. <br /> <br /><strong>Limitations of NSF</strong> <br /> <br />While it is not impossible to build this application in pure Lotus Notes/Domino technology with an NSF database, the missing geo index and limited scalability of NSF would make it difficult to keep response times low with large data sets, e.g. millions or even billions of places worldwide. MongoDB instead provides a <a href="http://www.mongodb.org/display/DOCS/Sharding+Introduction">sharding feature</a> to distribute the data evenly to several servers and reduce server load. <br /> <br />Additional indexer like <a href="http://lucene.apache.org/core" target="_blank">Apache Lucene</a> in combination with the <a href="http://www.openntf.org/internal/home.nsf/project.xsp?action=openDocument&amp;name=OSGI%20Tasklet%20Service%20for%20IBM%20Lotus%20Domino" target="_blank">OSGi tasklet service plugin's extension hooks</a> might help to improve Domino's limited indexing support (we already used a Lucene index with Domino data in a big customer project) , but using MongoDB for this use case is just so much easier. <br /> <br /><strong>Architecture</strong> <br /> <br />The application consists of client-side and server-side code:<br /> Client-side code is written in JavaScript language as a Dojo class using <a href="http://dojotoolkit.org/documentation/tutorials/1.6/declare/" target="_blank">the class declaration system of Dojo 1.6</a>. This Dojo class handles all user interface operations. <br /> <br />Server-side code is written in Java as a servlet and is exposed to the client-side via REST API's (here: GET/POST requests sent via <code>dojo.xhrGet</code> / <code>dojo.xhrPost</code>). <br /> <br />We developed two servlets for this application. The first servlet handles init/add/remove/query operations in MongoDB. The second servlet simply acts as a proxy to access the <a href="https://developers.google.com/maps/documentation/geocoding/" target="_blank">Google Geocoding API</a> from client-side Javascript in order to convert between addresses and geo coordinates (longitude/latitude). <br /> <br />Since the REST protocol is completely stateless, the server-side code is very easy to test. With a bit of refactoring, it's even possible to run the whole application in alternative servlet containers like Jetty, Tomcat or directly within the Eclipse IDE instead of the Domino server. <br /> <br />Personally, I really like this REST API based approach because it's clean, transparent and keeps technologies separated.  <br />It enables you to replace the server environment, the database system and the client-side UI toolkit at any time. You can even build multiple UIs (e.g. based on Dojo 1.6, 1.7 and Sencha's ExtJS) or mobile clients that work with the same REST API. <br /> <br /><strong>Diving into the code: server side</strong> <br />Our sample comes as an Eclipse plugin "<code>com.mindoo.mongo.test</code>" to be run on Domino's OSGi framework (tested with Domino 8.5.3 GA without any fixpacks or XPages extension library): <br /> <br /> <div align=center><img  src="http://www.mindoo.com/web/blog.nsf/dx/nosql-mongodb-plugin-small.jpg/$file/nosql-mongodb-plugin-small.jpg"></div> <br /> <br />As you can see above, I added the <a href="http://api.mongodb.org/java/2.6/overview-summary.html" target="_blank">Mongo API</a> classes to the plugin's classpath. <br />Adding the Mongo API classes to an NSF and using them directly from SSJS code <em>might</em> also be possible, but I prefer the plugin solution, because the MongoDB access is supposed to be a central service on the Domino server. In addition, by using a plugin we don't have any issues with Domino's restricted security manager that prevents operations to run properly in an XPages context (e.g. a lot of drivers are using Log4J for logging, which does not run well within an XPages application). <br /> <br />Our two servlets are defined in the plugin.xml file of the plugin: <br /> <br /><code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />?xml version="1.0" encoding="UTF-8"?<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />?eclipse version="3.4"?<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />extension point="org.eclipse.equinox.http.registry.servlets"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />servlet alias="/mongotest" class="com.mindoo.mongo.test.servlet.MongoTestServlet" <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; load-on-startup="true"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/servlet<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/extension<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />extension point="org.eclipse.equinox.http.registry.servlets"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />servlet alias="/mongogeo" class="com.mindoo.mongo.test.servlet.GeoQueryServlet" <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; load-on-startup="true"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/servlet<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/extension<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/plugin<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br />That's all you need to declare your own servlet on Domino. <br />After that, the servlet can either be accessed on the URL base level (<code>http://server/mongogeo</code>) or in the context of a Domino database (<code>http://server/path/to/db.nsf/mongotest</code>). <br /> <br />If called in the context of a database, the Domino HTTP server first makes sure that the current user is allowed to access the database and if not, it displays a login prompt. A utility class (<code>com.ibm.domino.osgi.core.context.ContextInfo</code>) can be used to get session/database objects for the current HTTP request. <br /> <br />In our sample, we use the first format for our Geo API query, because it's an open service of the server without access restriction. Anyone can use it and the URL is simple to remember. <br /> <br />The second URL format (/path/to/db.nsf/mongotest) is used to access MongoDB data. This enables us to check the user against the Notes database ACL to see if he is allowed to read or write MongoDB data. <br /> <br />Here is the method of our MongoDB access servlet that handles POST requests: <br /> <br /><code>protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { <br />&nbsp; &nbsp; &nbsp; &nbsp; Session session=ContextInfo.getUserSession(); <br />&nbsp; &nbsp; &nbsp; &nbsp; Database dbContext=ContextInfo.getUserDatabase(); <br />&nbsp; &nbsp; &nbsp; &nbsp; if (dbContext==null) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Servlet must be run in the context of a Domino database", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; try { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String pathInfo=req.getPathInfo(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ("/deleteplaces".equals(pathInfo)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isUserAuthenticated(MongoAccessMode.Write, session, dbContext)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Current user is not allowed to write data", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doDeleteGridData(session, dbContext, req, resp); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if ("/addplaces".equals(pathInfo)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isUserAuthenticated(MongoAccessMode.Write, session, dbContext)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Current user is not allowed to write data", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doAddGridData(session, dbContext, req, resp); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if ("/queryplaces".equals(pathInfo)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isUserAuthenticated(MongoAccessMode.Read, session, dbContext)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Current user is not allowed to read data", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doQueryPlaces(session, dbContext, req, resp); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if ("/initdb".equals(pathInfo)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isUserAuthenticated(MongoAccessMode.Write, session, dbContext)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Current user is not allowed to write data", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doInitDbWithValues(session, dbContext, req, resp); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if ("/cleardb".equals(pathInfo)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isUserAuthenticated(MongoAccessMode.Write, session, dbContext)) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, HttpServletResponse.SC_FORBIDDEN, <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Current user is not allowed to write data", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doClearDb(session, dbContext, req, resp); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, 500, "Unsupported command "+pathInfo, null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; catch (Throwable e1) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e1.printStackTrace(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //avoid posting the full stacktrace to the user (for security reasons) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServletUtils.sendHttpError(resp, 500, "An error occurred processing the request. The error has been logged. Please refer to the server log files/console for details", null); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />}</code> <br /> <br />The code is pretty simple: We check if the user is allowed to call the specific service (read operations require the role <code>&#91;MongoDBRead&#93;</code>, write operations the role <code>&#91;MongoDBWrite&#93;</code> ) and then forward the request to helper methods. <br /> <br />Note that I am not going into full detail in this blog article how we actually access data in MongoDB. You can find that in the provided download archive and there is a great <a href="http://www.mongodb.org/display/DOCS/Java+Tutorial" target="_blank">tutorial at the MongoDB website about using the Java API</a>. <br /> <br />Believe me, this stuff is really easy to use! <br /> <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/27.04.2012190009KLEMXN.htm" target="_blank">Click here for part 2 of this article!</a>  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/27.04.2012185938KLEMXB.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/27.04.2012185938KLEMXB.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>English slides for my Entwicklercamp 2012 session about NoSQL databases</title>
<pubDate>Thu, 5 Apr 2012 00:07:41 +0200</pubDate>
<description>
<![CDATA[ 
As promised, here are the translated files for my NoSQL session at this year's Entwicklercamp (developer camp) conference in Gelsenkirchen, Germany. I am still searching for time to polish the two ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm</link>
<category>NoSQL</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm</guid>
<content:encoded><![CDATA[ As promised, here are the translated files for my <a href="http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm" target="_blank">NoSQL session</a> at this year's <a href=http://www.entwicklercamp.de/ec12/home target=_blank>Entwicklercamp</a> (developer camp) conference in Gelsenkirchen, Germany. <br /> <br /> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/EC12_Mindoo_T4S6-NoSQL_en.pdf/$file/EC12_Mindoo_T4S6-NoSQL_en.pdf"><img  alt="Image:English slides for my Entwicklercamp 2012 session about NoSQL databases" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm/content/M2?OpenElement" /></a> <br /></div> <br />I am still searching for time to polish the two demos: MongoDb integration in XPages apps and NoSQL integration in XPages apps. <br />Next week is blocked for German holidays. Need to work on the demos afterwards. <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/05.04.2012000741KLETXV.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Download link for my Entwicklercamp 2012 session slides about NoSQL databases (German)</title>
<pubDate>Tue, 27 Mar 2012 19:00:43 +0200</pubDate>
<description>
<![CDATA[ 
Here are the slides for my session about NoSQL databases at Entwicklercamp 2012 today. For the non-German audience: sorry for the German content, I hope Google translate will help. :-) I plan to tran ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm</link>
<category>NoSQL</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm</guid>
<content:encoded><![CDATA[ Here are the slides for my session about NoSQL databases at Entwicklercamp 2012 today. For the non-German audience: sorry for the German content, I hope Google translate will help. :-) <br /> I plan to translate them to English, but this may take some time.  <br /><br> <div align=center><a href="http://www.mindoo.com/web/blog.nsf/dx/EC12_Mindoo_T4S6-NoSQL.pdf/$file/EC12_Mindoo_T4S6-NoSQL.pdf" target="_blank"><img  alt="Image:Download link for my Entwicklercamp 2012 session slides about NoSQL databases (German)" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm/content/M2?OpenElement" /></a></div> <br /><br /> I will also write blog entries about my two demos: leveraging the MongoDb geo index feature from an XPages application and embedding the Neo4J graph databases in XPages (travelling salesman algorithm to find the best route in a graph). <br /> <br /><strong><span style="text-decoration:underline">Update:</span></strong> <br />The English slides of the session <a href="http://www.mindoo.com/web/blog.nsf/dx/05.04.2012000741KLETXV.htm" target="_blank">are now online</a>. <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/27.03.2012190043KLEMY2.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/27.03.2012190043KLEMY2.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Speaking at Entwicklercamp 2012 about NoSQL databases</title>
<pubDate>Mon, 19 Mar 2012 09:08:18 +0200</pubDate>
<description>
<![CDATA[ 
Yesterday I submitted my slides for this years Entwicklercamp in Gelsenkirchen, Germany. My session will provide an overview of the NoSQL market for the database types key value stores column orient ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/19.03.2012090818KLEBKA.htm</link>
<category>NoSQL</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/19.03.2012090818KLEBKA.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/19.03.2012090818KLEBKA.htm</guid>
<content:encoded><![CDATA[ Yesterday I submitted my slides for this years <a href=http://www.entwicklercamp.de target=_blank>Entwicklercamp</a> in Gelsenkirchen, Germany. My session will provide an overview of the NoSQL market for the database types <br /> <ul> <li>key value stores </li><li>column oriented databases </li><li>document oriented databases </li><li>and graph database</li></ul> <br />It discusses <a href=http://redis.io/ target=_blank>Redis</a>, <a href=http://cassandra.apache.org/ target=_blank>Apache Cassandra</a>, <a href=http://www.mongodb.org/ target=_blank>MongoDB</a> and <a href=http://neo4j.org/ target=_blank>Neo4j</a> in detail and I will be demo'ing, how to integrate MongoDB's geo-spatial indexing feature and Neo4j's graph search algorithms in XPages applications. <br /> <br />Finally, the session compares the feature sets of Lotus Notes with other NoSQL to see how compatitive Lotus Notes, one of the oldest NoSQL database systems, is today in this moving market. <br /> <br />Working on this topic was quite challenging, because there is A LOT of material to check out on the web, but it also was a lot of fun playing with the databases and building the demos. <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/19.03.2012090818KLEBKA.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/19.03.2012090818KLEBKA.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Icon resources on the web for commercial and non-commercial use</title>
<pubDate>Wed, 8 Feb 2012 08:44:18 +0200</pubDate>
<description>
<![CDATA[ 
As Web and Notes developers, we often need to find icons of various sizes to use them in our applications. Since I found a new massive resource of free icons yesterday, I thought it might be a good i ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/08.02.2012084418KLEB4A.htm</link>
<category>Notesdev</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/08.02.2012084418KLEB4A.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/08.02.2012084418KLEB4A.htm</guid>
<content:encoded><![CDATA[ As Web and Notes developers, we often need to find icons of various sizes to use them in our applications. <br /> Since I found a new <a href=http://openiconlibrary.sourceforge.net/ target=_blank>massive resource of free icons</a> yesterday, I thought it might be a good idea so share some URLs. <br /> <br /> For commercial applications, we bought the Icon Experience library a few years ago, which contains about 2500+ icons in 7 sizes at a very affordable price: <span style="text-decoration:underline"><br /> </span><a href=http://www.iconexperience.com/ target=_blank>http://www.iconexperience.com</a> <br /> <br /> Free icons with varying licenses can be found here: <br /> <span style="text-decoration:underline"><br /> </span><a href=http://openiconlibrary.sourceforge.net/ target=_blank>http://openiconlibrary.sourceforge.net</a> <span style="text-decoration:underline"><br /> </span><a href=http://www.freeiconsweb.com/>http://www.freeiconsweb.com</a> <span style="text-decoration:underline"><br /> </span><a href=http://www.famfamfam.com/ target=_blank>http://www.famfamfam.com</a> <span style="text-decoration:underline"><br /> </span><a href=http://p.yusukekamiyamane.com/ target=_blank>http://p.yusukekamiyamane.com</a> <br /> <br /> For the latter, licenses reach from GPL, LGPL, Creative Commons to Public Domain. I guess for pure inhouse development, this is not that important, but if you plan to sell your application or publish it on <a href=http://openntf.org/ target=_blank>OpenNTF</a>, you should doublecheck if the icon license is ok for your use case. <br /> <br /> Feel free to add your own favorites by commenting on this article!   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/08.02.2012084418KLEB4A.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/08.02.2012084418KLEB4A.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>XPages series #13: XPiNC app development tool</title>
<pubDate>Thu, 2 Feb 2012 16:24:12 +0200</pubDate>
<description>
<![CDATA[ 
I was just working on an XPiNC integration of a quite large application and had some trouble getting it to work in the Notes Client (the app was working well on the web already). Finding out why it wa ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm</link>
<category>XPages</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm</guid>
<content:encoded><![CDATA[ I was just working on an XPiNC integration of a quite large application and had some trouble getting it to work in the Notes Client (the app was working well on the web already). Finding out why it was not working was even harder in this case than when dealing with "normal" XPages applications, because the application is not based on the Dojo web toolkit, but uses <a href=http://www.sencha.com/products/extjs/ target=_blank>Sencha's Ext JS</a> for the UI and is completely based on our own web app development framework. <br />The framework does not use XPages design elements at all, but follows a simple REST API architecture with standard servlets to produce the data and user interface. <br /> <br />The benefit of this approach is that web applications can be developed, run and debugged from a pure Eclipse environment. They can even run on an different servlet engine than the Domino server's http task and - thanks to our data abstraction layer - they can even store the whole app data in a non-Domino database and mix/merge data between different database types. <br /> <br />Another benefit is that almost all the code has been written by ourselves. So it's not a kind of blackbox, made by IBM, where it's hard to work around occuring issues, but we are able to track issues down right until the <tt>service(HttpServletRequest req, HttpServletResponse response) </tt>call coming from the web container. <br /> <br />The downside is of course, that apps developed with the framework do not make use of IBM's <a href=http://extlib.openntf.org/ target=_blank>XPages Extension Library</a>, that contains various powerful UI controls. So we needed to create them ourselves. <br /> <br />And regarding XPiNC development, there is another downside: JavaScript errors do not get logged/displayed in the Notes Client, unless you register your own global error handler (providing a function for window.onerror). <br />Normal XPiNC applications do already contain such an error handler (somewhere within the XSP API object), which uses an internal bridge to post the error content to the Notes Client's status bar. <br /> <br /><strong>The development tool</strong> <br /> <br />To make development of XPiNC applications easier, I have created a small Eclipse plugin that displays three icons in the Client's toolbar: <br /> <div align=center><img  alt="Image:XPages series #13: XPiNC app development tool" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm/content/M2?OpenElement" /></div> <br /> <br />The third icon lauches a piece of code that injects <a href=http://getfirebug.com/firebuglite target=_blank>Firebug lite</a> into the currently visible XPage: <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <code><strong>public</strong> <strong>void</strong> run(IAction action) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IWorkbenchPart part =  <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PlatformUI.<em>getWorkbench</em>().getActiveWorkbenchWindow().getPartService().getActivePart(); <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <strong>if</strong> (part <strong>instanceof</strong> XspViewPart) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; XspViewPart xPart=(XspViewPart)part; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; XspXulRunnerBrowser browser=xPart.getWebBrowser(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HTMLDocument doc=browser.getDocument(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NodeList headNodes=doc.getElementsByTagName("head"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <strong>if</strong> (headNodes!=<strong>null</strong> &amp;&amp; headNodes.getLength()>0 <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;&amp; headNodes.item(0) <strong>instanceof</strong> Element) { <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //add this snippet to the HTML DOM tree: <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //< script type="text/javascript" <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // src="https://getfirebug.com/firebug-lite.js" > < /script > <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String firebugUrl="https://getfirebug.com/firebug-lite-debug.js"; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Element headNode=(Element) headNodes.item(0); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Element scriptNode=doc.createElement("script"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scriptNode.setAttribute("type", "text/javascript"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scriptNode.setAttribute("src", firebugUrl); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headNode.appendChild(scriptNode); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <strong>else</strong> { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MessageDialog.<em>openError</em>(Display.<em>getDefault</em>().getActiveShell(), "Error", <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "This action does only work within an XPiNC application!"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; }</code> <br /> <br />The result looks like this: <br /><br> <div align=center><img  alt="Image:XPages series #13: XPiNC app development tool" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm/content/M3?OpenElement" /></div> <br /> <br />Using Firebug Lite, you can easily inspect the HTML DOM tree and CSS attributes of the current page. Another very useful feature is the <a href=http://getfirebug.com/logging target=_blank>Console API</a>, which you may know already from classic browser development: <br />it lets you write log/debug messages to the browser console (by calling console.log('...')) and has other nice features like stacktrace dumping of JavaScript calls. <br /> <br />To our surprise we found out that the pure Xulrunner engine, that is used to display XPages in the Notes Client, does not register the global "console" at all. So Firebug lite came to the rescue. You can find all your log messages in the Console tab. <br /> <br />The other two toolbar actions are even more powerful. One lets you define a custom script library URL, e.g. to a script library design element on a public or intranet web server. The other actions will then create a script tag in the current XPage that points to the library. That way, you can inject any code you like into the XPiNC application. <br /> <br /><strong>Download</strong> <br /> <br />Finally, here is the download link with the Eclipse plugin project, feature project and update site: <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/xpinc-firebuglite-helper.zip/$file/xpinc-firebuglite-helper.zip" title="xpinc-firebuglite-helper.zip">xpinc-firebuglite-helper.zip</a> <br /> <br />Hope this helps! <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/02.02.2012162412KLEL3Q.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/02.02.2012162412KLEL3Q.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Lotusphere 2012: Download links for 105 additional session slides</title>
<pubDate>Sun, 22 Jan 2012 22:59:10 +0200</pubDate>
<description>
<![CDATA[ 
I just compared the current state of the Lotusphere 2012 website with my previously released list of session slide download links. I found 105 new slide downloads: ls12_20120122.csv ls12_20120122.htm ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/22.01.2012225910KLETSK.htm</link>
<category>Lotusphere 2012</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/22.01.2012225910KLETSK.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/22.01.2012225910KLETSK.htm</guid>
<content:encoded><![CDATA[ I just compared the current state of the <a href=http://www.socialbizonline.com target=_blank>Lotusphere 2012 website</a> with <a href="http://www.mindoo.com/web/blog.nsf/dx/17.01.2012105009KLELKX.htm" target="_blank">my previously released list of session slide download links</a>. <br />I found 105 new slide downloads: <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/ls12_20120122.csv/$file/ls12_20120122.csv">ls12_20120122.csv</a> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/ls12_20120122.html/$file/ls12_20120122.html">ls12_20120122.html</a> <br /> <br />There are still a few missing slide decks, but it's a big step forward.  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/22.01.2012225910KLETSK.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/22.01.2012225910KLETSK.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Lotusphere 2012: download links for session slides</title>
<pubDate>Tue, 17 Jan 2012 10:50:09 -0400</pubDate>
<description>
<![CDATA[ 
I just spent some time to grab the download links of the sessions slides from the Lotusphere 2012 website. Since my Macbook Pro could not get a proper connection to the wireless network in Dolphin (ne ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/17.01.2012105009KLELKX.htm</link>
<category>Lotusphere 2012</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/17.01.2012105009KLELKX.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/17.01.2012105009KLELKX.htm</guid>
<content:encoded><![CDATA[ I just spent some time to grab the download links of the sessions slides from the <a href=http://www.socialbizonline.com target=_blank>Lotusphere 2012 website</a>. Since my Macbook Pro could not get a proper connection to the wireless network in Dolphin (network is quite bad both at Lotusphere and in the Yacht Club we are staying in), I had to do this on the iPhone, because it was the only device that got an IP address. That was fun. ;-) <br /> <br />So here are the links to the slides that are available so far, sorted by session ID. Unfortunately, many are still missing. From our last years experience, the speakers are not the one to blame here. All had to submit their slides back in December. <br /> <br />Hopefully, the remaining session slides will follow shortly. <br /> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/ls12_20120117.csv/$file/ls12_20120117.csv">ls12_20120117.csv</a> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx/ls12_20120117.html/$file/ls12_20120117.html">ls12_20120117.html</a> <br /> <br />Use your preferred download utility (e.g. <a href=https://addons.mozilla.org/de/firefox/addon/downthemall/ target=_blank>DownThemAll</a>) for download. You need to be logged in on the LS12 website before downloading.  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/17.01.2012105009KLELKX.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/17.01.2012105009KLELKX.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>Status report / no session submission for LS12</title>
<pubDate>Mon, 7 Nov 2011 10:27:35 +0200</pubDate>
<description>
<![CDATA[ 
It's been some time since the last blog post in July. The last weeks have been incredibly busy, working five days a week on 3-4 projects at customers on-site does not leave much time for blogging and it does not look like this will change very soon.
To give you an impression, here are a few things that we've been working on ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/07.11.2011102731KLED4S.htm</link>
<category>Lotusphere 2012</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/07.11.2011102731KLED4S.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/07.11.2011102731KLED4S.htm</guid>
<content:encoded><![CDATA[ It's been some time since the last blog post in July. The last weeks have been incredibly busy, working five days a week on 3-4 projects at customers on-site does not leave much time for blogging and it does not look like this will change very soon. <br /> To give you an impression, here are a few things that we've been working on: <br /> <strong><br /> Development of an OSGi based web application framework with Ext.js UI </strong><br /> Abstraction layer for web applications that unifies data access across document-oriented and relational database systems, allows for tracking of data object changes (old/new values, group multi-object changes as transactions), different kinds of data serialization like XML or JSON and visualizing data with an Ext.js based, dynamically created web UI (using <a href=http://jamon.org/ target=_blank>Jamon</a> template language) that reads and writes contents through REST APIs. The framework can run from pure Eclipse and also in Domino's OSGi container. <br /> <strong><br /> Development of an OSGi based XPages application framework with Dojo UI</strong> <br /> XPages extensibility API add-on to develop the backend code of XPages directly in Java instead of writing SSJS code or Expression Language to bridge between UI element events/properties and application code. <br /> The framework uses Java Annotations and Java Reflection APIs for UI/backend code weaving. <br /> <strong><br /> Development of an IBM Websphere portal server applications</strong> <br /> Custom development of market-analysis application for consumer goods industry. <br /> <strong><br /> Development of dynamic web application based on Glassfish and JPA, with jQuery and Highcharts</strong> <br /> Data analysis tool for the buying department of a German automotive company. <br /> <strong><br /> Plugin development for the Lotus Notes Client</strong> <br /> Several productivity enhancement plugins for the Lotus Notes Client <br /> <strong><br /> Plugin deployment support</strong> <br /> Autodetection routine for XPages applications in Client/Server to automatically check for required Eclipse features/plugins when an application is opened (implemented in Lotusscript) so that the XPages runtime does not display those confusing error messages about missing XPages extensions. Instead, errors are properly handled without user interaction and missing features are automatically deployed on the machine. <br /> <strong><br /> XPiNC development framework</strong> <br /> Spent time to work on enhancements for the <a href=http://xpages2eclipse.mindoo.com/ target=_blank>XPages2Eclipse</a> toolkit that provides Eclipse APIs to XPages applications in the Lotus Notes Client. <br /> <strong><br /> Classic Domino web application development</strong> <br /> Improved round tripping quality of richtext editing between web browser and Notes Client including paste optimization from MS Word. Solution uses a combination of CKeditor add-ons and HTML/DXL conversions developed in Lotussript code for R7. &nbsp;Customer: print industry <br /> <strong><br /> Classic Notes Client development</strong> <br /> Built a Notes application to automatically deploy and update a list of mail folders to iOS users on Traveler. <br /> <br /> <strong><hr><br /> A word about Lotusphere 2012</strong> <br /> Since time is so limited, <strong>we decided not to submit a session proposal for Lotusphere 2012</strong>. <br /> <br /> We will however participate with full conference pass and I just booked hotel and flight two days ago. In contrast to previous years, we will arrive one day earlier, on Friday, 13th of January 2012 (hopefully not a bad day for travel, at least it's a direct flight :-)). <strong><br /> Are there any plans yet for a blogger meeting for a beer or two on Saturday 14th like in previous years?</strong> <br /> <br /> Another reason not to submit a session is that things get more complicated year after year. To learn about OSGi development or XPages extensibility APIs in a hands-on session for a day or two does make much more sense than watching a one hour presentation. <br /> <br /> We could have submitted our plugin development session from last year another time (<a href="http://www.mindoo.com/web/blog.nsf/dx/06.02.2011171725KLEM4Y.htm" target="_blank">overview of plugin development for Notes Client and DDE with 14 demos</a>), because slides and demos are already done. But that session (which got very good feedback at LS11) has now been presented four times at two conferences (Lotusphere and German Entwicklercamp 2010/2011). It's hard to get motivated for the 5th time :-). <br /> <br /> <br /> So, to sum up this long blog entry, I am really looking forward to seeing many of you guys at LS12 - and to having more time to work on concepts and product prototypes in the next weeks.   ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/07.11.2011102731KLED4S.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/07.11.2011102731KLED4S.htm?opendocument&amp;comments</wfw:comment>
</item>
<item>
<title>XPages series #12: XAgents and performance bottlenecks</title>
<pubDate>Sun, 17 Jul 2011 10:18:55 +0200</pubDate>
<description>
<![CDATA[ 
XAgent is a term that describes the equivalent of a classic Notes web agent in XPages technology: an XPage is called via URL and produces any kind of data (e.g. HTML, dynamic images, data in JSON form ...
 ]]>
</description>
<link>http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm</link>
<category>XPages</category>
<dc:creator>Karsten Lehmann</dc:creator>
<comments>http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm?opendocument&amp;comments</comments>
<guid isPermaLink="true">http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm</guid>
<content:encoded><![CDATA[ <em>XAgent</em> is a term that describes the equivalent of a classic Notes web agent in XPages technology: an XPage is called via URL and produces any kind of data (e.g. HTML, dynamic images, data in JSON format or ODF documents) by sending Strings or even raw bytes directly to the browser. <br />&nbsp;<br /> Chris Toohey and Stephan Wissel have already blogged about this topic a few years ago and discussed some use cases: <br /> <span style="text-decoration:underline"><br /> </span><a href=http://www.dominoguru.com/pages/domino_rest_xpages_part1.html target=_blank><span style="text-decoration:underline">IBM Lotus Notes Domino REST Web Services via XPage XAgents</span></a> <span style="text-decoration:underline"><br /> </span><a href="http://www.wissel.net/blog/d6plinks/SHWL-7MGFBN" target=_blank><span style="text-decoration:underline">Web Agents XPages style</span></a>  <br /> <br /><strong>How to write an XAgent</strong> <br />To write an XAgent, you basically need to do two things: first you add the attribute <code>rendered="false"</code> to the <code>xp:view</code> tag of an XPage to prevent the XPages engine from rendering any output. Second, you need to write the code that produces the data and add it to the beforeRenderResponse event of an XPage. <br /> <br />Here are two simple example XAgents. The first one writes XML content to the writer object of the servlet response (which is used to return character data): <br /> <br /><code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />?xml version="1.0" encoding="UTF-8"?<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:this.beforeRenderResponse<img  src="http://www.mindoo.com/web/blog.nsf/dx//$file//icons/ecblank.nsf" width="1" height="1" /<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />!&#91;CDATA&#91;#{javascript:try { <br />&nbsp; &nbsp; &nbsp; &nbsp; var uName = session.createName(session.getEffectiveUserName()); <br />&nbsp; &nbsp; &nbsp; &nbsp; var exCon = facesContext.getExternalContext(); <br />&nbsp; &nbsp; &nbsp; &nbsp; var response = exCon.getResponse(); <br />&nbsp; &nbsp; &nbsp; &nbsp; var writer = response.getWriter(); <br />&nbsp; &nbsp; &nbsp; &nbsp; response.setContentType("text/xml"); <br />&nbsp; &nbsp; &nbsp; &nbsp; response.setHeader("Cache-Control", "no-cache"); <br />&nbsp; &nbsp; &nbsp; &nbsp; writer.write("<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />?xml version=\"1.0\" encoding=\"UTF-8\"?<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>\n"); <br />&nbsp; &nbsp; &nbsp; &nbsp; writer.write("<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />test<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>Hello "+uName.getAbbreviated()+"<<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/test<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />>"); <br />&nbsp; &nbsp; &nbsp; &nbsp; facesContext.responseComplete(); <br />} <br />catch (e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; _dump(e); <br />}}&#93;&#93;><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:this.beforeRenderResponse<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:view<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br />The second example demonstrates how you can load a file resource from the database design and write it to the output stream object of the servlet response: <br /> <br /><code><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />?xml version="1.0" encoding="UTF-8"?<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false"<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />> <br /> <br />&nbsp; &nbsp; &nbsp; &nbsp; <<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />xp:this.beforeRenderResponse<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />!&#91;CDATA&#91;#{javascript:try { <br />&nbsp; &nbsp; &nbsp; &nbsp; var exCon = facesContext.getExternalContext(); <br />&nbsp; &nbsp; &nbsp; &nbsp; var response = exCon.getResponse(); <br />&nbsp; &nbsp; &nbsp; &nbsp; var outStream = response.getOutputStream(); <br />&nbsp; &nbsp; &nbsp; &nbsp;  <br />&nbsp; &nbsp; &nbsp; &nbsp; //load a file resource from db design and write it to the output stream <br />&nbsp; &nbsp; &nbsp; &nbsp; var cl=com.ibm.domino.xsp.module.nsf.NotesContext.getCurrent().getModule().getModuleClassLoader(); <br />&nbsp; &nbsp; &nbsp; &nbsp; var buf=new byte&#91;16384&#93;; <br />&nbsp; &nbsp; &nbsp; &nbsp; var len; <br />&nbsp; &nbsp; &nbsp; &nbsp; var filePath="/test/document.docx"; <br />&nbsp; &nbsp; &nbsp; &nbsp; var inStream=cl.getResourceAsStream(filePath); <br />&nbsp; &nbsp; &nbsp; &nbsp; if (inStream==null) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var errMsg="File "+filePath+" not found"; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _dump(errMsg); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response.sendError(404, errMsg); <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; else { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //set mime type according to file type <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response.setHeader("Cache-Control", "no-cache"); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //send http header with filename (needed so that the browser does not use the XPage's name as filename) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response.setHeader("Content-Disposition", 'attachment; filename="document.docx"'); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //read bytes from inStream into the buffer <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while ((len=inStream.read(buf))<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />-1) { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //and write the data to the output stream <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.write(buf, 0, len); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inStream.close(); <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.close(); <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; facesContext.responseComplete(); <br />} <br />catch (e) { <br />&nbsp; &nbsp; &nbsp; &nbsp; _dump(e); <br />}}&#93;&#93;<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:this.beforeRenderResponse<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />><<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />/xp:view<img  src="http://www.mindoo.com/web/blog.nsf/dx//icons/ecblank.nsf/$file//icons/ecblank.nsf" width="1" height="1" />></code> <br /> <br />The loaded file resource must be part of the NSF project's build path to make the XPage code find it (that's where the module classloader is looking for files). <br />Please refer to <a href="http://www.mindoo.com/web/blog.nsf/dx/15.07.2009152504KLEHR8.htm" target="_blank"/>part two of this XPages series</a> to get more information about how to add a folder to the build path. <br /> <br /> <div align=center> <br /><img  alt="Image:XPages series #12: XAgents and performance bottlenecks" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm/content/M2?OpenElement" /></div> <br />If you just want to offer a file for download, developing an XAgent to stream the data would probably be the wrong solution. <br /> <br />In that case, you should add your files to the database design in the Java Perspective of Domino Designer instead and reference them directly in a URL. This is something that is used in the OpenNTF project <a href=http://mobilecontrols.openntf.org/ target=_blank>XPages Mobile Controls</a> to add a newer Dojo version (e.g. 1.6 with advanced mobile device support) to a Domino server than the default one (e.g. version 1.4.3 for Lotus Domino 8.5.2). <br /> <br />But the second code example from above could of course be modified to do something more useful, for example to replace placeholders in the file, create a zip file from multiple files on the fly using Java's <a href=http://download.oracle.com/javase/6/docs/api/java/util/zip/ZipOutputStream.html target=_blank>ZipOutputStream</a> or render a <a href="http://www.openntf.org/internal/home.nsf/project.xsp?action=openDocument&amp;name=Xpages%20Captcha%20Custom%20Control" target=_blank>captcha image</a> for spam protection. <br /> <br /><strong>Sounds great?</strong> <br />Well, before you start thinking about building large applications based on this approach, you should read on to get to know about it's limitations. <br /> <br /><strong>The limitations</strong> <br />What I'm going to show you is not only a limitation of XAgents, but of XPages technology in general. For XPages producing the user interface of an application, this limitation may not be critical, but it can become a <strong>show stopper</strong> for using them the XAgent way. <br /> <br />I've created a small test application with three XPages: Start.xsp, Frame1.xsp and Frame2.xsp (<a href="http://www.mindoo.com/web/blog.nsf/dx/xsp-rendering-synchronization.zip/$file/xsp-rendering-synchronization.zip">download link</a>). The first one (Start.xsp) contains two iframes and a button. By clicking on the button, the other two XPages are loaded as iframe contents:  <br /> <br /><code>var now=new Date(); <br />var nowTime=now.getTime(); <br />var iframe1=document.getElementById("iframe1"); <br />var iframe2=document.getElementById("iframe2"); <br />iframe1.src=document.location.pathname+"/Frame1.xsp?startTime="+nowTime; <br />iframe2.src=document.location.pathname+"/Frame2.xsp?startTime="+nowTime;</code> <br /> <br />Frame1.xsp contains beforeRenderResponse event code that delays the rendering for 5000 milliseconds (<code>java.lang.Thread.sleep(5000)</code>), while Frame2.xsp waits for 2500 milliseconds. <br /> <br />You would expect that both XPages are opened and rendered concurrently. Because of the delay, Frame2.xsp should be visible first, then Frame1.xsp. <br /> <br />Unfortunately, the output looks like this instead (click on the image to open the test application): <br /> <div align=center> <br /><a href="http://www.mindoo.com/web/blog.nsf/dx//web/samples/xsp-rendering-synchronization.nsf" target=_blank><img  alt="Image:XPages series #12: XAgents and performance bottlenecks" border="0" src="http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm/content/M3?OpenElement" /></a></div> <br />Frame1.xsp is displayed first, followed by Frame2.xsp. Frame2.xsp takes about 7600 milliseconds to be rendered, which is the sum of both delays, because <font color="#ff0000"><strong>the XPages engine does not render multiple XPages in an application at the same time for a single user</strong></font>. <br /> <br />It was a real surprise when we noticed this effect in a customer project. Our UI was based on the <a href=http://www.sencha.com/ target=_blank>Ext JS</a> toolkit which is heavily using REST services to read the UI component data. Our plan was to use XAgents for those REST services, but we quickly noticed that all UI elements only received data one at a time, which was a no-go for the application UI performance. Nothing was loading in parallel. <br /> <br />There are technical reasons for such a restriction, as Philippe Riand, XPages Chief Architect at IBM, explained to me in April 2011. <br />As you may know, the XPages runtime is based on JSF technology, which uses a tree of components on the server side that represents the structure of a web page and its current state. The tree is created/restored when a HTTP request comes in and saved/discarded after it is completed. <br />Unfortunately, this tree does not support being accessed by two concurrent threads, which would break many things like data sources and component states. <br /> <br />To prevent this to happen, XPages synchronizes on the user session object (<a href=http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpSession.html target=_blank>HttpSession</a>), so that only one thread can access the tree at a time. But by synchronizing on the user session (and not just on the component tree instance), the XPages dev crew also prevented any other XPage in an application from running (the Domino server seems to assign session objects on a per database basis).  <br /> <br />The consequence is that you should think twice about your XPages application architecture, if you have many concurrent HTTP requests or if some of them take a lot of time to be processed. <strong>An XAgent may be the easiest solution to deploy, but may not produce the best user experience in all cases</strong>. <br /> <br /><strong>Workarounds and solution</strong> <br />There is some hope that the situation will improve in Domino 8.5.3. <br /> <br />As Philippe said, the next XPages engine will be smarter in synchronization and synchronize less than previously. <br />In addition, there will be a new database property called <code>xsp.session.transient</code>. This flag means that unique session objects will be created per request to the server and discarded right after the request ended. This is a first attempt to provide session less mode. <br />If you use this option, then you can create one database with all the services and no synchronization will happen, as each request will have its own session object. <br /> <br />I have requested a more granular option so that you can activate session less mode for single XPages in an application, but I'm not sure if this will make 8.5.3. <br /> <br />For Domino 8.5.2, I can see three things that you can do if you can't live with this performance issue: <br /> <br /><strong>1. Move XPages that run for a long time to separate databases</strong> <br />This does not help a lot, but if you have an XPages application with an XPage that needs some time to process, you could move it to different database. In that case, the rest of the application would still be responsive, although your long running XPage for example produces a 100 MB log output in XML format that you want to download. <br /> <br /><strong>2. &nbsp;Write your own servlet in Java</strong> <br />By writing your own servlet as an Eclipse plugin running in Domino 8.5.2's OSGi framework, your code can run without any performance bottleneck caused by synchronization. See <a href="http://www.openntf.org/blogs/openntf.nsf/d6plinks/NHEF-8JB9DN" target=_blank>this article in the OpenNTF blog</a> for implementation details. <br /> <br /><strong>3. There is an app for that :-)</strong> <br />As you may know, we have developed <a href=http://xpages2eclipse.mindoo.com target=_blank>XPages2Eclipse</a>, an extensive toolkit for XPages development, which is currently in beta-testing (June 2011). The articles <a href=http://xpages2eclipse.mindoo.com/web/x2ewiki.nsf/dx/JavaScriptServletMode target=_blank>Building servlets in JavaScript</a> and <a href=http://xpages2eclipse.mindoo.com/web/x2ewiki.nsf/dx/JavaServletMode target=_blank>Building servlets in Java</a> demonstrate how you can write your own servlet implementation in JavaScript or Java language. <br />This solution reads all your code from the database design, so that you don't have to deploy every servlet individually. Just install the toolkit on a Domino server once, then you can create any number of servlets by writing code in Domino Designer and replicate them to the server. <br /> <br />  ]]></content:encoded>
<wfw:commentRss> http://www.mindoo.com/web/blog.nsf/dxcomments/17.07.2011101855KLEBRW.htm</wfw:commentRss>
<wfw:comment> http://www.mindoo.com/web/blog.nsf/dx/17.07.2011101855KLEBRW.htm?opendocument&amp;comments</wfw:comment>
</item>
</channel></rss>
