/* * Copyright 2012 david gonzalez. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.activecq.samples.eventhandlers.impl; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.api.observation.JackrabbitEvent; import org.apache.sling.event.EventUtil; import org.apache.sling.jcr.api.SlingRepository; import org.osgi.framework.Constants; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.EventAdmin; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; import javax.jcr.observation.ObservationManager; import java.util.Dictionary; import java.util.Hashtable; import java.util.logging.Level; import java.util.logging.Logger; @Component( label = "Samples - JCR Event Listener", description = "Sample implementation of a low-level JCR Event Listner.", metatype = false, immediate = true) @Properties({ @Property( label = "Vendor", name = Constants.SERVICE_VENDOR, value = "ActiveCQ", propertyPrivate = true) }) @Service public class SampleJcrEventListener implements EventListener { /* * A combination of one or more event type constants encoded as a bitmask * * Available JCR Events: * * Event.NODE_ADDED * Event.NODE_MOVED * Event.NODE_REMOVED * Event.PERSIST * Event.PROPERTY_ADDED * Event.PROPERTY_REMOVED * Event.PROPERTY_CHANGED */ private final int events = Event.PROPERTY_ADDED | Event.NODE_ADDED; // Only events whose associated node is at absPath (or within its subtree, if isDeep is true) will be received. It is permissible to register a listener for a path where no node currently exists. private final String absPath = "/content/samples"; private final boolean isDeep = true; // Additionally, if noLocal is true, then events generated by the session through which the listener was registered are ignored. Otherwise, they are not ignored. private final boolean noLocal = false; private final String[] uuids = null; // Only events whose associated node has one of the node types (or a subtype of one of the node types) in this list will be received. If his parameter is null then no node type-related restriction is placed on events received. private final String[] nodeTypes = new String[]{"nt:unstructured", "nt:folder"}; @Reference private SlingRepository repository; @Reference private EventAdmin eventAdmin; @Override public void onEvent(EventIterator events) { // Handle events while (events.hasNext()) { try { Event event = events.nextEvent(); // IMPORTANT! // // JCR Events are NOT cluster-aware and this event listener will be invoked on every node in the cluster. // Check if this event was spawned from the server this event handler is running on or from another if (event instanceof JackrabbitEvent && ((JackrabbitEvent) event).isExternal()) { // Event did NOT originate from this server // Skip, Let only the originator process; // This is usual to avoid having the same processing happening for every node in a cluster. This // is almost always the case when the EventListener modifies the JCR. // A possible use-case for handling the event on EVERY member of a cluster would be clearing out an // in memory (Service-level) cache. return; } else { // Event originated from THIS server // Continue processing this Event } final String path = event.getPath(); if (Event.NODE_ADDED == event.getType()) { // Node added! } else if (Event.PROPERTY_ADDED == event.getType()) { // Property added! } boolean handleInSlingEvent = true; if (!handleInSlingEvent) { // Execute handler logic // Get a resourceResolver or JCR Session using the usual ways // Always make sure to close them if you open them though! } else { // Or fire off a specific Sling Event final Dictionary<String, Object> eventProperties = new Hashtable<String, Object>(); eventProperties.put("resourcePath", path); eventAdmin.postEvent(new org.osgi.service.event.Event(EventUtil.TOPIC_JOB, eventProperties)); } } catch (RepositoryException ex) { Logger.getLogger(SampleJcrEventListener.class.getName()).log(Level.SEVERE, null, ex); } } } @Activate public void activate(ComponentContext context) throws RepositoryException { Session adminSession = null; ObservationManager observationManager = null; try { adminSession = repository.loginAdministrative(null); // Get JCR ObservationManager from Workspace observationManager = adminSession.getWorkspace().getObservationManager(); // Register the JCR Listener /** This is the KEY element where this listener is registered **/ observationManager.addEventListener(this, events, absPath, isDeep, uuids, nodeTypes, noLocal); } finally { if (adminSession != null) { adminSession.logout(); } } } @Deactivate public void deactivate() throws RepositoryException { Session adminSession = null; ObservationManager observationManager = null; try { adminSession = repository.loginAdministrative(null); // Get JCR ObservationManager from Workspace observationManager = adminSession.getWorkspace().getObservationManager(); if (observationManager != null) { // Un-register event handler observationManager.removeEventListener(this); } } finally { if (adminSession != null) { adminSession.logout(); } } } }