com.day.cq.commons.jcr.JcrObservationThrottle Maven / Gradle / Ivy
/*
* 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;
}
}