Rapid Development with Apache Sling using an IDE

Apache Sling allows you to use scripts to render your content. Usually these scripts are stored in the repository as specific path. While it is possible to directly edit a script in the repository (using WebDAV), this editing happens out of your project’s context. But fortunately there is a better way!
Usually your project consists of modules (or a single module) which are deployed as OSGi bundles. To get your scripts into the repository, you add the scripts as resources to your project and use the initial content feature from Apache Sling to add the scripts to the repository.
So you usually end up with your module (bundle) checked out in your IDE (Eclipse for example), you do your initial development here (develop your OSGi services and scripts). For testing purposes you deploy the bundle (using the Maven Sling Plugin) which copies your scripts into the repository. From here they get picked up by Sling. If you now edit your scripts directly in the repository you have to take care to synchronize the changes with your checked out project in your IDE which can be an error prone and annoying task. Or you can edit the scripts in your IDE and then either redeploy your bundle or manually copy the scripts via WebDAV – which doesn’t make the process easier.
Fortunately Sling provides some tooling which makes these extra steps obsolete – actually we have this feature for a long time now but I always forgot to write about it…of course the following is only interesting for you, if you’re using Maven for your project.
Now, imagine your scripts are for your own node types which use the namespace prefix “myapp”, so you have a “src/main/resources/SLING-INF/content” (this is a convention for initial content) directory in your project. This content directory now contains a sub directory “libs” (or “apps” or any other configured search path) with your scripts. Underneath “libs” you have the “myapp” folder with a folder for each node type and this folder contains then your scripts (it’s really easier than it is to describe in textual form).
You’ll add a configuration for the Maven Bundle Plugin for adding the initial content header to your pom.xml:

<Sling-Initial-Content>
SLING-INF/content/libs/myapp;overwrite:=true;path:=/libs/myapp
</Sling-Initial-Content>

This basically copies the contents of the “/libs/myapp” folder on bundle install into the repository at the same location. On each update the contents gets overwritten.
Now add the Maven Sling Plugin to your pom.xml:

<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<version>2.0.3-incubator-SNAPSHOT</version>
<executions>
<execution>
<id>install-bundle</id>
<goals>
<goal>validate</goal>
<goal>install</goal>
</goals>
<configuration>
<mountByFS>true</mountByFS>
</configuration>
</execution>
</executions>
</plugin>

In the configuration above you can spot to new features of the latest plugin version: the validate goal will validate all *.json files and more important for our topic, the configuration “mountByFS” with the value “true”. Apache Sling has an extension bundle called file system provider (aka fsresource) which allows you to mount a file system path into the resource tree. So basically you can point for example the Sling resource path /myphotos to some directory on your server containing photos. This allows you to directly use files with Sling without copying them into the repository. Once you have installed this bundle into Sling and use the above configuration, each time you build your bundle with Maven and do a “mvn install”, the Maven Sling plugin will create a fsresource configuration for your initial content. In our case the Sling resource path “/libs/myapp” points to the file system directory “/src/main/resources/SLING-INF/content/libs/myapp”. So once you’ve done an initial install of your bundle, you can directly change the scripts in your IDE in your project. And the changes get immediately active, no need to sync and no need to copy. This makes development turnarounds for scripting much shorter as there is no turnaround any more.
The whole thing comes with a little drawback – with the configuration from above, your build fails if no Sling instance is reachable. So you should use a Maven profile for this configuration.