Mindoo Blog - Cutting edge technologies - About Java, Lotus Notes and iPhone

  • XPages series #13: XPiNC app development tool

    Karsten Lehmann  February 2 2012 04:24:12 PM
    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 Sencha's Ext JS for the UI and is completely based on our own web app development framework.
    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.

    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.

    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 service(HttpServletRequest req, HttpServletResponse response) call coming from the web container.

    The downside is of course, that apps developed with the framework do not make use of IBM's XPages Extension Library, that contains various powerful UI controls. So we needed to create them ourselves.

    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).
    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.

    The development tool

    To make development of XPiNC applications easier, I have created a small Eclipse plugin that displays three icons in the Client's toolbar:
    Image:XPages series #13: XPiNC app development tool


    The third icon lauches a piece of code that injects Firebug lite into the currently visible XPage:

            public void run(IAction action) {
                    IWorkbenchPart part =
                      PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService().getActivePart();

                    if (part instanceof XspViewPart) {
                            XspViewPart xPart=(XspViewPart)part;
                            XspXulRunnerBrowser browser=xPart.getWebBrowser();
                           
                            HTMLDocument doc=browser.getDocument();
                            NodeList headNodes=doc.getElementsByTagName("head");
                            if (headNodes!=null && headNodes.getLength()>0
                               && headNodes.item(0) instanceof Element) {

                                    //add this snippet to the HTML DOM tree:
                                    //< script type="text/javascript"
                                    // src="https://getfirebug.com/firebug-lite.js" > < /script >
                                    String firebugUrl="https://getfirebug.com/firebug-lite-debug.js";
                                    Element headNode=(Element) headNodes.item(0);
                                    Element scriptNode=doc.createElement("script");
                                    scriptNode.setAttribute("type", "text/javascript");
                                    scriptNode.setAttribute("src", firebugUrl);
                                    headNode.appendChild(scriptNode);
                            }
                    }
                    else {
                            MessageDialog.openError(Display.getDefault().getActiveShell(), "Error",
                              "This action does only work within an XPiNC application!");
                    }
            }


    The result looks like this:

    Image:XPages series #13: XPiNC app development tool


    Using Firebug Lite, you can easily inspect the HTML DOM tree and CSS attributes of the current page. Another very useful feature is the Console API, which you may know already from classic browser development:
    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.

    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.

    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.

    Download

    Finally, here is the download link with the Eclipse plugin project, feature project and update site:

    xpinc-firebuglite-helper.zip

    Hope this helps!

    Lotusphere 2012: Download links for 105 additional session slides

    Karsten Lehmann  January 22 2012 10:59:10 PM
    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.html

    There are still a few missing slide decks, but it's a big step forward.

    Lotusphere 2012: download links for session slides

    Karsten Lehmann  January 17 2012 04:50:09 PM
    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 (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. ;-)

    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.

    Hopefully, the remaining session slides will follow shortly.

    ls12_20120117.csv
    ls12_20120117.html

    Use your preferred download utility (e.g. DownThemAll) for download. You need to be logged in on the LS12 website before downloading.

    Status report / no session submission for LS12

    Karsten Lehmann  November 7 2011 10:27:35 AM
    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:

    Development of an OSGi based web application framework with Ext.js UI

    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 Jamon template language) that reads and writes contents through REST APIs. The framework can run from pure Eclipse and also in Domino's OSGi container.

    Development of an OSGi based XPages application framework with Dojo UI

    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.
    The framework uses Java Annotations and Java Reflection APIs for UI/backend code weaving.

    Development of an IBM Websphere portal server applications

    Custom development of market-analysis application for consumer goods industry.

    Development of dynamic web application based on Glassfish and JPA, with jQuery and Highcharts

    Data analysis tool for the buying department of a German automotive company.

    Plugin development for the Lotus Notes Client

    Several productivity enhancement plugins for the Lotus Notes Client

    Plugin deployment support

    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.

    XPiNC development framework

    Spent time to work on enhancements for the XPages2Eclipse toolkit that provides Eclipse APIs to XPages applications in the Lotus Notes Client.

    Classic Domino web application development

    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.  Customer: print industry

    Classic Notes Client development

    Built a Notes application to automatically deploy and update a list of mail folders to iOS users on Traveler.



    A word about Lotusphere 2012

    Since time is so limited, we decided not to submit a session proposal for Lotusphere 2012.

    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 :-)).
    Are there any plans yet for a blogger meeting for a beer or two on Saturday 14th like in previous years?


    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.

    We could have submitted our plugin development session from last year another time (overview of plugin development for Notes Client and DDE with 14 demos), 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 :-).


    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.

    XPages series #12: XAgents and performance bottlenecks

    Karsten Lehmann  July 17 2011 10:18:55 AM
    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 format or ODF documents) by sending Strings or even raw bytes directly to the browser.
     
    Chris Toohey and Stephan Wissel have already blogged about this topic a few years ago and discussed some use cases:

    IBM Lotus Notes Domino REST Web Services via XPage XAgents
    Web Agents XPages style

    How to write an XAgent
    To write an XAgent, you basically need to do two things: first you add the attribute rendered="false" to the xp:view 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.

    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):

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">

            <xp:this.beforeRenderResponse>><![CDATA[#{javascript:try {
            var uName = session.createName(session.getEffectiveUserName());
            var exCon = facesContext.getExternalContext();
            var response = exCon.getResponse();
            var writer = response.getWriter();
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            writer.write("<test>Hello "+uName.getAbbreviated()+"</test>");
            facesContext.responseComplete();
    }
    catch (e) {
            _dump(e);
    }}]]></xp:this.beforeRenderResponse></xp:view>


    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:

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">

            <xp:this.beforeRenderResponse><![CDATA[#{javascript:try {
            var exCon = facesContext.getExternalContext();
            var response = exCon.getResponse();
            var outStream = response.getOutputStream();
           
            //load a file resource from db design and write it to the output stream
            var cl=com.ibm.domino.xsp.module.nsf.NotesContext.getCurrent().getModule().getModuleClassLoader();
            var buf=new byte[16384];
            var len;
            var filePath="/test/document.docx";
            var inStream=cl.getResourceAsStream(filePath);
            if (inStream==null) {
                    var errMsg="File "+filePath+" not found";
                    _dump(errMsg);
                    response.sendError(404, errMsg);
            }
            else {
                    //set mime type according to file type
                    response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
                    response.setHeader("Cache-Control", "no-cache");
                    //send http header with filename (needed so that the browser does not use the XPage's name as filename)
                    response.setHeader("Content-Disposition", 'attachment; filename="document.docx"');
                   
                    //read bytes from inStream into the buffer
                    while ((len=inStream.read(buf))>-1) {
                            //and write the data to the output stream
                            outStream.write(buf, 0, len);
                    }
                    inStream.close();
                    outStream.close();
            }
            facesContext.responseComplete();
    }
    catch (e) {
            _dump(e);
    }}]]></xp:this.beforeRenderResponse></xp:view>


    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).
    Please refer to part two of this XPages series to get more information about how to add a folder to the build path.


    Image:XPages series #12: XAgents and performance bottlenecks

    If you just want to offer a file for download, developing an XAgent to stream the data would probably be the wrong solution.

    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 XPages Mobile Controls 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).

    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 ZipOutputStream or render a captcha image for spam protection.

    Sounds great?
    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.

    The limitations
    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 show stopper for using them the XAgent way.

    I've created a small test application with three XPages: Start.xsp, Frame1.xsp and Frame2.xsp (download link). 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:

    var now=new Date();
    var nowTime=now.getTime();
    var iframe1=document.getElementById("iframe1");
    var iframe2=document.getElementById("iframe2");
    iframe1.src=document.location.pathname+"/Frame1.xsp?startTime="+nowTime;
    iframe2.src=document.location.pathname+"/Frame2.xsp?startTime="+nowTime;


    Frame1.xsp contains beforeRenderResponse event code that delays the rendering for 5000 milliseconds (java.lang.Thread.sleep(5000)), while Frame2.xsp waits for 2500 milliseconds.

    You would expect that both XPages are opened and rendered concurrently. Because of the delay, Frame2.xsp should be visible first, then Frame1.xsp.

    Unfortunately, the output looks like this instead (click on the image to open the test application):

    Image:XPages series #12: XAgents and performance bottlenecks

    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 the XPages engine does not render multiple XPages in an application at the same time for a single user.

    It was a real surprise when we noticed this effect in a customer project. Our UI was based on the Ext JS 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.

    There are technical reasons for such a restriction, as Philippe Riand, XPages Chief Architect at IBM, explained to me in April 2011.
    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.
    Unfortunately, this tree does not support being accessed by two concurrent threads, which would break many things like data sources and component states.

    To prevent this to happen, XPages synchronizes on the user session object (HttpSession), 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).

    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. An XAgent may be the easiest solution to deploy, but may not produce the best user experience in all cases.

    Workarounds and solution
    There is some hope that the situation will improve in Domino 8.5.3.

    As Philippe said, the next XPages engine will be smarter in synchronization and synchronize less than previously.
    In addition, there will be a new database property called xsp.session.transient. 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.
    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.

    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.

    For Domino 8.5.2, I can see three things that you can do if you can't live with this performance issue:

    1. Move XPages that run for a long time to separate databases
    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.

    2.  Write your own servlet in Java
    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 this article in the OpenNTF blog for implementation details.

    3. There is an app for that :-)
    As you may know, we have developed XPages2Eclipse, an extensive toolkit for XPages development, which is currently in beta-testing (June 2011). The articles Building servlets in JavaScript and Building servlets in Java demonstrate how you can write your own servlet implementation in JavaScript or Java language.
    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.


    XPages2Eclipse: New Beta-Build available

    Karsten Lehmann  July 11 2011 09:48:16 PM
    Today I got notified by one of the beta testers that the keystore template in the update site database is corrupt/incomplete. Thanks for that!

    The issue should now be fixed, I just uploaded a new version of the update site archive, which you can download via the download link on the product website :

    Image:XPages2Eclipse: New Beta-Build available


    Beta version of XPages2Eclipse available: Development toolkit for XPages in the Notes Client

    Karsten Lehmann  June 29 2011 09:10:37 AM
    It's been quite silent in this blog since the last posting in March, but we had a good reason to concentrate on our work:

    Today we are releasing the first public beta version of a new XPages development toolkit to the public!

    It's called XPages2Eclipse, a language extension for XPages development in the Lotus Notes Client 8.5.2 and higher.

    With XPages2Eclipse, XPages applications become first class citizens in the Lotus Notes Client.

    The toolkit contains a variety of APIs that developers can leverage to connect their XPages applications to the Eclipse-based Notes Client UI, classic Lotus Notes applications and even communicate with IBM Lotus Symphony R3, all from server-side JavaScript (SSJS) code.

    Here are only a few features that the toolkit has to offer:
    • Embed existing Notes applications: fill in Notes forms and Emails with data from XPages applications, access documents selected in classical Notes views, run existing LotusScript code
    • Import or export of data from IBM Lotus Symphony, supporting documents, spreadsheets and presentations
    • Execute document attachments with associated desktop-applications (for Windows, Linux and Mac OS)
    • Access the system clipboard to store HTML, text, images or files
    • Execute long-running operations in the background, display their progress and let the user cancel the operation if necessary
    • Convenient features like file selection, including multi-selection, and folder selection
    • Launch JavaScript code on Notes Client startup, when a toolbar button is clicked and on specific UI events like focus changes in the Client
    • Develop servlets using Javascript and Java with code stored in NSF
    To get more information, download a beta version and find a lot of documentation with demo applications please visit the XPages2Eclipse product area on our website:



    XPages series #11: Log data changes using beans and the DataObject interface

    Karsten Lehmann  March 18 2011 10:47:26 AM
    As promised last week, this blog article demonstrates how managed beans can be used to create and edit Notes documents, transparently log data changes and even support alternative storage systems. This is my third and final sample from the Lotusphere 2011 session BP212.

    If you followed this blog series from the beginning and take a look at the slides for the session BP212, you already know most of the technical details this sample is about:
    • declare managed beans
    • bind XPages UI fields with bean properties
    • use managed properties to declaratively configure managed beans

    So there is not much new content, but it's a nice sample that shows how all the parts fit together in an application.


    The download for this article contains a simple Notes database with four XPages:

    Start.xsp
    This XPage is the starting point when you open the database. It contains three buttons to create new company documents, view a list of existing documents and a button to view a change log that tracks data changes in the database:

    Image:XPages series #11: Log data changes using beans and the DataObject interface


    Company.xsp
    The Company XPage let's you create and edit company documents with fields for the company name and its address:

    Image:XPages series #11: Log data changes using beans and the DataObject interface


    Here is the source code for the XPage. The important parts are marked in red:

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
            <xp:span style="font-size:18pt;text-decoration:underline">Company information</xp:span>
            <xp:br style="font-size:18pt"></xp:br>
            <xp:br></xp:br>
            <xp:span style="font-size:18pt">Company name:</xp:span>
            <xp:br></xp:br>
            <xp:inputText id="inputText1" style="width:295.0px;font-size:18pt"
                    value="#{data.companyname}"></xp:inputText>
            <xp:br></xp:br>
            <xp:br></xp:br>
            <xp:span style="font-size:18pt">Address 1</xp:span>
            <xp:br style="font-size:18pt"></xp:br>
            <xp:inputText id="inputText2" style="width:295.0px;font-size:18pt"
                    value="#{data.address1}"></xp:inputText>
            <xp:br></xp:br>
            <xp:br></xp:br>
            <xp:span style="font-size:18pt">Address 2
    </xp:span>
            <xp:br></xp:br>
            <xp:inputText id="inputText3" style="width:295.0px;font-size:18pt"
                    value="#{data.address2}"></xp:inputText>
            <xp:br></xp:br>
            <xp:br></xp:br>
            <xp:span style="font-size:18pt">
                    City
            </xp:span>
            <xp:br style="font-size:18pt"></xp:br>
            <xp:inputText id="inputText4" style="width:295.0px;font-size:18pt"
                    value="#{data.city}"></xp:inputText>
            <xp:br></xp:br>
            <xp:br></xp:br>
            <xp:button value="Save" id="saveButton" style="font-size:18pt">
                    <xp:eventHandler event="onclick" submit="true"
                            refreshMode="complete">
                            <xp:this.action><![CDATA[#{javascript:actions["save"].execute();
    context.redirectToPage("CompanyList");}]]></xp:this.action>
                    </xp:eventHandler>
            </xp:button>
            <xp:button value="Cancel" id="cancelButton" style="font-size:18pt">
                    <xp:eventHandler event="onclick" submit="true"
                            refreshMode="complete">
                            <xp:this.action><![CDATA[#{javascript:context.redirectToPage("Start");}]]></xp:this.action>
                    </xp:eventHandler>
            </xp:button>
    </xp:view>


    We do not directly bind UI fields to document items (there is no document datasource declaration), but use a managed bean called "data" instead, hence the EL strings like #{data.companyname}.

    Actually, the bean implementation does not handle the load/store operation itself, it just redirects the calls to another class that handles them. This redirection is used to be able to change the storage system later on, e.g. from NSF to SQL, without modifying anything in the XPages UI.

    All we need to do is change a single managed property in the faces-config.xml file, which can be found in the WebContent/WEB-INF folder in the Java perspective of DDE:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config>
            <managed-bean>
                    <managed-bean-name>data</managed-bean-name>
                    <managed-bean-class>com.ls11.uibackend.PageDataBean
                    </managed-bean-class>
                    <managed-bean-scope>request</managed-bean-scope>
                   
                    <managed-property>
                            <property-name>dataProviderClass</property-name>
                            <!-- Dummy implementation to simulate loaded data -->
                            <!--
                            <value>com.ls11.uibackend.dummy.DummyPageDataProvider</value>
                            -->

                            <!-- Implementation that loads/stores data in a Notes database -->
                            <!--
                            <value>com.ls11.uibackend.nsf.NSFPageDataProvider</value>
                             -->

                             
                            <value>com.ls11.uibackend.dummy.DummyPageDataProvider</value>
                    </managed-property>
            </managed-bean>
            <managed-bean>
                    <managed-bean-name>actions>
                    <managed-bean-class>com.ls11.uibackend.PageActionsBean
                    </managed-bean-class>
                    <managed-bean-scope>request>
            </managed-bean>
      <!--AUTOGEN-START-BUILDER: Automatically generated by IBM Lotus Domino Designer. Do not modify.-->
      <!--AUTOGEN-END-BUILDER: End of automatically generated section-->
    </faces-config>


    As you can see, the database contains two implementations to load/store data:
    The NSFPageDataProvider  reads the documentId query string parameter and uses the corresponding Notes document to get the data. DummyPageDataProvider is just a dummy implementation that creates placeholder text, which might be useful for the UI designer to already test the UI even though the database developer is still working on the NSF/SQL storage code.

    Image:XPages series #11: Log data changes using beans and the DataObject interface
    Company XPage powered by the DummyPageDataProvider



    CompanyList.xsp
    The CompanyList XPage contains a view control and displays the company documents in the database:

    Image:XPages series #11: Log data changes using beans and the DataObject interface


    ChangeLog.xsp
    The main benefit of using managed beans for the UI bindings instead of directly binding fields to document datasource properties is that you can track, log, transform and prevent data changes in your code. During the page request, JSF calls the method setValue in our Java class with the item names and the new item values.

    We can then compare the old and new values and create a log record if the value has been changed:

            public void setValue(Object id, Object newValue) {
                    Object oldValue=getValue(id);
                   
                    boolean changed=(newValue==null & oldValue!=null) || (newValue!=null && !newValue.equals(oldValue));
                    if (changed) {
                            m_changedValues.put(id.toString(), newValue==null ? null : newValue.toString());
                            logChangedData(id.toString(), oldValue, newValue);
                    }
            }

            /**
             * Create a new change log entry for the modified field
             *
             * @param id field name
             * @param oldValue old value
             * @param newValue new value
             */

            private void logChangedData(String id, Object oldValue, Object newValue) {
                    Session session=NotesContext.getCurrent().getCurrentSession();

                    try {
                            DataChangeLogEntry newEntry=new DataChangeLogEntry(m_documentId==null || "".equals(m_documentId) ? "-New-" : m_documentId, session.getUserName(), new Date(), id, oldValue==null ? null : oldValue.toString(), newValue==null ? null : newValue.toString());
                            m_pendingLogEntries.add(newEntry);
                    } catch (NotesException e) {
                            throw new FacesException(e);
                    }
            }


    When the Company XPage is saved, all pending log records are written to a permanent log list which is displayed in a data table on the ChangeLog XPage:

    Image:XPages series #11: Log data changes using beans and the DataObject interface


    A word about com.ibm.xsp.model.DataObject
    If you take a deeper look at the code in the sample database, you might notice that the data bean implements the interface com.ibm.xsp.model.DataObject.
    This interface is part of the XPages runtime (not part of the JSF standard!) and simplifies both writing beans and the EL syntax to access bean properties.

    You will also find this interface in the session slides for BP212. Here is an excerpt from the slides:

           package com.acme.demo.persondata;

            import com.ibm.xsp.model.DataObject;

            public class PersonData implements DataObject {
                    public Class getType(Object id) {
                            // Return the type of class that id resolves to.
                            // Complex case could return Employee or Customer

                            return Person.class;
                    }

                    public Object getValue(Object id) {
                            // Retrieve a record from some store, based on id
                            return null;
                    }

                    public boolean isReadOnly(Object id) {
                            // You are free to implement your own, or rely on your underlying data store
                            return false;
                    }

                    public void setValue(Object id, Object value) {
                            // Store value in your data store using id
                    }
            }


    Implementing the DataObject interface makes JSF call the setValue/getValue methods in your bean for any string behind the bean name in the EL string: #{data.companyname], #{data.address1}, #{data.address2}, #{data.whatever}.

    You don't have to write getter and setter methods for every property!

    Please note that this could already be done without the DataObject interface by implementing the java.util.Map interface (JSF then calls the method Map.get(Object) instead of DataObject.getValue(Object)), but this XPages runtime class makes the implementation much easier and cleaner.

    That's it for today! Here is the download archive with the sample database:
    ls11_uibackendsep.zip


    The View article: XPath - A Flexible Solution for Filtering, Visualizing, and Binding XML Data in Your XPages Applications

    Karsten Lehmann  March 3 2011 10:52:42 PM
    I just received the information that an article that I wrote for The View has been published on their website. This article describes a way to use the XPath query language in XPages Expression Language, something I demonstrated in the Lotusphere session BP212.

    Here is the public abstract:

    XPath - A Flexible Solution for Filtering, Visualizing, and Binding XML Data in Your XPages Applications

    By using the XPath query language, you can query XML data in an XPages application and then seamlessly bind the results to the application’s fields and repeater controls. This enables you to easily and dynamically build interfaces using resources in your application or display XML data in a data table. Learn the syntaxes to use and get a demonstration of how to implement them in this flexible, easy-to-maintain solution.
    XPath, the XML path query language, is a powerful tool for selecting nodes and attributes from an XML document. Using XPath statements in XPages expression language, you can build dynamic XPages content based on an XML configuration document. No third-party library is required for this task. All the functionality you need is already available in IBM Lotus Notes and Domino 8.5.2, and all the information you need is here.

    Image:The View article: XPath - A Flexible Solution for Filtering, Visualizing, and Binding XML Data in Your XPages Applications

    Download link of sample application:
    theview_xpath-el.zip

    Full article (subscription required):
    Article on eview.com

    Slides from my two sessions at Entwicklercamp 2011 (German content)

    Karsten Lehmann  February 28 2011 09:25:21 AM
    Here are the slides of my two sessions at Entwickercamp 2011, Gelsenkirchen/Germany. As always, it was an interesting and very well organized event.