incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Sling Website > How to Manage Events in Sling
Date Mon, 16 Aug 2010 13:05:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/1/_/styles/combined.css?spaceKey=SLINGxSITE&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/SLINGxSITE/How+to+Manage+Events+in+Sling">How
to Manage Events in Sling</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~jck">Jean-Christophe
KAUTZMANN</a>
    </h4>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>The complete code for the
service looks as follows: <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">{<span
class="diff-added-chars"style="background-color: #dfd;">new</span>code:collapse=true}</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >package com.jck.sling.eventing; <br>
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>} <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">{<span
class="diff-added-chars"style="background-color: #dfd;">new</span>code}</span>
<br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p>Apache Sling provides some mechanisms and support for managing events. This
page describes ...</p>

<p>Sling makes a distinction between 2 types of events:</p>
<ul>
	<li>standard events: no garantee of processing</li>
	<li>job events: garantee of processing. Someone has to do something with the event
(do the job).</li>
</ul>


<p>The event mechanism is leveraging the OSGi Event Admin Specification (OSGi Compendium
113).<br/>
The OSGi API is very simple and leightweight - sending an event is just generating the event
object and calling the event admin. Receiving the event is implementing a single interface
and declaring through properties which topics one is interested in. For more details please
refer to the following javadocs:</p>
<ul>
	<li>package <a href="http://www.osgi.org/javadoc/r4v42/org/osgi/service/event/package-summary.html"
class="external-link" rel="nofollow">org.osgi.service.event</a> of the OSGI API.</li>
	<li>package <a href="http://sling.apache.org/apidocs/sling5/org/apache/sling/event/package-summary.html"
class="external-link" rel="nofollow">org.apache.sling.event</a> of the Sling API.</li>
</ul>


