In the last posting I showed the benefits of Sling regarding resource access over plain JCR. But not only in resource access both frameworks offer similar functionality, but also in the important area of listening to changes in the repository. So today I want to compare JCR observation to Sling eventing.
JCR observation is a part of the JCR specification and is a very easy way to listen for changes in the repository.
@component (immediate=true, metatype=false)
@service
class Listener implements ObservationListener {
@Reference
SlingRepository repo;
Session session;
Logger log = LoggerFactory.getLogger (Listener.class);
@activate
protected void activate () {
try {
Session adminSession = repo.loginAdministrative(null);
session = adminSession.impersonate (new SimpleCredentials("author",new char[0]));
adminSession.logout();
adminSession = null;
session.getObservationManager.addEventListener( this, // listener
NODE_CREATED|NODE_DELETED|NODE_MOVED, // eventTypes
"/", // absPath
true, // isDeep
null, // uuid
null, //nodeTypeNames
true // noLocal
);
} catch (RepositoryException e) {
log.error ("Error while registering observation", e);
}
}
@deactivate
protected void deactivate() {
session.getObservationManager.removeListener(this);
session.logout();
session = null:
}
private handleEvents (Events events) {
while (events.hasNext()) {
Event e = events.next();
… // do here your event handling
}
}
}
In JCR the creation of an observation listener is straight forward, also the event listening. The observation process is tied to the lifetime of the session, which is started and stopped at activation/deactivation of this sling service. This kind of implementation is a common pattern.
Note: Be aware of the implications of using an admin session!
- You can read and write everywhere in the repository
- You work with elevated rights you probably never need.
So try to avoid an adminSession. In th example above is use a session owned by the user “author” for this via impersonation.
A sling implementation of the same could look like this:
@Component (immediate = true)
@Service()
@Property (name = "event.topics", value = "/org/apache/sling/api/resource/Resource/*")
class Listener implements EventHandler {
public void handleEvent (Event event) {
// handle
}
}
You see, that we don’t have to care about registering a listener and managing a session. Instead we just subscribe to some events emitted by the Sling Eventing framework. This framework is essentially implementing the OSGI event specification, and therefor you can also subscribing the very same way to various other event topics. You can check the “Event” tab in the Felix console, where you can see a list of events, which just happened in your CQ.
Some example for topics:
One disadvantage of Sling eventing is, that you cannot restrict the resource events to a certain path or user. Instead Sling registers with an admin session and publishes all observation events starting at the root node of the repository (/). You should filter quite early in your handleEvent routine for the events you are really interested in.
But: With these events you don’t geld hold of a resource. You always have you create them by this pattern:
if (event.getProperty(SlingConstants.PROPERTY_PATH) != null) {
Resource resource = resourceResolver.getResource(event.getPath());
}
Also there you need to take care, that you’re using an appropriate ResourceResolver (try to avoid an admin resource resolver as well).
Also JCR observation has some benefits, if you want or need to limit the events you receive more granularly, for example by listening to changes of specific nodeTypes only or mixins.
So, as a conclusion: If you need to restrict the amount of repository events you want to process directly on API level, JCR observation is the right thing for you. Otherwise go for Sling Eventing, as it offers you also the possibility to receive many more types of events. For non-repository events it’s the only way to listen for them.
You must be logged in to post a comment.