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, 25 Jun 2012 12:27:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/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" >h2. Sending Job Events <br>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">To
send an event the following code can be used:  <br>{code} <br>public void sendEvent()
{ <br>    final Dictionary&lt;String, Object&gt; props = new Hashtable&lt;String,
Object&gt;(); <br>    props.put(JobUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC); <br>
   props.put(&quot;resourcePath&quot;, RESOURCE_PATH); <br>    final Event myEvent
= new Event(JOB_TOPIC, props); <br>    eventAdmin.sendEvent(myEvent); <br>}  <br>{code}
<br> <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">To</span>
<span class="diff-added-words"style="background-color: #dfd;">However, for our example,
to</span> send a job event the service needs to implement: <br></td></tr>
            <tr><td class="diff-unchanged" >* the *org.osgi.service.event.EventHandler*
interface. <br>* the *org.apache.sling.event.JobProcessor* interface. <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="HowtoManageEventsinSling-HowtoManageEventsinSling"></a>How
to Manage Events in Sling</h1>

<p>Apache Sling provides some mechanisms and support for managing events.</p>

<p>The event mechanism is leveraging the OSGi Event Admin Specification (OSGi Compendium
113). The OSGi API is very simple and lightweight. 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. <br/>
Sling makes a distinction between events and job events. Unlike events, job events are garanteed
to be processed. In other words: someone has to do something with the job event (do the job).
</p>

<p>For more details please refer to the following resources:</p>
<ul>
	<li><a href="http://sling.apache.org/site/eventing-and-jobs.html" class="external-link"
rel="nofollow">Eventing, Jobs and Scheduling section</a> to get detailed information
on the eventing mechanisms in Sling.</li>
	<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/sling6/org/apache/sling/event/package-summary.html"
class="external-link" rel="nofollow">org.apache.sling.event</a> of the Sling API.</li>
</ul>


<p>This page drives you through the implementation of two services that rely on the
Sling eventing mechanisms. The services implement the following use case: whenever a file
is uploaded to a temporary location in your web application, the file is moved to a specific
location according to its MIME type.</p>

<h2><a name="HowtoManageEventsinSling-Introduction"></a>Introduction</h2>

<p>You will now implement the logic to listen to files posted to <b>/tmp/dropbox</b>
and to move 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 two services. The first one, called <b>DropBoxService</b>:</p>
<ul>
	<li>Listens to OSGI events.</li>
	<li>Sends a job event if a resource has been added to <b>/tmp/dropbox</b>.</li>
</ul>


<p>The second one, called <b>DropBoxEventHandler</b>:</p>
<ul>
	<li>Listens to the former job event.</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 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>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
 * @scr.property name=<span class="code-quote">"event.topics"</span> valueRef=<span
class="code-quote">"org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED"</span>
</pre>
</div></div>

<p>You can refer to the <a href="http://sling.apache.org/apidocs/sling6/org/apache/sling/api/SlingConstants.html"
class="external-link" rel="nofollow">org.apache.sling.api.SlingConstants</a> class
in the Javadocs to know about other events available in Sling.</p>

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

<p>To send an event the following code can be used: </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> void sendEvent() {
    <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(JobUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC);
    props.put(<span class="code-quote">"resourcePath"</span>, RESOURCE_PATH);
    <span class="code-keyword">final</span> Event myEvent = <span class="code-keyword">new</span>
Event(JOB_TOPIC, props);
    eventAdmin.sendEvent(myEvent);
} 
</pre>
</div></div>

<p>However, for our example, to send a job event the service needs to implement:</p>
<ul>
	<li>the <b>org.osgi.service.event.EventHandler</b> interface.</li>
	<li>the <b>org.apache.sling.event.JobProcessor</b> interface.</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class DropBoxService <span class="code-keyword">implements</span>
JobProcessor, EventHandler {
</pre>
</div></div>

<p>To send the job event the Event Admin service needs to be referenced:</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 <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.</p>

<p>Its 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 <b>/tmp/dropbox</b>:
	<ul>
		<li>An event is created with 2 properties:
		<ul>
			<li>A property to set the event as a job event.</li>
			<li>A property for 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 complete code for the <b>DropBoxService</b> service is available
<a href="/confluence/download/attachments/23335037/DropBoxService.java?version=1&amp;modificationDate=1282040557000">here</a>.</p>

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

<p>Now that you have implemented a service that sends a job event when a file is uploaded
to <b>/tmp/dropbox</b>, you will implement the service <b>DropBoxEventHandler</b>
that listens to those job events and moves the files to a location according to their MIME
types.</p>

<p>To listen to the job events that have been defined before:</p>
<ul>
	<li>The property <b>event.topics</b> needs to be set to <b>mypackage.DropBoxService.JOB_TOPIC</b>
in the class annotations.</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
 * @scr.property name=<span class="code-quote">"event.topics"</span> valueRef=<span
class="code-quote">"mypackage.DropBoxService.JOB_TOPIC"</span>
</pre>
</div></div>

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

<p>To move the files the service needs to implement:</p>
<ul>
	<li>the <b>org.osgi.service.event.EventHandler</b> interface.</li>
	<li>the <b>org.apache.sling.event.JobProcessor</b> interface.</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class DropBoxEventHandler <span class="code-keyword">implements</span>
JobProcessor, EventHandler {
</pre>
</div></div>

<p>Some class fields need to be defined for:</p>
<ul>
	<li>The default log.</li>
	<li>The references to the SlingRepository and the JcrResourceResolverFactory services,
which are used in the implementation.</li>
	<li>The destination paths 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());

    /** @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>

<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.</p>

<p>Its 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 resource 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) {
		Session adminSession = <span class="code-keyword">null</span>;
		<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 <b>DropBoxEventHandler</b> service is available
<a href="/confluence/download/attachments/23335037/DropBoxEventHandler.java?version=1&amp;modificationDate=1282040540000">here</a>.</p>
    </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=29&originalVersion=28">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