/* * 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 com.day.cq.jcrclustersupport.ClusterAware; import org.apache.commons.lang.ArrayUtils; import org.apache.felix.scr.annotations.Component; 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.sling.api.SlingConstants; import org.apache.sling.event.EventUtil; import org.apache.sling.event.jobs.JobProcessor; import org.apache.sling.event.jobs.JobUtil; import org.osgi.framework.Constants; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Dictionary; /** * The <code>DropBoxEventHandler</code> moves files posted to /tmp/dropbox to the appropriate locations: * images (MIME type: image/png) to /dropbox/images/ * music (MIME type: audio/mpeg) to /dropbox/music/ * movies (MIME type: video/x-msvideo) to /dropbox/movies/ * otherwise to /dropbox/other/ * * @scr.component immediate="true" * @scr.service interface="org.osgi.service.event.EventHandler" * @scr.property name="event.topics" valueRef="mypackage.DropBoxService.JOB_TOPIC" */ @Component( label = "Samples - Sling Event Handler", description = "Sample implementation of a Custom Event Listener based on Sling", immediate = true, metatype = false ) @Properties({ @Property( label = "Vendor", name = Constants.SERVICE_VENDOR, value = "ActiveCQ", propertyPrivate = true ), @Property( label = "Event Topics", value = {"samples/events/poked", "samples/events/*"}, description = "[Required] Event Topics this event handler will to respond to.", name = "event.topics", propertyPrivate = true ) /* @Property( label="Event Filter", value="(propKey=propValue)", description="[Optional] Event Filter further selects Events of interest.", name="event.topics", propertyPrivate=true ) */ }) @Service public class SampleEventHandler implements JobProcessor, EventHandler, ClusterAware { protected final Logger log = LoggerFactory.getLogger(this.getClass()); // EventAdmin is used to manually trigger other events @Reference private EventAdmin eventAdmin; private boolean isMaster; @Override public void handleEvent(Event event) { boolean handleLocally = false; boolean handleWithMaster = !handleLocally; if (!ArrayUtils.contains(event.getPropertyNames(), EventUtil.PROPERTY_DISTRIBUTE)) { // This is the check for a distributed event or not; if this property does not exist, it usually // means that this event handler should process the job, as no other event handlers // will see this event. JobUtil.processJob(event, this); } else if (handleLocally && EventUtil.isLocal(event)) { // This is a distributed event (first 'if' condition failed) // If this server created the event // then only this server should process the event // This will call this's process(..) method, passing in the event obj // JobUtil.processJob(..) sends/checks for an ack for this job // Jobs guarantee the event will be processed (though doesnt guarentee the job will be processed SUCCESSFULLY) JobUtil.processJob(event, this); } else if (handleWithMaster && this.isMaster) { // This is a distributed event (first 'if' condition failed) // If a event is distributed, you may only want to execute it the Master node in // the cluster. JobUtil.processJob(event, this); } else { // DO NOTHING! } } @Override public boolean process(Event event) { // Process event logic here /** * Sling Event Properties - VERY handy */ // Resource path "undergoing" the event event.getProperty(SlingConstants.PROPERTY_PATH); // Resource type event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE); // Resource super type event.getProperty(SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE); // Properties names that were added/changes/removed event.getProperty(SlingConstants.PROPERTY_ADDED_ATTRIBUTES); event.getProperty(SlingConstants.PROPERTY_CHANGED_ATTRIBUTES); event.getProperty(SlingConstants.PROPERTY_REMOVED_ATTRIBUTES); // User id event.getProperty(SlingConstants.PROPERTY_USERID); /** * Event Properties */ // Specifies application node event.getProperty(EventUtil.PROPERTY_APPLICATION); // Specifies if the event should be distributed in the cluster (defaults to false) event.getProperty(EventUtil.PROPERTY_DISTRIBUTE); // Timed Event properties // Unique event id for Timed event event.getProperty(EventUtil.PROPERTY_TIMED_EVENT_ID); event.getProperty(EventUtil.PROPERTY_TIMED_EVENT_DATE); event.getProperty(EventUtil.PROPERTY_TIMED_EVENT_PERIOD); event.getProperty(EventUtil.PROPERTY_TIMED_EVENT_SCHEDULE); event.getProperty(EventUtil.PROPERTY_TIMED_EVENT_TOPIC); /** * Available for Events that are processed as Jobs */ if(JobUtil.isJobEvent(event)) { event.getProperty(JobUtil.JOB_ID); event.getProperty(JobUtil.PROPERTY_JOB_NAME); event.getProperty(JobUtil.PROPERTY_JOB_QUEUE_NAME); event.getProperty(JobUtil.PROPERTY_JOB_CREATED); event.getProperty(JobUtil.PROPERTY_JOB_PARALLEL); event.getProperty(JobUtil.PROPERTY_JOB_PRIORITY); event.getProperty(JobUtil.PROPERTY_JOB_QUEUE_ORDERED); event.getProperty(JobUtil.PROPERTY_JOB_RETRIES); event.getProperty(JobUtil.PROPERTY_JOB_RETRY_COUNT); event.getProperty(JobUtil.PROPERTY_JOB_RETRY_DELAY); event.getProperty(JobUtil.PROPERTY_JOB_RUN_LOCAL); event.getProperty(JobUtil.PROPERTY_JOB_TOPIC); event.getProperty(JobUtil.PROPERTY_NOTIFICATION_JOB); } // Only return false if job processing failed and the job should be rescheduled return true; } /** * Cluster Aware Methods * */ @Override public void bindRepository(String repositoryId, String clusterId, boolean isMaster) { this.isMaster = isMaster; } @Override public void unbindRepository() { this.isMaster = false; } /** * OSGi Component Methods * */ protected void activate(ComponentContext context) { Dictionary<String, Object> properties = context.getProperties(); // Do things like get an admin JCR Session to modify nodes } protected void deactivate(ComponentContext context) { // Close/release any resources before ending the component's lifecycle } }