Latest Posts

Archives [+]

Categories [+]

Authors [+]

Entries filed under 'ajax'

    Posted by Kas Thomas AUG 25, 2010

    Posted in ajax, crx, crx gems, development, javascript, rest and sling Comments 7

    In previous posts, I've shown how to load movie data into CRX and how to render data for individual movies via HTML, SVG, and PDF. What I'd like to do now is show how easy it is to build interactivity into an app using a bit of AJAX combined with Sling's support for RESTful XPath-based search.

    It turns out that all we have to do to query the repository for, say, all nodes that have a value of "Hitchcock" under the property named "Director" is put together an XPath expression like

    //*[jcr:contains(@Director,'hitchcock')]

    and pass it to Sling in a URL that looks like:

    http://localhost:7402/content.query.json?queryType=xpath&statement=//*[jcr:contains(@Director,'hitchcock')]

    (assuming the repository is on port 7402 of localhost). This request will invoke a Lucene search of all nodes stored under the /content subtree. The results will come back as a JSON-formatted array:

    [
        {
            "name": "notorious",
            "jcr:path": "/content/films/notorious",
            "jcr:score": 3331
        },
        {
            "name": "under_capricorn",
            "jcr:path": "/content/films/under_capricorn",
            "jcr:score": 3331
        },
                . . .
    ]


    This is perfect, because it means we can use the JSON data to populate a dropdown menu (a "select" control in an HTML form) showing the names of films; and we can arrange things so that when the user clicks a "Show Details" button, the form updates to show detail information (title, director, year, genre, actor, actress, etc.) for the film in question. To get the detail information, of course, we can perform a behind-the-scenes AJAX query to the server. I already showed, in a previous post, how to render detail information for a given movie in an HTML page. All we really need to do at this point is put that HTML page into its own iframe, and (right next to it) add search controls to the page.

    The following form shows one possible way of handling things.

    /content/ddc/blog/2010/08/crx_gems_interactiv0/jcr:content/par/image_0/file

     

    Basically, we have an HTML form in which there are two action buttons: One is a Search button ("Search Films by") that initiates an XPath-based search of the repository based on a user-chosen criterion of Title, Director, Year, Genre, Actor, or Actress. The other is a Show Details button, underneath a picklist of films. Clicking the Search button populates the picklist with hits. When the user chooses a hit from the list and clicks Show Details, the left side of the page updates with detail information.

    The form consists of 200 lines of JavaScript and markup, as follows:

    <html>
    <head>
    <script>

    var CRX_BASE_URL = "http://localhost:7402";

    function addEventListeners( ) {

            document.getElementById( "_Query_" ).addEventListener(
            "keypress", function( e ) {
                    if ( 13 == e.keyCode )
                    handleClick( null );
            },
            false );

            document.getElementById( "_QueryButton_" ).addEventListener(
            "click", handleClick, false );



            document.getElementById( "_Fetch_" ).addEventListener(
            "click", handleFetch, false );

    }

    function getSearchMode( ) {

            return document.getElementById("_Select_").value;
    }

    function handleFetch( e ) {

            var list = document.getElementById("_Hits_");

            if (list.value) {
                    var url =  CRX_BASE_URL + list.value + ".html";
                    var iframe = document.getElementsByTagName("iframe")[0];

                    // force a reload of the iframe:
                    iframe.src = url;
            }
    }

    // get user's input and call server
    function handleClick( e ) {

            var userData =
            document.getElementById( "_Query_" ).value;

            if ( !userData )
                return;   // nothing to do

            var CRX_QUERY_PATH = "/content.query.json?queryType=xpath&statement=";
            var GETheader = {
                    "Accept": "application/json",
            };

            var query = createXPathQuery( userData );
            var url = CRX_BASE_URL + CRX_QUERY_PATH + query;

            myHttpGet( url, GETheader, handleResponse ); // hit server
    }


    function myHttpGet( url, header, handler ) {

            try {
                    request = new XMLHttpRequest();
                    request.open("GET", url, true);
                    for (i in header)
                    request.setRequestHeader( i, header[i] );
                    request.onreadystatechange = handler;

                    request.send("");
            }
            catch(e ) {
                    alert("Problem sending request: " + e.toString());
            }
    }

    function handleResponse( ) {

            if (request.readyState == 4) {
                    showResults( request );
            }
    }

    function showResults( request )  {

            var json = request.responseText;

            var hits = eval ( json );

            if ( null == hits ) {
                    alert( "No hits were found." );
                    return;
            }

            display( hits );
    }


    function display( hits ) {

            var div = document.getElementById( "_Hits_" );

            if ( null == div )
                throw( "Problem getting div for hitlist." );

            showHitCount( hits.length );

            var markup = "";

            for (var i = 0; i < hits.length; i++) {
                    markup += "<option value=\"" + hits[i][ "jcr:path" ] + "\">";
                    markup += fixName( hits[i].name );
                    markup += "</option>";
            }
            div.innerHTML = markup;
    }

    function fixName( name ) {
            var tmp = name.split("_");
            for (var i = 0; i < tmp.length; i++)
                tmp[i] = capitalize( tmp[i] );
            return tmp.join(" ");
    }

    function capitalize(a) {

            return typeof a[0] == 'undefined'?
               "":a[0].toUpperCase() + a.substring(1);

    }

    function showHitCount( numberOfHits ) {
            var div = document.getElementById( "_hitcount_" );
            if ( null != div )
                div.innerHTML = ("Total hits: " + numberOfHits).italics();
    }

    // build xpath query url
    function createXPathQuery( userString ) {

            var xpathTerms = [];

            var querySemantics = " and ";

            // trim leading & trailing spaces off query
            var terms = userString.replace(/^\s+/,"").replace(/\s+$/,"");

            // split on whitespace
            terms = terms.split(/\s+/);

            var _queryBasis =  "//*[_#_]/@location";
            var mode = getSearchMode( );

            for ( var i = 0; i < terms.length; i++ )
                xpathTerms.push( "jcr:contains(@" + mode + ",'" + terms[i] + "')" );

            var query = _queryBasis.replace( '_#_', xpathTerms.join( querySemantics ) );

            return query;
    }

    </script>
    </head>


    <body onload="addEventListeners()">

    <iframe width="380" height="410" style="border:none" src="http://localhost:7402/content/films/wild_at_heart.html"></iframe>

    <span style="font-size:small;position:absolute;right:80px;top:7px;">
    <input type="text"     id="_Query_" size="25"/>
    <input type="button"   id="_QueryButton_" value="Search Films by:"/>

    <select id="_Select_">
    <option value="Title">Title</option>
    <option value="Director">Director</option>
    <option value="Actor">Actor</option>
    <option value="Actress">Actress</option>
    <option value="Year">Year</option>
    <option value="Subject">Genre</option>
    </select>
    <br/>

    <select id="_Hits_" size="10"></select><div id="_hitcount_"></div>
    <br/>
    <input type="button" id="_Fetch_" value="Show Details"/>


    </span>
    <div id="hitlist"></div>
    </body>
    </html>
     

    This form (movieForm.html), along with the data for 1700 films (and scripts and PDF files discussed in prior posts), is available in the zip file below, which can also be downloaded from Day Package Share. After installing the package, go to http://localhost:7402/apps/films/movieForm.html to see the form in action (assuming your CRX is on port 7402).

    * MovieApp-1.zip
    Sample code and data for MovieApp.

    Posted by Kas Thomas JUL 12, 2010

    Posted in ajax, crx, crx gems, development, http, javascript and sling Add comment

    Not long ago, I wrote about possible ways to get interaction to happen between Adobe Acrobat and Day CRX, and I gave an example of how to use a PDF form to push content into CRX. That's the simplest way to get content into the repository using Acrobat, but it's certainly not the only way. As it turns out, Acrobat's JavaScript API supports more sophisticated AJAX-style asynchronous communication back and forth between Acrobat and a host. That's what I'd like to talk about now.

    There are some important differences between what I'll call Acrobat AJAX and ordinary (browser) AJAX. The most important difference is that with Acrobat (and here, I'm talking about Acrobat Professional, not Acrobat Reader; unlike my last blog, everything we're going to talk about today requires a full copy of Acrobat), your AJAX scripts are scoped to the application (that is, Acrobat itself) rather than to the document, and in fact your script(s) can only run outside of document scope: the relevant API methods are prevented (by security restrictions) from executing as part of a document. So you can't just attach scripts to a PDF document's form fields, say, and expect to do AJAX. Instead, you have to put scripts in a /Javascripts folder on your local drive, under your /Acrobat install path. Acrobat registers the scripts on program startup, and they remain in scope for the duration of an Acrobat session (regardless of how many documents you open). In this sense, you can think of an Acrobat AJAX script as being similar to, say, a Jetpack script in Firefox.

    You may be wondering what, then, is the user gesture for getting a so-called folder-level script to fire? In Acrobat, the standard pattern here is to expose a folder-level script as a new menu item. The Acrobat JavaScript API has a method, app.addMenuItem, that looks like this:

    app.addMenuItem({

       cName: "Save Annotations to CRX",
       cParent: "File",
           nPos: 0
       cExec: 'myMethod();',
       cEnable: "event.rc = (event.target != null);",
    });

    The method takes a parameter block that can have several (mostly optional) properties. The cName property is the name of the new menu item. The cParent property designates the Acrobat menu in which the new menu item should live (in this case, the File menu), while nPos indicates the desired position of the new menu command in the list of commands on the menu in question. The cExec property points to the custom code you want to execute when the menu item is selected by the user.

    The optional cEnable property lets you specify whether the new menu item is enabled when the user sees it, based on certain conditions. In the example shown above, we've got code that essentially tests whether a document is already open in Acrobat. If no document is open, the menu command is greyed out.

    In ordinary (browser) AJAX, you're no doubt accustomed to using the XMLHttpRequest object to do the heavy lifting. Acrobat has its own XHR construct, called Net.HTTP.request. Like the addMenuItem() method above, the request() method of Net.HTTP takes a parameter block as an argument. There are many possible properties you can supply on this parameter block object (and they're all documented in the JavaScript for Acrobat API Reference). For our purposes, the most important are cVerb (which can be "GET", "POST", or any number of other HTTP and/or WebDAV verbs), cURL (the URL to which the request should be sent), aHeaders (a place to specify the HTTP request headers for this transmission), oRequest (the data stream for the POST), and the all-important oHandler. The latter needs to point to an object (any object) that has a response() method. The response() method of the object is called when the server is done handling your request. In other words, it's your callback method, analogous to onreadystatechange in conventional AJAX.

    When the response method of your handler is called, it gets called with four arguments. The first argument is a reference to the response body (a stream object). The second argument is just the URL to which the request was sent. The third argument points to an exception object (if the request was not successful). The fourth argument is an array of response headers returned from the server. Again, all of this is documented in Adobe's JavaScript for Acrobat API Reference and I won't belabor any of it further here.

    The code below shows an example of what you can do using Acrobat AJAX. In this example, we harvest all of the annotations (if any) in the currently open PDF document (the frontmost document, if there are multiple docs open), convert those annotations to XML, and POST the XML to CRX at a location of http://localhost:7402/content/acrobat/annots/, under a node name of "Annots for [PDFname]" (where PDFname is the file name of the PDF document from which annotations were taken).

    AjaxRequest = function(cURL) {
            this.params =
            {
                    cVerb: "POST", // default
                    cURL: cURL,
                    aHeaders: [
                    { name: "Content-Type",
                            value: "application/x-www-form-urlencoded"
                    }
                    ],

                    oRequest: null,

                    oHandler:
                    {
                            response: function(msg, uri, e,h){
                                    var stream = msg;
                                    var string = "";
                                    string = SOAP.stringFromStream( stream );
                                    app.alert( string );
                            }
                    }
            };

            this.invoke = function( ) {

                    Net.HTTP.request(this.params);
            }
    }

    // Prepare an AjaxRequest
    function createRequest( annots, fileName, url ) {

            var ajax = new AjaxRequest( );

            // where to store data in CRX:
            ajax.params.cURL = url;

            ajax.params.cVerb = "POST";

            var data = {};

            // optional redirect:
            data[":redirect"] =
            "http://localhost:7402/content/acrobat/thankyou.txt";

            // this is the name of the new node
            data[":nameHint"] = "Annots for " + fileName;

            // this is our annotation data as XML
            data.data = getAnnotationsAsXML( annots );

            var dataString = createDataString( data );

            // convert our data to a stream object
            ajax.params.oRequest =
            Net.streamFromString( dataString );

            return ajax;
    }

    // create a string of the form
    // name1=value1&name2=value2 [etc]
    function createDataString( object ) {

            var data = [];
            for ( var i in object )
            data.push( i + "=" + object[ i ].toString( ) );

            return data.join( "&" );
    }

    // converts annots to XML using E4X
    function getAnnotationsAsXML( annots ) {

            var xmlOutput = <annots></annots>;
            for ( var i = 0; i < annots.length; i++ )
            {
                    var props = annots[i].getProps();
                    xmlOutput.* += <annot/>;
                    var parent = xmlOutput.annot[i];
                    parent.* = <author>{props.author}</author>;
                    parent.* += <contents>{props.contents}</contents>;
                    parent.* += <page>{props.page}</page>;
                    parent.* += <creationDate>{props.creationDate}</creationDate>;
                    parent.* += <type>{props.type}</type>;
            }

            return xmlOutput.toXMLString();
    }


    var theURL = "http://localhost:7402/content/acrobat/annots/";

    // Add a new menu item under File
    app.addMenuItem({
            cName: "Save Annotations to CRX",
            cParent: "File",
            cExec: 'request = createRequest( this.getAnnots( ), this.documentFileName, theURL ); request.invoke();',
            cEnable: "event.rc = (event.target != null);",
            nPos: 0
    });
     

    If you have a copy of Acrobat Professional, copy and paste the above code to a text file (with an extension of .js) in your /Javascripts folder under your /Acrobat path, then restart Acrobat and you should see a new menu command appear under the File menu, called "Save Annotations to CRX."

    Note that to prevent security errors, you may have to go into Preferences (Control-K) and turn off Enhanced Security, or else add the currently open PDF document to the list of trusted docs. (In the preferences dialog, choose Security (Enhanced) in the list on the left.)

    Acrobat's JavaScript API makes it trivially easy to harvest all annotations from a PDF document with a single line of code:

    this.getAnnots()

    What you get back from this call is an array of Annotation objects (see Adobe's documentation), each of which has numerous properties that can be parsed out. We convert the annotations and properties to XML in the following method:

    // converts annots to XML using E4X

    function getAnnotationsAsXML( annots ) {

            var xmlOutput = <annots></annots>;
            for ( var i = 0; i < annots.length; i++ )
            {
                    var props =     annots[i].getProps();
                    xmlOutput.* += <annot/>;
                    var parent = xmlOutput.annot[i];
                    parent.* = <author>{props.author}</author>;
                    parent.* += <contents>{props.contents}</contents>;
                    parent.* += <page>{props.page}</page>;
                    parent.* += <creationDate>{props.creationDate}</creationDate>;
                    parent.* += <type>{props.type}</type>;
            }

            return xmlOutput.toXMLString();
    }

    You'll notice we use E4X syntax here for building the XML. If you're not familiar with it, E4X (ECMAScript extensions for XML, otherwise known as ECMA-357) constitutes a powerful -- and quite handy -- syntax for manipulating XML in ECMAScript. It is supported not only in Acrobat JavaScript but (on the server side) in Sling as well.

    When I ran this script on an annotated PDF document of my own, I got XML that looked like this:

    <annots>
      <annot>
        <author>Admin</author>
        <contents>Need more discussion of "privileges"</contents>
        <page>31</page>
        <creationDate>Mon Jul 12 2010 08:03:17 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Underline</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>Not sure we need to have this sentence.</contents>
        <page>29</page>
        <creationDate>Mon Jul 12 2010 08:02:39 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Highlight</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>Is this the correct copyright date?</contents>
        <page>1</page>
        <creationDate>Mon Jul 12 2010 08:01:44 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Highlight</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>We need to strike this.</contents>
        <page>729</page>
        <creationDate>Tue Jul 06 2010 14:43:57 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Highlight</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>I am underlining this.</contents>
        <page>729</page>
        <creationDate>Tue Jul 06 2010 14:44:12 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Underline</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>I liked this.</contents>
        <page>57</page>
        <creationDate>Tue Jul 06 2010 15:04:21 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Highlight</type>
      </annot>
      <annot>
        <author>Admin</author>
        <contents>This does not seem right.</contents>
        <page>57</page>
        <creationDate>Tue Jul 06 2010 15:04:32 GMT-0400 (Eastern Daylight Time)</creationDate>
        <type>Text</type>
      </annot>
    </annots>

     

    This is what gets stored in CRX.

    A while ago, I said that AJAX scripts in Acrobat are scoped to the application and may not (for security reasons) run in the context of a given document. Given that this is so, you may be wondering, at this point, how it is that we can harvest annotations from a document programmatically in an AJAX script. The key is that our script doesn't fire until there's actually a document open in Acrobat (remember, the menu command is dimmed out if there's no PDF open). When the script does finally run, it's safe to call this.getAnnots() -- "this" will be a reference to the currently open document (and using it has no security side-effects). The only real restriction is that you can't call Net.HTTP.request() from a document-level script. Doing so will cause Acrobat to complain.

    Those are the basics of doing AJAX against a CRX repository from Acrobat. In a future blog, I'll show how to populate a PDF form with values slurped from CRX (and do it in a way that allows you to use Acrobat Reader rather than Acrobat Professional). Stay tuned!

    Posted by Michael Marth JUN 18, 2008

    Posted in ajax, announcements, jcr, jsr-170, jsr-283 and rest Add comment

    The large international Java conference Jazoon is soon to start. Jazoon takes place end of June in Zurich, Switzerland. There will be six presentations given by speakers from Day. Hope to see you there:

    Roy Fielding: Open Architecture

    Keynote speech, Wednesday, 2008/06/25, 09:30-10:30, Arena 5

    At the heart of most successful open source projects is an emphasis on open architecture -- at least one mechanism that allows the product to be utilized as a support network for unanticipated extensions and independently motivated functionality. Such extensibility mechanisms allow an open source project to decentralize its evolution and take advantage of Internet-scale collaboration. However, they can also be a source for unnecessary complexity and hidden barriers to entry.

    Representational State Transfer (REST) is an architectural style that I developed to describe and redefine the World Wide Web. The essential constraints of REST are designed to promote the development of open architectures within Web-based applications, such that the resulting resources are reusable across independently developed systems (today, we call these "MashUps"). The same principles can be used to design other open architectures, though not necessarily with the same constraints. This talk will focus on applying principled design techniques to the design of open architectures, as demonstrated by various examples from successful open source projects.

    Peeter Piegaze: The Next Content Repository: A sneak peek at the upcoming JCR 2.0

    Technical long talk 50 min, Wednesday, 2008/06/25, 12:00 - 12:50, Arena 9

    The Story So Far

    • JCR 1.0 a quick recap
    • JCR 1.0 successes
    • JCR 1.0 lessons learned
    Goals of JCR 2.0
    • Expose new functionality for JCR-from-scratch repositories
    • Better expose functions of existing legacy repositories through JCR
    • Simplify complex features
    Major Features and Changes
    Node Identifiers
    • More flexible constraints
    Metadata
    • Standardizing metadata node types
    Observation
    • Two semantic levels of event reporting: state-change and method
    • Journaling
    Simplified Versioning
    • Simple and full versioning options
    Shareable Nodes
    • enabling multi-filing without breaking the workspace tree semantics
    Query
    • Abstract Query Model allows multiple equivalent syntaxes
    • Java bindings and SQL bindings
    • XPath bindings and more
    Node Type Management
    • Creating and registering node types
    Access control management
    • Access control discovery
    • Access control policies
    • Access control entries

    Lars Trieloff: Creating RESTful Web Applications with AJAX and Web Forms 2.0

    Technical long talk 50 min, Wednesday, 2008/06/25, 16:30 - 17:20, Arena 5

    The talk will have following structure: Introduce the concepts REST, AJAX and Web Forms 2.0 first, then provide hands-on-examples on building applications using these concepts. REST is a principle of creating large-scale internet applications and is seen by many developers as the way to go for creating web applications. The problem with real-world REST application however is that current web browsers only implement a subset of the HTTP specification that makes it hard to create true RESTful applications that work in a web browser. AJAX is a way of creating highly dynamic web applications that use Javascript and client-side DOM manipulations for interaction with the user and background HTTP request in XML or JSON for real-time-interaction with the browser. Combining AJAX and REST allows the creation of rich internet applications running in the browser that follow the REST principles. Web Forms 2.0 is an emerging web standard that tries to overcome some limitations with classical forms in HTML pages that are today the standard way of user interaction in web applications. Web Forms 2.0 add concepts like form field repetition, different transport encodings and validation. As long as only a small fraction of web browsers support Web Forms 2.0, implementing Web Forms 2.0 with AJAX is an elegant solution for creating standards-based web applications. In the practical part of the presentation concrete coding examples of creating RESTful web applications using Web Forms 2.0 will be given. The frameworks involved in this example session will be Apache Sling, a web-framework that combines concepts of REST, server-side scripting, OSGi and JCR and the Dojo Toolkit, a powerful collection of Javascript APIs that allow the creation of widget-based applications that run in a web browser. Apache Sling is an incubating project of the Apache Software Foundation.

    David Nüscheler: Content Integration: Java(tm) Applications vs. Microsoft(R) Sharepoint

    Technical long talk 50 min, Wednesday, 2008/06/25, 17:30 - 18:20, Arena 9

    Most large organizations on the one hand develop Java(tm) Applications and on the other hand run Microsoft(R) Sharepoint for their business users.

    This generates the crucial need for Java Applications to be able to interact with content stored in Sharepoint, be it a Java based Swing Application that would like to refer to content managed by Sharepoint or a regular Intranet WebApp or Java Portlet that needs to search and manage office content residing in Sharepoint.

    This session will talk about the benefits and drawbacks of various ways of integrating Java applications and Sharepoint.

    This session will also demo and showcase the integration of both J2SE and J2EE applications through a quick and easy to use standards based integration.

    The goal of this session is to demonstrate in a practical fashion how to integrate with Microsoft Sharepoint at a Content Repository level using a "Content Repository API for Java(tm) Technology" (aka JSR-170) connector to build a Java application in a very agile fashion.

    Expect a hands-on demo of the installation and deployment of a JSR-170 based Sharepoint Connector and the development of a simple JSR-170 based application and the use of an existing JSR-170 based application backed by content from Microsoft Sharepoint.

    Agenda:
    (1) Content Integration: A Business Issue
    (2) Java vs. Microsoft Sharepoint
    (3) Various Integration Options Pro/Cons
    (4) Integration Demo using the "Content Repository API for Java(tm) Technology"
    (5) Q&A

    David Nüscheler and Bertrand Delacrétaz: The Revenge of the "Weblog in 15 minutes"

    Technical long talk 50 min, Thursday, 2008/06/26, 12:00 - 12:50, Arena 5

    Based on last years successful Jazoon session on how to build a "Weblog in 15 minutes" using AJAX and JCR, this talk is the sequel in the "AJAX meets JCR" series.

    In the meantime microjax has become a legitimate part of the Apache Sling project which is at the time of this submission in incubation.

    This talk will focus on the unique benefits of using a combination of AJAX and JCR (aka. JSR-170 & JSR-283) to satisfy modern Web 2.0 application requirements and allow for an extremely agile application development.

    To take last years "15-minute weblog" example to the next level we will talk about how microjax effortlessly complies with the real-life requirements of Search Engine Optimization (SEO), Back-button, Deep Links, WAI, Access Control, XSS protection, etc...

    This session will be interesting for an audience that works in a general J2EE environment and is eager to learn how to build Web2.0 Applications in a very efficient way without leaving the traditional heavy-weight j2ee style backend resources.

    The session overview looks as follows:

    (1) The JCR elevator pitch
    (2) microsling - JCR and AJAX
    (3) The revenge of the microjax "weblog"
    (4) The real-life: SEO, WAI, Backbutton, XSS, Access Control
    (5) Q&A

    Thomas Mueller: Java SQL Databases

    Technical short talk 20 min, Thursday, 2008/06/26, 11:00 - 11:20, Arena 3

    This talk is about what persistence mechanism to chose for your Java application, and what to consider when you decided to use a SQL database as your backend. The focus of this presentation is open source Java databases. One of those, the H2 Database Engine, is developed by the speaker.

    The API is one aspect of the persistence mechanism. Standardized high level APIs are the JPA (Java Persistence API), the JDBC API (Java Database Connectivity), and the JCR (Java Content Repository) API. Each API has advantages and disadvantages. Other APIs exist as well, but are less used (such as JDO) or are proprietary. Proprietary APIs will result in substantial cost when switching to another product to overcome the vendor lock-in (for example when using db4o).

    If you have decided to use a SQL database as the backend, you need to think about which products fit your use case best. The main factors factors to consider are: cost, stability, security, features, performance, ease-of-use, support, and documentation. Sometimes, you will want to support multiple products: one for development and unit testing, and another (or multiple) for production.

    If you already purchased a SQL database, for example Oracle or MS SQL Server, you may want to use it for production. If not, the cost of such products can be avoided by using free databases like PostgreSQL, or MySQL (which is not free in all cases). There is also a number of Java databases, most of them are free.

    Some think that Java still is slow, and a fast database can not be written in Java. However Java is no longer slow. Additionally, there is no network overhead when accessing Java databases from Java applications in embedded mode. Therefore, Java databases are much faster than other database in many situations.

    The main open source Java databases today are HSQLDB, Apache Derby, and H2. There are other Java databases, but some are not free (PointBase), and others not updated since a long time (McKoi, DaffodilDb/One$Db, Quadcap). HSQLDB, Derby and H2 are quite different. According to Ohloh, HSQLDB is the most popular one, followed by Derby and H2. The reason is probably that HSQLDB is the open source since a long time, Derby since 2004, and H2 since the end of 2005.

    HSQLDB is based on Hypersonic SQL, which was developed by the author of H2. It is now maintained by a group of people headed by Fred Toussi in England. A commercial version of HSQLDB is available as well. HSQLDB is popular because of its speed. However it does lack a few features such as locking and transaction isolation. HSQLDB is bundled with OpenOffice Base. Many use HSQLDB for testing. However, more complex queries can be very slow in HSQLDB because the query optimizer does not consider different access strategies. There is no ODBC driver for HSQLDB.

    The history of Apache Derby goes back to 1996. Cloudscape was bought by Informix in 1999, which was bought by IBM in 2001, and then contributed to Apache in 2004. IBM stopped selling Cloudscape in 2007 and will stop support in September 2008. However most Derby developers are employed by IBM. Sun offers commercial support for Java Db, which is basically Derby. Since 2007 IBM owns PointBase, the second commercial Java database. Derby offers a rich feature set. The optimizer usually chooses a good query plan. The main disadvantage is the slow performance for simple use cases (up to 10 times slower than HSQLDB or H2).

    The development of H2 was started in 2004, but it was first published in December 2005. The author of H2, Thomas Mueller, is also the original developer of Hypersonic SQL. In 2001, he joined PointBase Inc. where he wrote PointBase Micro. At that point, he had to discontinue Hypersonic SQL, but then the HSQLDB Group was formed to continued to work on the Hypersonic SQL codebase. The name H2 stands for Hypersonic 2; however H2 is built from scratch. H2 is feature rich and fast. The main disadvantages are: it is relatively new, and there is no commercial support as of today.

    Posted by Lars Trieloff MAY 14, 2008

    Posted in ajax, jcr, osgi, rest and sling Add comment

    I presented yesterday at the Henry Stewart DAM Show in New York. My presentation explained that JCR as a standard is important for Digital Asset Management because you want to re-use your digital assets in other content-centric applications such as web content management, collaboration or document management, turning your requirement for a digital asset management system into an application platform for asset centric applications.

    I then explained the basic concepts behind JCR, REST, AJAX and OSGi, that all together form Sling, the fifth way of creating asset centric applications. For implementors of asset centric applications Communiqué DAM offers a big head start, because it offers you an user-friendly asset management interface, asset transformation and export services and defined API and data model for your application out of the box. Furthermore you can use our connectors to JCR-enable existing content repositories such as Microsoft Sharepoint or Vignette.

    As always, find the slides on slideshare…