ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Advanced Java Content Repository API
Pages: 1, 2

Observation

Observation allows you to monitor your content repository and to execute some business logic as soon as some persistent change is made. For example, let's suppose that this sample blogging application is used by your company for corporate blogging, and every employee gets a blogging account. Now imagine the legal department of your company wants an email sent to them as soon as each new blog entry is posted, just to check for any legal implications. Observation enables this feature.



You can find out if your repository implements observation by querying the repository descriptor table using repository.getDescriptor("OPTION_OBSERVATION_SUPPORTED"); this method call returns true if observation is supported, false otherwise.

Follow these steps to change your sample blogging application so that the event listener is notified as soon as a new blog entry is added; this version prints the new blog to the console rather than sending email.

  1. First, change JackrabbitPlugin.init() like this:

    public void init(ActionServlet actionServlet, ModuleConfig moduleConfig)
        throws ServletException {
        System.setProperty("org.apache.jackrabbit.repository.home",
                            "c:/temp/Blogging");
        Repository repository = new TransientRepository();
        session = repository.login(new SimpleCredentials("username",
                "password".toCharArray()));
        NodeEventListener nodeEventListener = new NodeEventListener();
        if (repository.getDescriptor(
            Repository.OPTION_OBSERVATION_SUPPORTED).equals("true")){
            ObservationManager observationManager =
                session.getWorkspace().getObservationManager();
        observationManager.addEventListener(nodeEventListener,
            Event.NODE_ADDED,"/",true,null,null,false);
        }
    }

    After getting a connection to the repository, we check whether this repository supports observation. If it does, get an ObservationManager by calling getObservationManager() on the workspace. Notice that observers operate at the workspace level, not the repository level.

    The ObservationManager class defines methods for registering and deregistering listeners. You can call ObservationManager.addEventListener() to register a new event listener. The first argument is an EventListener implementation, whose onEvent() will be called by the repository to notify it about events. The next argument is the event that you want to listen for; in our case, we are interested in a node added event. The third parameter is the path of the node that you're interested in. The fourth parameter is a flag that, if true, says that you're interested regardless of where the node is added in the child node hierarchy. The next two parameters are used for filtering events; the first parameter takes an array of UUIDs to indicate that you're only interested in events whose associated parent node has one of the UUIDs in this list. The next parameter takes an array of nodeTypes; if the value of this parameter is not null, then you'll be notified only if the associated parent node has one of the node types. The last parameter is a flag indicating whether you're interested in events that occur in the same node. If true, you won't be notified (not only of your own adds, but also when someone else adds a node in the same workspace).

  2. Now it's time to implement NodeEventListener:

    public class NodeEventListener implements EventListener {
     public void onEvent(EventIterator eventIterator) {
        while (eventIterator.hasNext()) {
            Event event = eventIterator.nextEvent();
            String eventPath = event.getPath();
            int eventType = event.getType();
            if (eventType == Event.NODE_ADDED) {
                String nodePath = eventPath.substring(1, eventPath.length());
                Session session = JackrabbitPlugin.getSession();
                Node blogEntryNode = session.getRootNode().getNode(nodePath);
                if(blogEntryNode.getName().equals("blogEntry")){
                    _logger.debug("New blog entry is added by"
                        + blogEntryNode.getProperty(
                                JackrabbitBlogEntryDAO.PROP_BLOGAUTHOR)
                                .getString()
                        + ", titled "
                        + blogEntryNode.getProperty(
                                JackrabbitBlogEntryDAO.PROP_TITLE)
                                .getString());
                }
            }
        }
    }

    When a persistent change occurs, the repository calls the onEvent() method of each registered listener that is entitled to receive notification, and passes it as an EventIterator object. The EventIterator contains the bundle of events (again, filtered for a particular listener) that describe the persistent changes made to the workspace. In our case, we are interested only when a new node is added, so EventIterator will have only one node added event. Once we have that event, we can get the path of the newly added node by calling the event.getPath() method. Use that path to search for the newly added node and print details in the logger.

Once you've built and deployed your code, try adding a new blogEntry: you will see that as soon as the Session.save() (or Item.save()) method is called, the onEvent() method of NodeEventListener will be called in a different thread and will dump details of the newly created node in the logfile.

Summary

In this article, we discussed two of the most useful advanced features defined in JSR-170. We talked about how to implement versioning and observation using JSR-170. Please take a look at the Apache Jackrabbit online documentation as well as the sample code for examples on how to develop your application using the locking and SQL Search optional features.

One of the most important factors for the success of any standardization effort is how much industry support exists for the effort. The best thing about JSR-170 is that it goes that extra distance to make this specification more adaptable. Due to its strategy of dividing core features in Level 1 and Level 2 compliance, it's easier for content repository vendors to start supporting it at whichever level makes the most sense to them. The second risk with specification is that if you don't define advanced features, then every vendor will start implementing it in its own way. JSR-170 does a fine job by defining these advanced features as optional, so if you decide to implement, you do so in a standardized way.

Take a look at JSR-170's expert group list, and you will find that it has already gained support from most of the CMS vendors such as Day Software, EMC Corporation, Filenet, Vignette, IBM, BEA, Oracle, and Sun Microsystems. Work has already begun on the next version of Java Content Repository API specification, version 2.0, under JSR 283. This specification will try to address a few more features that were not covered in JSR-170.

Resources

Sunil Patil has worked on J2EE technologies for more than five years. His areas of interest include object relational mapping tools, UI frameworks, and portals.


Return to ONJava.com.