Author: fmeschbe Date: Mon Jun 4 07:40:42 2012 New Revision: 1345850 URL: http://svn.apache.org/viewvc?rev=1345850&view=rev Log: SLING-2002 Complete review of Tutorial pages
Added: sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxEventHandler.java sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxService.java Modified: sling/site/trunk/content/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.mdtext sling/site/trunk/content/documentation/tutorials-how-tos/how-to-manage-events-in-sling.mdtext sling/site/trunk/content/documentation/tutorials-how-tos/installing-and-upgrading-bundles.mdtext sling/site/trunk/content/documentation/tutorials-how-tos/jackrabbit-persistence.mdtext sling/site/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.mdtext Added: sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxEventHandler.java URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxEventHandler.java?rev=1345850&view=auto ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxEventHandler.java (added) +++ sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxEventHandler.java Mon Jun 4 07:40:42 2012 @@ -0,0 +1,92 @@ + +package mypackage; + +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 <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" + */ + +public class DropBoxEventHandler implements JobProcessor, EventHandler { + + /** Default log. */ + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + /** @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) { + Session adminSession = null; + 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 && adminSession.isLive()) { + adminSession.logout(); + adminSession = null; + } + } + } +} Added: sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxService.java URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxService.java?rev=1345850&view=auto ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxService.java (added) +++ sling/site/trunk/content/documentation/tutorials-how-tos/DropBoxService.java Mon Jun 4 07:40:42 2012 @@ -0,0 +1,57 @@ + +package mypackage; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.apache.sling.api.SlingConstants; +import org.apache.sling.event.EventUtil; +import org.apache.sling.event.JobProcessor; +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; + +/** + * The <code>DropBoxService</code> is listening content added to /tmp/dropbox by using OSGI events + * + * @scr.component immediate="true" + * @scr.service interface="org.osgi.service.event.EventHandler" + * @scr.property name="event.topics" valueRef="org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED" + */ +public class DropBoxService implements JobProcessor, EventHandler { + + /** Default log. */ + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + /** + * The OSGI event admin used for sending events + * @scr.reference + */ + private EventAdmin eventAdmin; + + /** The job topic for dropbox job events. */ + public static final String JOB_TOPIC = "com/sling/eventing/dropbox/job"; + + public void handleEvent(Event event) { + if (EventUtil.isLocal(event)) { + EventUtil.processJob(event, this); + } + } + + public boolean process(Event event) { + String propPath = (String) event.getProperty(SlingConstants.PROPERTY_PATH); + String propResType = (String) event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE); + // an event is sent if a file is added to /tmp/dropbox + if (propPath.startsWith("/tmp/dropbox") && propResType.equals("nt:file")) { + final Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put(EventUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC); + props.put("resourcePath", propPath); + Event dropboxJobEvent = new Event(EventUtil.TOPIC_JOB, props); + eventAdmin.sendEvent(dropboxJobEvent); + log.info("the dropbox job has been sent: {}", propPath); + } + return true; + } +} Modified: sling/site/trunk/content/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.mdtext URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.mdtext?rev=1345850&r1=1345849&r2=1345850&view=diff ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.mdtext (original) +++ sling/site/trunk/content/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.mdtext Mon Jun 4 07:40:42 2012 @@ -1,6 +1,5 @@ Title: Getting Resources and Properties in Sling -# Getting Resources and Properties in Sling The Resource is one of the central parts of Sling. Extending from JCR's Everything is Content, Sling assumes Everthing is a Resource. Thus Sling is maintaining a virtual tree of resources, which is a merger of the actual contents in the JCR Repository and resources provided by so called resource providers. By doing this Sling fits very well in the paradigm of the REST architecture. @@ -12,8 +11,8 @@ The whole game consists in first getting You can access a resource through the `ResourceResolverFactory` service: - - /** @scr.reference */ + #!java + @Reference private ResourceResolverFactory resolverFactory; public void myMethod() { @@ -35,14 +34,14 @@ You can access a resource through the `R You can access the resource defined by the request URL through the `SlingHttpServletRequest`: - + #!java Resource res = req.getResource(); // req is the SlingHttpServletRequest You can access any resource by first accessing the `ResourceResolver`: - + #!java String resourcePath = "path/to/resource"; ResourceResolver resourceResolver = req.getResourceResolver(); // req is the SlingHttpServletRequest @@ -55,7 +54,7 @@ When you use the `<sling:defineObjects>` To access a resource: - + #!jsp <sling:defineObjects> <% String resourcePath = "path/to/resource"; @@ -65,7 +64,7 @@ To access a resource: If needed you can adapt a Sling Resource to a JCR Node: - + #!java Node node = resource.adaptTo(Node.class); @@ -75,22 +74,22 @@ Note: `resource.adaptTo(Node.class)` may The `ValueMap` is an easy way to access properties of a resource. With most resources you can use `Adaptable.adaptTo(Class)` to adapt the resource to a value map: - + #!java ValueMap properties = res.adaptTo(ValueMap.class); // res is the Resource You can also access the properties through the `ResourceUtil` utility class: - + #!java ValueMap properties = ResourceUtil.getValueMap(res); // res is the Resource Then, to access a specific String property called `propName`: - + #!java String rule = properties.get(propName, (String) null); -For more details about resources and how to access them in Sling, you can refer to the [Sling documentation about Resources]({{ refs.http://sling.apache.org/site/resources.html.path }}). +For more details about resources and how to access them in Sling, you can refer to the [Sling documentation about Resources]({{ refs.resources.path }}). Modified: sling/site/trunk/content/documentation/tutorials-how-tos/how-to-manage-events-in-sling.mdtext URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/how-to-manage-events-in-sling.mdtext?rev=1345850&r1=1345849&r2=1345850&view=diff ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/how-to-manage-events-in-sling.mdtext (original) +++ sling/site/trunk/content/documentation/tutorials-how-tos/how-to-manage-events-in-sling.mdtext Mon Jun 4 07:40:42 2012 @@ -1,6 +1,5 @@ Title: How to Manage Events in Sling -# How to Manage Events in Sling Apache Sling provides some mechanisms and support for managing events. @@ -8,138 +7,139 @@ The event mechanism is leveraging the OS 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). For more details please refer to the following resources: -* [Eventing, Jobs and Scheduling section]({{ refs.http://sling.apache.org/site/eventing-and-jobs.html.path }}) to get detailed information on the eventing mechanisms in Sling. -* package [org.osgi.service.event]({{ refs.http://www.osgi.org/javadoc/r4v42/org/osgi/service/event/package-summary.html.path }}) of the OSGI API. -* package [org.apache.sling.event]({{ refs.http://sling.apache.org/apidocs/sling6/org/apache/sling/event/package-summary.html.path }}) of the Sling API. + +* [Eventing, Jobs and Scheduling section]({{ refs.eventing-and-jobs.path }}) to get detailed information on the eventing mechanisms in Sling. +* Package [org.osgi.service.event](http://www.osgi.org/javadoc/r4v42/org/osgi/service/event/package-summary.html) of the OSGI API. +* Package [org.apache.sling.event](/apidocs/sling6/org/apache/sling/event/package-summary.html) of the Sling API. 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. ## Introduction You will now implement the logic to listen to files posted to */tmp/dropbox* and to move them to the appropriate locations depending on the MIME type: -* images (.png) are moved to */dropbox/images/* -* music (.mp3) are moved to */dropbox/music/* -* movies (.avi) are moved to */dropbox/movies/* -* otherwise the files are moved to */dropbox/other/* -To do that, you will implement two services. The first one, called *DropBoxService*: +* images (.png) are moved to **/dropbox/images/** +* music (.mp3) are moved to **/dropbox/music/** +* movies (.avi) are moved to **/dropbox/movies/** +* otherwise the files are moved to **/dropbox/other/** + +To do that, you will implement two services. The first one, called **DropBoxService**: + * Listens to OSGI events. -* Sends a job event if a resource has been added to */tmp/dropbox*. +* Sends a job event if a resource has been added to **/tmp/dropbox**. + +The second one, called **DropBoxEventHandler**: -The second one, called *DropBoxEventHandler*: * Listens to the former job event. * Moves the file according to its extension. ## Listening to OSGI Events -To listen to the specific OSGI event *"resource added"*: -* The property *event.topics* needs to be set to *org.apache.sling.api.SlingConstants.TOPIC*RESOURCE*ADDED* in the class annotations. +To listen to the specific OSGI event **resource added* the property *event.topics* needs to be set to **org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED** in the class annotations. + #!java + @Property(name="event.topics", + value=org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED) - * @scr.property name="event.topics" valueRef="org.apache.sling.api.SlingConstants.TOPIC_RESOURCE_ADDED" - -You can refer to the [org.apache.sling.api.SlingConstants]({{ refs.http://sling.apache.org/apidocs/sling6/org/apache/sling/api/SlingConstants.html.path }}) class in the Javadocs to know about other events available in Sling. +You can refer to the [org.apache.sling.api.SlingConstants](/apidocs/sling6/org/apache/sling/api/SlingConstants.html) class in the Javadocs to know about other events available in Sling. ## Sending Job Events -To send a job event the service needs to implement: -* the *org.osgi.service.event.EventHandler* interface. -* the *org.apache.sling.event.JobProcessor* interface. +To send a job event the service needs to implement the **org.osgi.service.event.EventHandler** and **org.apache.sling.event.JobProcessor** interfaces: + #!java public class DropBoxService implements JobProcessor, EventHandler { To send the job event the Event Admin service needs to be referenced: - /** - * The OSGI event admin used for sending events - * @scr.reference - */ - private EventAdmin eventAdmin; + #!java + @Reference + private EventAdmin eventAdmin; The job topic for dropbox job events needs to be defined: - /** The job topic for dropbox job events. */ - public static final String JOB_TOPIC = "com/sling/eventing/dropbox/job"; + #!java + /** The job topic for dropbox job events. */ + public static final String JOB_TOPIC = "com/sling/eventing/dropbox/job"; -The *org.osgi.service.event.EventHandler#handleEvent(Event event)* method needs to be implemented: +The **org.osgi.service.event.EventHandler#handleEvent(Event event)** method needs to be implemented: - public void handleEvent(Event event) { - if (EventUtil.isLocal(event)) { - EventUtil.processJob(event, this); - } - } + #!java + public void handleEvent(Event event) { + if (EventUtil.isLocal(event)) { + EventUtil.processJob(event, this); + } + } -The *org.apache.sling.event.JobProcessor#process(Event event)* method needs to be implemented. +The **org.apache.sling.event.JobProcessor#process(Event event)** method needs to be implemented: -Its logic is as follows: -* The OSGI event is analyzed. -* If the event is a file that has been added to */tmp/dropbox*: -** An event is created with 2 properties: -*** A property to set the event as a job event. -*** A property for the file path. -** The job event is sent to all the listeners that subscribe to the topic of the event. - - - public boolean process(Event event) { - String propPath = (String) event.getProperty(SlingConstants.PROPERTY_PATH); - String propResType = (String) event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE); - // an event is sent if a file is added to /tmp/dropbox - if (propPath.startsWith("/tmp/dropbox") && propResType.equals("nt:file")) { - final Dictionary<String, Object> props = new Hashtable<String, Object>(); - props.put(EventUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC); - props.put("resourcePath", propPath); - Event dropboxJobEvent = new Event(EventUtil.TOPIC_JOB, props); - eventAdmin.sendEvent(dropboxJobEvent); - log.info("the dropbox job has been sent: {}", propPath); - } - return true; + #!java + public boolean process(Event event) { + + // get the resource event information + String propPath = (String) event.getProperty(SlingConstants.PROPERTY_PATH); + String propResType = (String) event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE); + + // an event is sent if a file is added to /tmp/dropbox + if (propPath.startsWith("/tmp/dropbox") && propResType.equals("nt:file")) { + + // configure the job event + final Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put(EventUtil.PROPERTY_JOB_TOPIC, JOB_TOPIC); + props.put("resourcePath", propPath); + + // create the job event + Event dropboxJobEvent = new Event(EventUtil.TOPIC_JOB, props); + + // deliver the job event + eventAdmin.sendEvent(dropboxJobEvent); + + log.info("the dropbox job has been sent: {}", propPath); } + + // all set and done + return true; + } -The complete code for the *DropBoxService* service is available [here]({{ refs.-dropboxservice-java.path }}). +The complete code for the **DropBoxService** service is available [here](DropBoxService.java). ## Listening to Job Events -Now that you have implemented a service that sends a job event when a file is uploaded to */tmp/dropbox*, you will implement the service *DropBoxEventHandler* that listens to those job events and moves the files to a location according to their MIME types. - -To listen to the job events that have been defined before: -* The property *event.topics* needs to be set to *mypackage.DropBoxService.JOB_TOPIC* in the class annotations. +Now that you have implemented a service that sends a job event when a file is uploaded to **/tmp/dropbox**, you will implement the service **DropBoxEventHandler** that listens to those job events and moves the files to a location according to their MIME types. +To listen to the job events that have been defined before the property **event.topics** needs to be set to **mypackage.DropBoxService.JOB_TOPIC** in the class annotations: - * @scr.property name="event.topics" valueRef="mypackage.DropBoxService.JOB_TOPIC" + #!java + @Property(name="event.topics", + value=mypackage.DropBoxService.JOB_TOPIC) ## Handling Job Events -To move the files the service needs to implement: -* the *org.osgi.service.event.EventHandler* interface. -* the *org.apache.sling.event.JobProcessor* interface. +To move the files the service needs to implement the **org.osgi.service.event.EventHandler** and **org.apache.sling.event.JobProcessor** interfaces: + #!java public class DropBoxEventHandler implements JobProcessor, EventHandler { -Some class fields need to be defined for: -* The default log. -* The references to the SlingRepository and the JcrResourceResolverFactory services, which are used in the implementation. -* The destination paths of the files. +Some class fields need to be defined: - {code} - /** Default log. */ + #!java + /** Default log. */ protected final Logger log = LoggerFactory.getLogger(this.getClass()); - /** @scr.reference */ + @Reference private SlingRepository repository; - - /** - * @scr.reference - */ + + @Reference private JcrResourceResolverFactory resolverFactory; private final static String IMAGES_PATH = "/dropbox/images/"; @@ -148,8 +148,9 @@ Some class fields need to be defined for private final static String OTHER_PATH = "/dropbox/other/"; - The *org.osgi.service.event.EventHandler#handleEvent(Event event)* method needs to be implemented: +The **org.osgi.service.event.EventHandler#handleEvent(Event event)** method needs to be implemented: + #!java public void handleEvent(Event event) { if (EventUtil.isLocal(event)) { EventUtil.processJob(event, this); @@ -157,15 +158,18 @@ Some class fields need to be defined for } - The *org.apache.sling.event.JobProcessor#process(Event event)* method needs to be implemented. - - Its logic is as follows: - * The resource path is extracted from the job event property. - * The resource is obtained from the resource path. - * If the resource is a file, the destination path is defined based on the file MIME type. - * The file is moved to the new location. +The **org.apache.sling.event.JobProcessor#process(Event event)** method needs to be implemented. +Its logic is as follows: + +* The resource path is extracted from the job event property. +* The resource is obtained from the resource path. +* If the resource is a file, the destination path is defined based on the file MIME type. +* The file is moved to the new location. + +or in Java Code: + #!java public boolean process(Event event) { Session adminSession = null; try { @@ -206,4 +210,4 @@ Some class fields need to be defined for } - The complete code for the *DropBoxEventHandler* service is available [here|^DropBoxEventHandler.java]. +The complete code for the **DropBoxEventHandler** service is available [here](DropBoxEventHandler.java). Modified: sling/site/trunk/content/documentation/tutorials-how-tos/installing-and-upgrading-bundles.mdtext URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/installing-and-upgrading-bundles.mdtext?rev=1345850&r1=1345849&r2=1345850&view=diff ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/installing-and-upgrading-bundles.mdtext (original) +++ sling/site/trunk/content/documentation/tutorials-how-tos/installing-and-upgrading-bundles.mdtext Mon Jun 4 07:40:42 2012 @@ -1,10 +1,8 @@ Title: Installing and Upgrading Bundles Excerpt: Explains how to install, upgrade and uninstall Bundles using the Sling Management console. -# Installing and Upgrading Bundles - {note} -We recommend to use the Apache Felix Web Console. The documentation below describes the old Sling Management Console, which isn't in use any more. Please refer to the documentation of the [Apache Felix Web Console]({{ refs.http://felix.apache.org/site/apache-felix-web-console.html.path }}). +We recommend to use the Apache Felix Web Console. The documentation below describes the old Sling Management Console, which isn't in use any more. Please refer to the documentation of the [Apache Felix Web Console](http://felix.apache.org/site/apache-felix-web-console.html). {note} @@ -16,7 +14,7 @@ Basically, you have two choices to insta ## Sling Management Console -The Sling Management Console is installed by default when Sling is running and may be reached at on the page `/system/console` in the Sling Context by default. For example if you installed the Sling Web Application in the `/sample` context of the Servlet Container running at `http``://somehost:4402`, you would access the Sling Management Console at `http``://somehost:4402/sample/system/console`. +The Sling Management Console is installed by default when Sling is running and may be reached at on the page `/system/console` in the Sling Context by default. For example if you installed the Sling Web Application in the `/sample` context of the Servlet Container running at `http://somehost:4402`, you would access the Sling Management Console at `http://somehost:4402/sample/system/console`. You will be prompted for a user name and password to access the Sling Management Console. This password is preset to be *admin* for the user name and *admin* for the password. @@ -28,10 +26,10 @@ NB: Both the username and password and t To install a new bundle or upgrade an already installed bundle, go to the *Bundles* page in the Sling Management Console. At the top and the bottom of the page you have a form to specify and upload a bundle as a file : - * Select the bundle file to upload - * Click the *Start* checkbox, if you want to start the bundle after installation. If the bundle is upgraded, this checkbox is ignored. - * Specify the start level of the bundle in the *Start Level* field. This must be a number higher than 0 and is ignored for bundles, which are already installed. Most of the time, you will use the default value. - * Click the *Install or Update* button +* Select the bundle file to upload +* Click the *Start* checkbox, if you want to start the bundle after installation. If the bundle is upgraded, this checkbox is ignored. +* Specify the start level of the bundle in the *Start Level* field. This must be a number higher than 0 and is ignored for bundles, which are already installed. Most of the time, you will use the default value. +* Click the *Install or Update* button After clicking the button, the bundle file will be uploaded. If a bundle with the same bundle symbolic name is already installed, the respective bundle will be updated with the new bundle file. Otherwise the bundle file will be installed as a new bundle and its start level is set as defined. Additionally the bundle will optionally be started. @@ -70,8 +68,18 @@ There exists no GUI functionality yet to For example, if you run Sling on `http``://localhost:7402/sample` with default location of the Sling Management Console, the following request would add a repository at `/tmp/repo/repository.xml` in the filesystem: - + :::html http://localhost:7402/sample/system/console/bundlerepo?action=refreshOBR&repository=file:///tmp/repo/repository.xml +Some Java Sample: + + #!java + public class Test { + public static String x = ""; + public static void main(String[] args) { + int x = 0; + } + } + Note: Only use `file:` URLs if you know Sling has access to the named file ! Modified: sling/site/trunk/content/documentation/tutorials-how-tos/jackrabbit-persistence.mdtext URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/jackrabbit-persistence.mdtext?rev=1345850&r1=1345849&r2=1345850&view=diff ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/jackrabbit-persistence.mdtext (original) +++ sling/site/trunk/content/documentation/tutorials-how-tos/jackrabbit-persistence.mdtext Mon Jun 4 07:40:42 2012 @@ -18,20 +18,23 @@ When you are not using the Derby persist ## JDBC Driver -The hardest thing to do is probably getting the JDBC driver for your database. One option is to look at the bundles provided by Spring Source in their repository at [http://www.springsource.com/repository/](http://www.springsource.com/repository/). +The hardest thing to do is probably getting the JDBC driver for your database. One option is to look at the bundles provided by Spring Source in their repository at <http://www.springsource.com/repository/>. Another option is to create the bundle on your own using Peter Kriens' [BND Tool](http://www.aqute.biz/Code/Bnd): 1. Get the JDBC driver for your database from the driver provider -1. Wrap the JDBC driver library into an OSGi bundle: +1. Wrap the JDBC driver library into an OSGi bundle: - # Example for PostgreSQL JDBC 3 driver 8.4-701 - $ java -jar bnd.jar wrap postgresql-8.4-701.jdbc3.jar - $ mv postgresql-8.4-701.jdbc3.bar postgresql-8.4-701.jdbc3-bnd.jar + :::sh + # Example for PostgreSQL JDBC 3 driver 8.4-701 + $ java -jar bnd.jar wrap postgresql-8.4-701.jdbc3.jar + $ mv postgresql-8.4-701.jdbc3.bar postgresql-8.4-701.jdbc3-bnd.jar 1. Deploy the driver to your local Maven 2 Repository (Required if adding the JDBC driver to a Maven build, e.g. using the Sling Launchpad Plugin) - $ mvn install:install-file -DgroupId=postgresql -DartifactId=postgresql -Dversion=8.4.701.jdbc3 \ + :::sh + $ mvn install:install-file \ + -DgroupId=postgresql -DartifactId=postgresql -Dversion=8.4.701.jdbc3 \ -Dpackaging=jar -Dfile=postgresql-8.4-701.jdbc3-bnd.jar @@ -61,7 +64,7 @@ If the file already exists, you can modi For example to use PostgreSQL instead of Derby modify the `<PersistenceManager>` elements as follows: - + :::xml <Repository> ... <Workspace name="${wsp.name}"> Modified: sling/site/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.mdtext URL: http://svn.apache.org/viewvc/sling/site/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.mdtext?rev=1345850&r1=1345849&r2=1345850&view=diff ============================================================================== --- sling/site/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.mdtext (original) +++ sling/site/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.mdtext Mon Jun 4 07:40:42 2012 @@ -1,7 +1,5 @@ Title: Testing Sling-based applications -# Testing Sling-based applications - Automated testing of OSGi components and services can be challenging, as many of them depend on other services that must be present or simulated for testing. This page describes the various approaches that we use to test Sling itself, and introduces a number of tools that can help testing OSGi and HTTP-based applications. @@ -9,30 +7,34 @@ This page describes the various approach [TOC] ## Unit tests + When possible, unit tests are obviously the fastest executing ones, and it's easy to keep them close to the code that they're testing. We have quite a lot of those in Sling, the older use the JUnit3 TestCase base class, and later ones use JUnit4 annotations. Mixing both approaches is possible, there's no need to rewrite existing tests. ## Tests that use a JCR repository -Utility classes from our [commons/testing]({{ refs.https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing.path }}) module make it easy to get a real JCR repository for testing. That's a bit slower than pure unit tests, of course, but this only adds 1-2 seconds to the execution of a test suite. + +Utility classes from our [commons/testing](https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing) module make it easy to get a real JCR repository for testing. That's a bit slower than pure unit tests, of course, but this only adds 1-2 seconds to the execution of a test suite. The `RepositoryProviderTest` in that module uses this technique to get a JCR repository. Note that our utilities do not cleanup the repository between tests, so you must be careful about test isolation, for example by using unique paths for each test. ## Mock classes and services + The next step is to use mock classes and services to simulate components that are needed for testing. This makes it possible to test OSGi service classes without an OSGi framework. -We have a number of custom-written mock services in Sling, like [MockNodeType]({{ refs.https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/jcr/MockNodeType.java.path }}) for example. These handwritten mocks implement just what's needed for their tests, so they might not be reusable as is. +We have a number of custom-written mock services in Sling, like [MockNodeType](https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/jcr/MockNodeType.java) for example. These handwritten mocks implement just what's needed for their tests, so they might not be reusable as is. -In other cases we use [jmock]({{ refs.http://www.jmock.org/.path }}) to help create mock objects without having to write much code - such mocking libraries take care of the plumbing and allow you to write just the bits of code that matter (often with funny syntaxes). The tests of the [org.apache.sling.event|https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/event/] bundle, for example, make extensive use of such mock services. +In other cases we use [jmock](http://www.jmock.org/) to help create mock objects without having to write much code - such mocking libraries take care of the plumbing and allow you to write just the bits of code that matter (often with funny syntaxes). The tests of the [org.apache.sling.event](https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/event/) bundle, for example, make extensive use of such mock services. The problem with mocks is that it can become hard to make sure you're actually testing something, and not just "mocking mocks". At a certain level of complexity, it becomes quicker and clearer to actually start an OSGi framework for automated tests. ### Side note: injecting services in private fields + To inject (real or fake) services in others for testing, without having to create getters and setters just for this, we use a reflection-based trick, as in this example: -<DIV class="code panel" style="border-style: solid;border-width: 1px;"><DIV class="codeHeader panelHeader" style="border-bottom-width: 1px;border-bottom-style: solid;"><B>setting a private field via reflection</B></DIV><DIV class="codeContent panelContent"> + #!java // set resource resolver factory // in a ServletResolver object which has a private resourceResolverFactory field @@ -44,21 +46,24 @@ To inject (real or fake) services in oth ## Pax Exam -[Pax Exam]({{ refs.http://team.ops4j.org/wiki/display/paxexam/Pax+Exam.path }}) allows you to easily start an OSGi framework during execution of a JUnit test suite. -We currently use it for our [Sling installer integration tests]({{ refs.https://svn.apache.org/repos/asf/sling/trunk/installer/it.path }}) for example. As parts of the installer interact directly with the OSGi framework, it felt safer to test it in a realistic situation rather than mock everything. +[Pax Exam](http://team.ops4j.org/wiki/display/paxexam/Pax+Exam) allows you to easily start an OSGi framework during execution of a JUnit test suite. + +We currently use it for our [Sling installer integration tests](https://svn.apache.org/repos/asf/sling/trunk/installer/it) for example. As parts of the installer interact directly with the OSGi framework, it felt safer to test it in a realistic situation rather than mock everything. Such tests are obviously slower than plain unit tests and tests that use mocks. Our installer integration tests, using Pax Exam, take about a minute to execute on a 2010 macbook pro. ## Sling testing tools: server-side JUnit tests -The [Sling testing tools]({{ refs.slingxsite-sling-testing-tools.path }}) include a module that executes JUnit tests server-side, in a Sling instance. This allows integration tests to run in a realistic environment, and could also be used for self-testing production systems. -As I write this, we are not using those tools to test Sling itself, but we have a [complete example]({{ refs.https://svn.apache.org/repos/asf/sling/trunk/testing/samples/integration-tests.path }}) of integration tests that use them to run server-side JUnit tests, including automatic setup of the test Sling instance. +The [Sling testing tools]({{ refs.sling-testing-tools.path }}) include a module that executes JUnit tests server-side, in a Sling instance. This allows integration tests to run in a realistic environment, and could also be used for self-testing production systems. + +As I write this, we are not using those tools to test Sling itself, but we have a [complete example](https://svn.apache.org/repos/asf/sling/trunk/testing/samples/integration-tests) of integration tests that use them to run server-side JUnit tests, including automatic setup of the test Sling instance. ## HTTP-based integration tests + The highest level of integration is testing a complete Sling instance via its HTTP interface. -We use this technique to test Sling itself: the [launchpad/integration-tests]({{ refs.https://svn.apache.org/repos/asf/sling/trunk/launchpad/integration-tests.path }}) module defines the tests (462 of them as I write this), and the [launchpad/testing|https://svn.apache.org/repos/asf/sling/trunk/launchpad/testing] module executes them, after setting up a Sling instance from scratch (which is quite easy as Sling is just a runnable jar). +We use this technique to test Sling itself: the [launchpad/integration-tests](https://svn.apache.org/repos/asf/sling/trunk/launchpad/integration-tests) module defines the tests (462 of them as I write this), and the [launchpad/testing](https://svn.apache.org/repos/asf/sling/trunk/launchpad/testing) module executes them, after setting up a Sling instance from scratch (which is quite easy as Sling is just a runnable jar). A simple mechanism (described in README files in these modules) allows individual tests to be executed quickly against a previously started Sling instance, to be able to write and debug tests efficiently. @@ -67,4 +72,5 @@ The test code could be made simpler usin One problem with these launchpad tests is that the tests of all Sling modules are defined in a single testing module, they are not co-located with the code that they test. This could be improved by providing the tests in bundles that can be created from the same Maven modules that the code that they test. ## Summary + Combining the above testing techniques has worked well for us in creating and testing Sling. Being able to test things at different levels of integration has proved an efficient way to get good test coverage without having to write too much boring test code. \ No newline at end of file