All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.commons.jcr.JcrObservationThrottle Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*
 * Copyright 1997-2008 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.commons.jcr;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Used to wait until all queued observation events
 *  have been delivered, useful to throttle down
 *  operations that modify lots of nodes.
 */
public class JcrObservationThrottle implements EventListener {
    private final Node tempFolder;
    private Node tempNode;
    private final Logger log = LoggerFactory.getLogger(getClass());
    private int nodeCounter = 0;
    private int lastCounterSeen;
    
    /** Create a JcrObservationThrottle
     *  @param tempNodeFolder a node with a unique name
     *  is created in that folder to detect observation
     *  events.
     */
    public JcrObservationThrottle(Node tempNodeFolder) {
        tempFolder = tempNodeFolder;
    }
    
    /** Setup temporary node to detect events, must be called
     *  before {link #waitForEvents}
     */
    public void open() throws RepositoryException {
        tempNode = JcrUtil.createUniqueNode(
                tempFolder, getClass().getSimpleName(), 
                JcrConstants.NT_UNSTRUCTURED, tempFolder.getSession());
        
        final int eventTypes = Event.NODE_ADDED;
        final boolean isDeep = true;
        final boolean noLocal = false;
        tempFolder.getSession().getWorkspace().getObservationManager().addEventListener(
                        this, eventTypes, tempNode.getPath(), isDeep, null, null, noLocal);
        log.debug("Temporary node {} created, observation setup", tempNode.getPath());
    }
    
    /** MUST be called to clean up, DELETES the temp folder
     *  node that was passed to constructor */
    public void close() {
        try {
            tempFolder.getSession().getWorkspace().getObservationManager().removeEventListener(this);
            tempFolder.remove();
            tempFolder.getSession().save();
        } catch(RepositoryException re) {
            log.warn("RepositoryException in close()", re);
        }
        tempNode = null;
    }

    public void onEvent(EventIterator events) {
        while(events.hasNext()) {
            final Event e = events.nextEvent();
            // If last part of path is a number, we got the ADDED event
            // of a node that we just created
            try {
                final String [] path = e.getPath().split("/");
                final String last = path[path.length - 1];
                try {
                    int i = Integer.valueOf(last);
                    synchronized (this) {
                        lastCounterSeen = i;
                        notify();
                    }
                    log.debug("Got event {}, notified", lastCounterSeen);
                } catch(NumberFormatException ignore) {
                }
            } catch(Exception ex) {
                log.warn("Exception in onEvent", ex);
            }
        }
    }
    
    /** Block until all pending observation events have been delivered.
     *  As JCR events are delivered in order of their creation, simply
     *  creates a new temp node and waits for the corresponding event to
     *  be delivered.
     *  Note that the Session of the temporary folder node passed to the
     *  constructor is saved by this method, in order to create temporary
     *  nodes and detect their observation events.
     *  @return the elapsed time in msec for this method call.
     */
    public long waitForEvents() throws RepositoryException {
        final long start = System.currentTimeMillis();
        final int targetCounter = ++nodeCounter;
        final Node added = tempNode.addNode(String.valueOf(targetCounter), JcrConstants.NT_UNSTRUCTURED);
        tempNode.getSession().save();
        log.debug("Waiting for observation events on {}", added.getPath());
        try {
            while(lastCounterSeen < targetCounter) {
                synchronized (this) {
                        wait();
                }
            }
            log.debug("Got observation event {}", lastCounterSeen);
        } catch (InterruptedException e) {
            log.warn("InterruptedException in waitForEvents", e);
        }
        return System.currentTimeMillis() - start;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy