Latest Posts

Archives [+]

Categories [+]

Authors [+]

Entries filed under 'jsr-283'

    Posted by Michael Marth JUL 02, 2010

    Posted in jcr, jsr-170 and jsr-283 Comment 1

    One particular strength of Java Content Repositories is that they provide so much infrastructure for developing content centric applications. Today, I discovered another hidden gem in JCR2 (JSR-283) that can come in very handy for app development:

    In JCR1 the class ObservationManager used to manage EventListeners that get triggered immediately when an event like a property change occurs. Starting from JCR2 the ObservationManager also provides an EventJournal for each node that can be retrieved without having to register a listener first. The EventJournal is a list of events, e.g. addition, moves or removal(!) of child nodes, complete with user id and timestamp.

    Attached to this post is a little CRX package with a servlet that renders the events for a given node. The relevant lines are:

    ObservationManager om = session.getWorkspace().getObservationManager();
    EventJournal eventJournal = om.getEventJournal(
        Event.NODE_ADDED | Event.NODE_MOVED | Event.NODE_REMOVED  | Event.PROPERTY_CHANGED
        | Event.PROPERTY_REMOVED | Event.PROPERTY_ADDED, path, false, null, null);

    Install the package and point your browser to http://localhost:7402/apps/eventy.html?path=/content (the path parameter specifies the node you are interested in). You should see a list of entries like:

    Event: Path: /content/n3, NodeAdded: , UserId: admin, Timestamp: 1272975189833, UserData: null, Info: {}
    Event: Path: /content/n3, NodeRemoved: , UserId: admin, Timestamp: 1272975212725, UserData: null, Info: {}
    ...

    And from the Javadoc:

    Events returned in the EventJournal instance will be filtered according to [...] the current session's access restrictions

    I am delighted.

    * eventjournal-1.0.zip
    CRX package: sample for EventJournal

    Posted by Kas Thomas JUN 30, 2010

    Posted in crx, crx gems, development, java content repository, jcr, jsr-283, package and sling Comments 3

    Bookmarks have their place, but sometimes what you'd really like to be able to do is save actual snippets of content from a given web page rather than just keep a reference to the page's URL in your Bookmarks menu. Saving the whole page is easy, but usually impractical, because usually you're not interested in saving all the text (and photos and advertisements, etc.) on a page. Usually you're just interested in a particular span of text (a code snippet, or a particular paragraph, or a list of links) and nothing more. There ought to be an easy way to cache just the portion of the page that interests you. And there is -- if you have Day CRX and Google's Chrome browser.

    It turns out that with only around 200 lines of JavaScript, you can modify Chrome's behavior so that when you make a text selection (or in fact any selection) on a web page, a button appears on the page, and when you click the button, your selection is saved to your Sling repository. (In this case, we're using CRX instead of Sling per se, but the same code should work with either one.)

    The following code (stored in a file called clip2crx.user.js) shows how it's done. Note that the code is formatted as a Greasemonkey script (but has no Greasemonkey dependencies). It turns out that Chrome version 4-and-up supports Greasemonkey scripts: All you have to do to load such a script (assuming its name ends in ".user.js") is Open the script in Chrome and say yes to the "Are you sure you want to install this script?" warning that appears. No need to restart Chrome. Once the script is loaded, simply go to any web page and make a selection on the page (by click-dragging the mouse). When you let your finger off the mouse, a "Save Selection" button will appear in the lower right corner of the window. Click that button. A small dialog will pop up, asking you to give the selection a name. After supplying a name, click OK and the selection is saved to CRX.

    // ==UserScript==
    // @name           clip2crx
    // @namespace      clip2crx
    // @description    Save user-selected items in web page to a CRX node
    // @include        *
    // ==/UserScript==

    // Kas Thomas <kas.thomas@day.com>
    // 28 June 2010
    // Tested in Google Chrome 5.0.375.70 beta

    // *************************** Button ******************************
    // This is the "Save Selection" button (sans event handlers).

        Button = new function( ) {    // Button is a singleton object

            var _ID = "SAVESELECTION";
            var _domNode =
                createFixedPositionNode( "div", _ID, 50, 10,
                '<input type="button" value="Save Selection..." />' );
       
            this.getDomNode = function ( ) { return _domNode; }
       
            function createFixedPositionNode( nodeName, id, x, y, innerhtml ) {
           
                var node  =  document.createElement( nodeName );
                var style = 'position: fixed; ';
                style +=    'bottom: ' + y + 'px; ';
                style +=    'right: ' + x + 'px; ';
                style +=    'z-index:100; ';
                style +=    'font-size: small;';
                node.setAttribute( "style", style );
                node.setAttribute( "id", id );
                node.innerHTML = innerhtml;
           
                return node;
            }

                // This will add the Button to the page
            this.attach = function ( doc ) {
       
                if ( !nodeExists( doc, _ID ) )
                    doc.body.insertBefore( _domNode , doc.body.firstChild );
            }

            // This removes the Button from the page
            this.detach = function ( doc ) {
       
                if ( nodeExists( doc, _ID ) )
                    _domNode = doc.body.removeChild( _domNode );
            }

            function nodeExists( doc, id ) {
       
                return doc.getElementById( id ) != null;
            }

            };  // Button


        // called by buttonHandler( ) further below...
        function saveToRepository() {

                // Repository storage URL
                var base_url  = "http://localhost:7402/content/myapp/";
               
            // Obtain the content we want to post
                var params = "content=" + getContent( );

                // prompt the user to give the new node a name
                var name = prompt( "Name for this entry:" );
                if ( !name || name.length == 0 )
                    throw "No name provided.";

            params += "&:nameHint=" + name;

                // Prepare for AJAX POST
                http = new XMLHttpRequest( );
                http.open( "POST", base_url, true );

                // Send the proper header information along with the request
                http.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
                http.setRequestHeader( "Content-length", params.length );
                http.setRequestHeader( "Connection", "close" );

                // Show whether we succeeded...
                http.onreadystatechange = function( ) {
                        if ( http.readyState == 4 )
                     ;// alert( "http.status = " + http.status ); DEBUG ONLY
                }

                // do the AJAX POST
                http.send( params );
            }


        function getContent() {

            var selection = window.getSelection( );
            var markup = serializeSelection( selection );  
            var finalMarkup = formatPage( markup );
            return finalMarkup;
        }


        function formatPage( pageContent ) {

            return "<br>" + fixRelativeURLs( pageContent );
            }

        // Try to expand relative URLs to absolute paths
        // so they'll continue to work when viewed from CRX
            function fixRelativeURLs( text ) {
         
                var url = window.parent.location.href;
                var lastSlash = url.lastIndexOf("/");
                var basisURL = url.substring( 0, lastSlash );

                function convertURL( hit, offset, text ) {

                    var output = hit;

                    if ( text[ offset + hit.length ] == "/"  )
                        output += window.parent.location.protocol +
                            "//" + window.parent.location.host;
     
                    else if ( text[ offset + hit.length ].match( /\w|#|\./) != null )
                            output += basisURL + "/";

                    return output; // all other cases, nop
                }

            var regex1 = /src="(?!http)/gi;
                var regex2 = /href="(?!http)/gi;
                var newText =
                    text.replace( regex1, convertURL ).replace( regex2, convertURL );

                return newText;
            }


        function serializeSelection( selection ) {

                var xmlFragment = "";
                try {
                  var n = 0, ranges = selection.rangeCount;
                  while ( n != ranges ) {
                        var range = selection.getRangeAt( n++ );
                        var content = range.cloneContents( );
                        var serializer = new XMLSerializer( );
                        xmlFragment += serializer.serializeToString( content );
                    }
                }
                catch( msg ) { }

                return xmlFragment;
            }

    // ******************************** main( ) ********************************

    ( function main( ) {

        // Button mouseup handler
        function buttonHandler( e ) {

            Button.detach( document );      
          saveToRepository();      
        }
       
        // document.body mouseUpHandler
        function mouseUpHandler( e ) {

            var selection = window.getSelection( );

            if ( selection.toString( ).length > 0 ) { // a selection exists        
                Button.attach( document );          
            }
            else  
                Button.detach( document );
             
        }

        function clickHandler( e ) {  // need to handle page clicks too, because
                                      // if user clicks inside a selection,
                                      // browser eats the mouseup event...    
            mouseUpHandler( e );
        }

        // now add event handlers to the page...
        addEventListener( "mouseup", mouseUpHandler, false );
        addEventListener( "click", clickHandler, false );

        // add event handler to the Button...
        Button.getDomNode( ).addEventListener( "mouseup", buttonHandler, false );
       
    }) ( );   // end main( )
     
     

    There are several things to note.

    By default, selections are stored in CRX at a URL of:

       http://localhost:7402/content/myapp/[name]

    where name is the item name you provided in the popup dialog. The name is provided to CRX as a :nameHint parameter value in the POST data. This ensures that the item gets stored with the name you want (rather than an autogenerated number created by Sling) while also ensuring that the name is normalized to a legal form (with non-alphanumeric characters converted to underscores). The fact that it is stored under /content/ means that Sling will look for application scripts to run against your content, under http://localhost:7402/apps. In this example we're not using any such scripts, but it would be easy to add some.

    Content gets stored in CRX with all markup intact, so that when you decide to view the snippet later, it will have more or less than same appearance that it had on the original web page from which it was taken. Also note that, thanks to a function called fixRelativeURLs(), any relative URLs in the saved selection are expanded to full-path form before content is moved into the repository. That way, embedded links should still work properly when you view the stored snippet later even though its root URL has changed.

    The rest of the code is fairly self-explanatory.

    To obtain your own ready-to-run copy of clip2crx.user.js, check out the package stored here.

     

    Posted by Jukka Zitting JUN 04, 2010

    Posted in crx, crx gems, jackrabbit, jcr and jsr-283 Comments 6

    The J2EE Connector Architecture (JCA) is a mechanism by which applications can access all kinds of information systems in a controlled and coordinated manner. The JCA support included in application servers like Weblogic and JBoss takes care of managing things like connections, transactions and connection security on behalf of a client application. To do this, the application server leverages a JCA connector for the information system being accessed.

    JCA is quite useful in many environments with complex integration requirements, so thanks to a community contribution, the Apache Jackrabbit project has been shipping a JCA connector since the 1.0 release. However, the Jackrabbit JCA connector was originally designed to run the Jackrabbit repository in embedded mode within the connector itself, only providing standard JCR API access to client applications. This made the connector design unsuitable for repositories like CRX that include a full suite of web-based management and editing tools that need access to repository internals. We worked around this issue with custom solutions for some CRX 1.x customers, but an improved JCA connector design was clearly needed.

    Instead of implementing something for just CRX, we wanted to make a generic JCA connector for all JCR implementations and release it as open source. This way we'll return the favor to the community that contributed the original JCA connector code and will benefit from any improvements and fixes by the external contributors.

    To improve the connector design, we turned to the RepositoryFactory interface introduced in JCR 2.0 and the Repository URI work we had done earlier. With these tools we could turn the existing Jackrabbit JCA connector from a Jackrabbit-specific tool to one that supports all JCR 2.0 implementations. This work was tracked in JCR-2555 and released as a part of Jackrabbit 2.1.0. You can find the resulting JCA resource archive (rar) file on the Jackrabbit download page.

    To use the JCA connector with CRX on for example the JBoss application server, you first need install the CRX webapp following the normal installation documentation. Then deploy the Jackrabbit JCA rar file without modifications. Finally, as the last step you only need to connect these two resources together by deploying a connection factory descriptor like the one shown below:

    <connection-factories>
      <tx-connection-factory>
        <jndi-name>jcr/crx</jndi-name>
        <xa-transaction/>
        <rar-name>jackrabbit-jca-2.1.0.rar</rar-name>
        <connection-definition>
          javax.jcr.Repository
        </connection-definition>
        <config-property name="repositoryURI"
          type="java.lang.String">
    jndi://?org.apache.jackrabbit.repository.jndi.name=crx
    &java.naming.factory.initial
    =com.day.util.jndi.provider.MemoryInitialContextFactory
    &java.naming.provider.url
    =http://jcr.day.com
        </config-property>
        <config-property name="bindSessionToTransaction"
          type="java.lang.Boolean">true</config-property>
      </tx-connection-factory>
    </connection-factories>

    NOTE: The repositoryURI configuration property has been split to multiple lines for display. It needs to be all in one one in an actual descriptor file.

    Set the jndi-name to the path under which you want the JCA-managed Repository instance to be available in the default JNDI context of the application server. Note also that you need to adjust the rar-name setting if you've deployed a different version of the Jackrabbit JCA rar file.

    The diagram below illustrates how these different components work together:

    /content/ddc/blog/2010/06/crx_gems_jca_connec/jcr:content/par/image/file

     

    When you need to replicate this setup over multiple application servers, you can even package these components together with your application inside an enterprise archive (ear) for simple deployment of your entire setup. But that's a topic for another post...

    Posted by Greg Klebus MAY 01, 2010

    Posted in announcements, cmis, crx, jcr and jsr-283 Comment 1

    I'm proud and excited to see Day CRX 2.1 generally available. This first standalone release of our enterprise content repository product implementing the new JCR 2 (JSR 283) standard, and enabled for the upcoming CMIS standard, is a milestone in Day Software content technology and product strategy. The first release of CRX 2 technology, CRX 2.0 engineering controlled release embedded in our CQ 5.3 product, has been shipping already since January 2010.

    Download the free developer edition of CRX for all your evaluation, development, and testing needs. Watch the product screencast on www.day.com/crx. Follow the First Steps with CRX guide to web application development on CRX platform. You will discover the product features in the matter of minutes. 

    Our enterprise customers and partners can download CRX from DayCare support platform. If you are interested in the enterprise license, contact our regional office. For smaller projects developed using the CRX developer edition, which need to go into production, you can order our competitively priced CRX ONE edition. Projects based on Apache Jackrabbit can also benefit from CRX enterprise or ONE edition's commercial offering & support thanks to drop-in compatibility with CRX.

    This release is the result of industry cooperation in defining the JCR 2 and CMIS standars, open source community providing the reference implementation of JCR and other modules used in CRX, and our customers, partners, and developer edition users providing us with valuable feedback and challenging enhancements requests. I'd like to thank you for this great cooperation on behalf of Day's highly motivated and qualified delivery team, who have made every effort to ensure it is a great product release.

    For more information, see Release Notes and product online documentation at docs.day.com, and knowledge base articles.

    Also, do not miss the upcoming events related to CRX 2.1:

    • Mark the date for the CRX 2.1 Launch Webinars on Thursday, May 6th, 2010: for Europe at 11 a.m. CEST and for US at 10 a.m. PT / 1 p.m. ET.
    • Participate in Day's IT Agility Cup development competition for developers of composite content applications, with categories including Innovative JCR Application, Innovative CMIS Application, and Innovative Mobile Application.

    Posted by Michael Marth APR 08, 2010

    Posted in cmis, jackrabbit, jcr, jsr-170 and jsr-283 Add comment

    The capability to expose a Java content repository through CMIS has been around for a while (see for example Day's announcement of a publicly available CMIS server). On the other hand, Apache Jackrabbit developer Michael Duerig has committed some code to the Jackrabbit sandbox that makes available a CMIS repository through JCR. Essentially, this allows you to connect to a CMIS repository and browse it with the JSR-170/283 API.

    Being in the sandbox, this is for the adventurous to try by themselves. But if you want to: check out https://svn.apache.org/repos/asf/jackrabbit/sandbox/jackrabbit-spi2cmis/. You will need to have Apache Chemistry and Apache Jackrabbit installed (i.e. available in the local mvn repository) in order to build. Michael has put together some instructions in a README.

    To understand how to use the code have a look at the test cases. In particular, in AbstractTestCase.java there are test setups for the public CMIS repositories of Day, Alfresco and Nuxeo.