<p>You can learn more in the <a href="/confluence/pages/createpage.action?spaceKey=SLINGxSITE&amp;title=Eventing%2C+Jobs+and+Scheduling+section&amp;linkCreation=true&amp;fromPageId=23335037"
class="createlink">Eventing, Jobs and Scheduling section</a> (<a href="http://sling.apache.org/site/eventing-and-jobs.html"
class="external-link" rel="nofollow">http://sling.apache.org/site/eventing-and-jobs.html</a>).</p>

<p>To get started with the Sling eventing API, you will implement here a service that
listens to files posted to <b>/tmp/dropbox</b> and moves them to the appropriate
locations depending on the mime-type:</p>
<ul>
	<li>images (.png) are moved to <b>/dropbox/images/</b></li>
	<li>music (.mp3) are moved to <b>/dropbox/music/</b></li>
	<li>movies (.avi) are moved to <b>/dropbox/movies/</b></li>
	<li>otherwise the files are moved to <b>/dropbox/other/</b></li>
</ul>


<p>To do that, you will implement 2 services. The first one, called <b>OsgiDropBoxService</b>:</p>
<ul>
	<li>listens to osgi event <b>resource added</b></li>
	<li>sends a job event<br/>
The second one, called <b>DropBoxEventHandler</b>:</li>
	<li>listens to job event <b>file added to /tmp/dropbox</b></li>
	<li>moves the file according to its extension</li>
</ul>


<h2><a name="HowtoManageEventsinSling-ListeningtoOSGIEvents"></a>Listening
to OSGI Events</h2>

<p>To listen to the specific osgi event <b>resource added</b>:</p>
<ul>
	<li>The service needs to implement the <b>org.osgi.service.event.EventHandler</b>
interface and its <b>handleEvent(Event event)</b> method.</li>
	<li>The property <b>event.topics</b> needs to be set to <b>org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED</b>
in the class annotations.</li>
</ul>


<p>To get a list of possible events available in Sling (resource added, removed or changed),
refer to the <a href="http://sling.apache.org/apidocs/sling5/org/apache/sling/api/SlingConstants.html"
class="external-link" rel="nofollow">org.apache.sling.api.SlingConstants</a> class
in the Javadocs.</p>

<h2><a name="HowtoManageEventsinSling-SendingJobEvents"></a>Sending Job
Events</h2>

<p>To send a job event:</p>
<ul>
	<li>The service needs to implement the <b>org.apache.sling.event.JobProcessor</b>
interface and its <b>process(org.osgi.service.event.Event job)</b> method.</li>
</ul>


<p>The first part of the code looks as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
 * The &lt;code&gt;OsgiDropBoxService&lt;/code&gt; is listening content added
to /tmp/dropbox by using OSGI events
 * 
 * @scr.component  immediate=<span class="code-quote">"<span class="code-keyword">true</span>"</span>
 * @scr.service <span class="code-keyword">interface</span>=<span class="code-quote">"org.osgi.service.event.EventHandler"</span>
 * @scr.property name=<span class="code-quote">"event.topics"</span> valueRef=<span
class="code-quote">"org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED"</span>
 */
<span class="code-keyword">public</span> class OsgiDropBoxService <span class="code-keyword">implements</span>
JobProcessor, EventHandler {
</pre>
</div></div>

<p>The Event Admin service is needed to send the job event:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
	/** 
	 * The OSGI event admin used <span class="code-keyword">for</span> sending events

	 * @scr.reference
	 */
	<span class="code-keyword">private</span> EventAdmin eventAdmin;
</pre>
</div></div>

<p>The job topic for dropbox job events needs to be defined:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
    /** The job topic <span class="code-keyword">for</span> dropbox job events.
*/
    <span class="code-keyword">public</span> <span class="code-keyword">static</span>
<span class="code-keyword">final</span> <span class="code-object">String</span>
JOB_TOPIC = <span class="code-quote">"com/sling/eventing/dropbox/job"</span>;
</pre>
</div></div>

<p>The org.osgi.service.event.EventHandler#handleEvent(Event event) method needs to
be implemented:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
	<span class="code-keyword">public</span> void handleEvent(Event event) {
	    <span class="code-keyword">if</span> (EventUtil.isLocal(event)) {
	        EventUtil.processJob(event, <span class="code-keyword">this</span>);
	    }
	}
</pre>
</div></div>

<p>The <b>org.apache.sling.event.JobProcessor#process(Event event)</b> method
needs to be implemented.</p>

<p>The logic is as follows:</p>
<ul>
	<li>the OSGI event is analyzed</li>
	<li>if the event is a file that has been added to "/tmp/dropbox":
	<ul>
		<li>an event is created with 2 properties:
		<ul>
			<li>one to flag the event as a job event</li>
			<li>the file path</li>
		</ul>
		</li>
		<li>the job event is sent to all the listeners that subscribe to the topic of the
event.</li>
	</ul>
	</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
	<span class="code-keyword">public</span> <span class="code-object">boolean</span>
process(Event event) {
		<span class="code-object">String</span> propPath = (<span class="code-object">String</span>)
event.getProperty(SlingConstants.PROPERTY_PATH);
		<span class="code-object">String</span> propResType = (<span class="code-object">String</span>)
event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE);
		<span class="code-comment">// an event is sent <span class="code-keyword">if</span>
a file is added to /tmp/dropbox
</span>		<span class="code-keyword">if</span> (propPath.startsWith(<span
class="code-quote">"/tmp/dropbox"</span>) &amp;&amp; propResType.equals(<span
class="code-quote">"nt:file"</span>)) {
    		<span class="code-keyword">final</span> Dictionary&lt;<span class="code-object">String</span>,
<span class="code-object">Object</span>&gt; props = <span class="code-keyword">new</span>
Hashtable&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt;();
            props.put(EventUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC);
    		props.put(<span class="code-quote">"resourcePath"</span>, propPath);
    		Event dropboxJobEvent = <span class="code-keyword">new</span> Event(EventUtil.TOPIC_JOB,
props);
    		eventAdmin.sendEvent(dropboxJobEvent);
    		log.info(<span class="code-quote">"the dropbox job has been sent: {}"</span>,
propPath);
		}
		<span class="code-keyword">return</span> <span class="code-keyword">true</span>;
	}
</pre>
</div></div>

<p>The whole service looks now as follows:<br/>
...</p>

<p>Now that you have a service that sends job events whenever a file is uploaded to
<b>/tmp/dropbox</b>, you will create the service <b>DropBoxEventHandler</b>
that listens to those job events and moves the files to a location corresponding to their
mime-types.</p>

<h2><a name="HowtoManageEventsinSling-ListeningtoJobEvents"></a>Listening
to Job Events</h2>

<p>To listen to the job events that have been defined before:</p>
<ul>
	<li>The service also needs to implement the <b>org.osgi.service.event.EventHandler</b>
interface and its <b>handleEvent(Event event)</b> method.</li>
	<li>The property <b>event.topics</b> needs to be set to <b>com.jck.sling.eventing.osgi.OsgiDropBoxService.JOB_TOPIC</b>
in the class annotations.</li>
</ul>


<p>To move the files:</p>
<ul>
	<li>The service needs to implement the <b>org.apache.sling.event.JobProcessor</b>
interface and its <b>process(org.osgi.service.event.Event job)</b> method.</li>
</ul>


<p>The first part of the code looks as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
 * @scr.component  immediate=<span class="code-quote">"<span class="code-keyword">true</span>"</span>
 * @scr.service <span class="code-keyword">interface</span>=<span class="code-quote">"org.osgi.service.event.EventHandler"</span>
 * @scr.property name=<span class="code-quote">"event.topics"</span> valueRef=<span
class="code-quote">"com.jck.sling.eventing.osgi.OsgiDropBoxService.JOB_TOPIC"</span>
 */

<span class="code-keyword">public</span> class DropBoxEventHandler <span class="code-keyword">implements</span>
JobProcessor, EventHandler {
</pre>
</div></div>


<p>Several class fields are defined:</p>
<ul>
	<li>for logging</li>
	<li>to reference the SlingRepository and the JcrResourceResolverFactory services, which
are used in the implementation</li>
	<li>to define the destination path of the files</li>
</ul>


 <div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   /** Default log. */
    <span class="code-keyword">protected</span> <span class="code-keyword">final</span>
Logger log = LoggerFactory.getLogger(<span class="code-keyword">this</span>.getClass());

    <span class="code-keyword">private</span> Session adminSession;
    
    /** @scr.reference */
    <span class="code-keyword">private</span> SlingRepository repository;
    
    /**
     * @scr.reference
     */
    <span class="code-keyword">private</span> JcrResourceResolverFactory resolverFactory;
    
    <span class="code-keyword">private</span> <span class="code-keyword">final</span>
<span class="code-keyword">static</span> <span class="code-object">String</span>
IMAGES_PATH = <span class="code-quote">"/dropbox/images/"</span>;
    <span class="code-keyword">private</span> <span class="code-keyword">final</span>
<span class="code-keyword">static</span> <span class="code-object">String</span>
MUSIC_PATH = <span class="code-quote">"/dropbox/music/"</span>;
    <span class="code-keyword">private</span> <span class="code-keyword">final</span>
<span class="code-keyword">static</span> <span class="code-object">String</span>
MOVIES_PATH = <span class="code-quote">"/dropbox/movies/"</span>;
    <span class="code-keyword">private</span> <span class="code-keyword">final</span>
<span class="code-keyword">static</span> <span class="code-object">String</span>
OTHER_PATH = <span class="code-quote">"/dropbox/other/"</span>;
</pre>
</div></div>

<h2><a name="HowtoManageEventsinSling-HandlingJobEvents"></a>Handling Job
Events</h2>

<p>The <b>org.osgi.service.event.EventHandler#handleEvent(Event event)</b>
method needs to be implemented:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
	<span class="code-keyword">public</span> void handleEvent(Event event) {
	    <span class="code-keyword">if</span> (EventUtil.isLocal(event)) {
	        EventUtil.processJob(event, <span class="code-keyword">this</span>);
	    }
	}
</pre>
</div></div>

<p>The <b>org.apache.sling.event.JobProcessor#process(Event event)</b> method
needs to be implemented.<br/>
The logic is as follows:</p>
<ul>
	<li>the resource path is extracted from the job event property</li>
	<li>the resource is obtained from the file path</li>
	<li>if the resource is a file, the destination path is defined based on the file mime-type</li>
	<li>the file is moved to the new location</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
	<span class="code-keyword">public</span> <span class="code-object">boolean</span>
process(Event event) {
		<span class="code-keyword">try</span> {
			<span class="code-object">String</span> resourcePath = (<span class="code-object">String</span>)
event.getProperty(<span class="code-quote">"resourcePath"</span>);
			<span class="code-object">String</span> resourceName = resourcePath.substring(resourcePath.lastIndexOf(<span
class="code-quote">"/"</span>) + 1);
        	adminSession = repository.loginAdministrative(<span class="code-keyword">null</span>);
	        ResourceResolver resourceResolver = resolverFactory.getResourceResolver(adminSession);
	        Resource res = resourceResolver.getResource(resourcePath);
	        <span class="code-keyword">if</span> (ResourceUtil.isA(res, <span
class="code-quote">"nt:file"</span>)) {
	        	<span class="code-object">String</span> mimeType = res.getResourceMetadata().getContentType();
	        	<span class="code-object">String</span> destDir;
	        	<span class="code-keyword">if</span> (mimeType.equals(<span class="code-quote">"image/png"</span>))
{
	        		destDir = IMAGES_PATH;
	        	}
	        	<span class="code-keyword">else</span> <span class="code-keyword">if</span>
(mimeType.equals(<span class="code-quote">"audio/mpeg"</span>)) {
	        		destDir = MUSIC_PATH;
	        	}
	        	<span class="code-keyword">else</span> <span class="code-keyword">if</span>
(mimeType.equals(<span class="code-quote">"video/x-msvideo"</span>)) {
	        		destDir = MOVIES_PATH;
	        	}
	        	<span class="code-keyword">else</span> {
	        		destDir = OTHER_PATH;
	        	}
        		adminSession.move(resourcePath, destDir + resourceName);
	        	adminSession.save();
	        	log.info(<span class="code-quote">"The file {} has been moved to {}"</span>,
resourceName, destDir);
	        }
	        <span class="code-keyword">return</span> <span class="code-keyword">true</span>;
		} <span class="code-keyword">catch</span> (RepositoryException e) {
			log.error(<span class="code-quote">"RepositoryException: "</span> + e);
			<span class="code-keyword">return</span> <span class="code-keyword">false</span>;
        } <span class="code-keyword">finally</span> {
            <span class="code-keyword">if</span> (adminSession != <span class="code-keyword">null</span>
&amp;&amp; adminSession.isLive()) {
            	adminSession.logout();
            	adminSession = <span class="code-keyword">null</span>;
            }
        }
	}
</pre>
</div></div>

<p>The complete code for the service looks as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: true; theme: Default; brush: java; collapse:
true; gutter: false"><![CDATA[
package com.jck.sling.eventing;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.event.EventUtil;
import org.apache.sling.event.JobProcessor;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The &lt;code&gt;DropBoxEventHandler&lt;/code&gt; 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/
 * 
 * When used with JCR events:  valueRef="com.jck.sling.eventing.DropBoxService.JOB_TOPIC"
 * When used with OSGI events: valueRef="com.jck.sling.eventing.osgi.OsgiDropBoxService.JOB_TOPIC"
 * 
 * @scr.component  immediate="true"
 * @scr.service interface="org.osgi.service.event.EventHandler"
 * @scr.property name="event.topics" valueRef="com.jck.sling.eventing.osgi.OsgiDropBoxService.JOB_TOPIC"
 */

public class DropBoxEventHandler implements JobProcessor, EventHandler {

    /** Default log. */
    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    private Session adminSession;
    
    /** @scr.reference */
    private SlingRepository repository;
    
    /**
     * @scr.reference
     */
    private JcrResourceResolverFactory resolverFactory;
    
    private final static String IMAGES_PATH = "/dropbox/images/";
    private final static String MUSIC_PATH = "/dropbox/music/";
    private final static String MOVIES_PATH = "/dropbox/movies/";
    private final static String OTHER_PATH = "/dropbox/other/";

	public void handleEvent(Event event) {
	    if (EventUtil.isLocal(event)) {
	        EventUtil.processJob(event, this);
	    }
	}

	public boolean process(Event event) {
		try {
			String resourcePath = (String) event.getProperty("resourcePath");
			String resourceName = resourcePath.substring(resourcePath.lastIndexOf("/") + 1);
        	adminSession = repository.loginAdministrative(null);
	        ResourceResolver resourceResolver = resolverFactory.getResourceResolver(adminSession);
	        Resource res = resourceResolver.getResource(resourcePath);
	        if (ResourceUtil.isA(res, "nt:file")) {
	        	String mimeType = res.getResourceMetadata().getContentType();
	        	String destDir;
	        	if (mimeType.equals("image/png")) {
	        		destDir = IMAGES_PATH;
	        	}
	        	else if (mimeType.equals("audio/mpeg")) {
	        		destDir = MUSIC_PATH;
	        	}
	        	else if (mimeType.equals("video/x-msvideo")) {
	        		destDir = MOVIES_PATH;
	        	}
	        	else {
	        		destDir = OTHER_PATH;
	        	}
        		adminSession.move(resourcePath, destDir + resourceName);
	        	adminSession.save();
	        	log.info("The file {} has been moved to {}", resourceName, destDir);
	        }
	        return true;
		} catch (RepositoryException e) {
			log.error("RepositoryException: " + e);
			return false;
        } finally {
            if (adminSession != null &amp;&amp; adminSession.isLive()) {
            	adminSession.logout();
            	adminSession = null;
            }
        }
	}


}
]]></script>
</div></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/SLINGxSITE/How+to+Manage+Events+in+Sling">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23335037&revisedVersion=11&originalVersion=10">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/SLINGxSITE/How+to+Manage+Events+in+Sling?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message