Effective Web Application Development with Apache Sling Robert Munteanu ( @rombert ) , Adobe Systems Romania
About the Speaker ● Apache Sling PMC member ● Fanboy of the Sling/JCR/OSGi stack ● Enthusiastic Open-Source contributor ● Senior Computer Scientist at Adobe in Romania Speaker.currentSpeaker().interrupt(); 11/18/14 2
Presentation Flow ● Quick facts and figures ● Conceptual foundations ● Building blocks ● Building Sling applications 11/18/14 3
Quick facts and figures
Apache Sling - History 2007 incubation 2009 TLP 2014 Version 7 200x Pre-Apache 11/18/14 5
Apache Sling – High-level View of the Code Source: OpenHub 11/18/14 6
Apache Sling - Activity Level Source: OpenHub Source: status.apache.org 11/18/14 7
Conceptual Foundations
Apache Sling – Conceptual Foundations REST-based Content-driven OSGi-powered Apache Scripting inside 11/18/14 9
Apache Sling – Apache Open Source 4 Aries 1 ServiceMix 7 Commons 17 Felix 3 Geronimo 6 Jackrabbit 1 Derby 2 Tika 11/18/14 10
Apache Sling – REST-based /blog/{0}.html /blog/ / BlogViewController BlogListController HomeController / /blog /blog/hello-world SlingMainServlet 11/18/14 11
Apache Sling – Content-Driven blog hello-world jcr:content images some-cat.jpg other-cat.jpg 11/18/14 12
Apache Sling – Content-Driven some-cat.jpg - jcr:primaryType = app:asset - jcr:title = Some Cat - jcr:description = A longer description of this picture of a cat - jcr:created = 2014-06-03T00:00:00.000+02:00 - jcr:lastUpdated = 2014-06-03T11:00:00.000+02:00 - tags = [Animal, Cat, Color] - width = 400 - height = 600 11/18/14 13
Apache Sling – Scripting Inside JSP 11/18/14 14
Apache Sling – Scripting Inside libs blogapp welcome.jsp welcome json.html 11/18/14 15
Apache Sling – OSGi-powered ● Provision and deploy bundles ● Configure, register and lookup services ● Eventing ● Web Console 11/18/14 16
Building blocks
Apache Sling – Serving a request GET /blog/welcome.html ??? /blog/welcome myblog/blog.groovy 11/18/14 18
Apache Sling – Resource Types blog [blogapp/listing] hello-world jcr:content [blogapp/blog/content] images some-cat.jpg other-cat.jpg 11/18/14 19
Apache Sling – Script Resolution GET /blog.html Type: blogapp/listing Extension: html Method: GET /libs/blogapp/listing.jsp /libs/blogapp/listing/html.jsp @SlingServlet(resourceTypes=”blogapp/list ing”,...) 11/18/14 20
Apache Sling – Request Selectors GET /blog.rss.xml Type: blogapp/listing Extension: xml Selector: rss Method: GET /libs/blogapp/listing/rss.html 11/18/14 21
Apache Sling – Resource Providers JCR MongoDB / /content/ /content/comments /logs FS Cassandra 11/18/14 22
Apache Sling – JCR 11/18/14 23
Apache Sling – JCR implementations Apache Jackrabbit Oak 11/18/14 24
Building Sling Applications
Apache Sling – JCR modeling images some-cat.jpg File upload renditions small.jpg ripple.jpg Observation annotations initial-review ACLs 11/18/14 26
Apache Sling - JCR etc rendition ripple - orientation = /etc/rendition/ripple/options↵ /orientation/vertical - antialiasing = true - edges = /etc/rendition/ripple/options/↵ edges/wrap - wave type = /etc/rendition/ripple/options/↵ wave_type/simple - period = 20 - amplitude = 5 11/18/14 27
Apache Sling – Everything is a Resource Everything is a Resource 11/18/14 28
Apache Sling – Reading from the Repository @SlingServlet(resourceTypes = "blogapp/listing", extensions = "xml", methods = "GET") public class RSSFeedServlet extends SlingSafeMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { // actual implementation } } 11/18/14 29
Apache Sling – Reading from the Repository Resource res = request.getResource(); ValueMap properties = ↵ res.adaptTo(ValueMap.class); String title = properties.get(“jcr:title”,↵ “Missing”); Post post = res.adaptTo(Post.class); title = post.getTitle(); 11/18/14 30
Apache Sling - Extensions ● Thread Pools and Scheduled Tasks ● I18n ● Caching ● Models ● Health Checks ● Eventing 11/18/14 31
Apache Sling - SlingQuery Get the closest Folder parent $(resource).parents("sling:Folder").last(); Get the second child of each resource $(resource1, resource2).children(":eq(1)"); Find children named en or de $(resource).children("#en, #de") 11/18/14 32
Apache Sling - Deployment ● Single executable Jar or War file – the Sling launchpad ● Configuration defined in multiple text files, defining bundles, configuration, variables, bootstrap commands, etc 11/18/14 33
Apache Sling – Provisioning Model [feature name=main] [variables] io.version=1.4 [configurations] org.apache.jackrabbit.....SegmentNodeStoreService name="Default NodeStore" repository.home="sling/oak/repository" [artifacts startLevel=5] commons-io/commons-io/${io.version}/jar commons-fileupload/commons-fileupload/1.3.1/jar 11/18/14 34
Apache Sling - Tooling ● Maven Plugins ● Bundle deployment ● Launchpad creation ● Maven Archetypes ● IDE Tooling ● Eclipse ● Netbeans (external) 11/18/14 35
Resources ● http://sling.apache.org/ ● http://jackrabbit.apache.org/ 11/18/14 36

Effective Web Application Development with Apache Sling

  • 1.
    Effective Web Application Development with Apache Sling Robert Munteanu ( @rombert ) , Adobe Systems Romania
  • 2.
    About the Speaker ● Apache Sling PMC member ● Fanboy of the Sling/JCR/OSGi stack ● Enthusiastic Open-Source contributor ● Senior Computer Scientist at Adobe in Romania Speaker.currentSpeaker().interrupt(); 11/18/14 2
  • 3.
    Presentation Flow ●Quick facts and figures ● Conceptual foundations ● Building blocks ● Building Sling applications 11/18/14 3
  • 4.
  • 5.
    Apache Sling -History 2007 incubation 2009 TLP 2014 Version 7 200x Pre-Apache 11/18/14 5
  • 6.
    Apache Sling –High-level View of the Code Source: OpenHub 11/18/14 6
  • 7.
    Apache Sling -Activity Level Source: OpenHub Source: status.apache.org 11/18/14 7
  • 8.
  • 9.
    Apache Sling –Conceptual Foundations REST-based Content-driven OSGi-powered Apache Scripting inside 11/18/14 9
  • 10.
    Apache Sling –Apache Open Source 4 Aries 1 ServiceMix 7 Commons 17 Felix 3 Geronimo 6 Jackrabbit 1 Derby 2 Tika 11/18/14 10
  • 11.
    Apache Sling –REST-based /blog/{0}.html /blog/ / BlogViewController BlogListController HomeController / /blog /blog/hello-world SlingMainServlet 11/18/14 11
  • 12.
    Apache Sling –Content-Driven blog hello-world jcr:content images some-cat.jpg other-cat.jpg 11/18/14 12
  • 13.
    Apache Sling –Content-Driven some-cat.jpg - jcr:primaryType = app:asset - jcr:title = Some Cat - jcr:description = A longer description of this picture of a cat - jcr:created = 2014-06-03T00:00:00.000+02:00 - jcr:lastUpdated = 2014-06-03T11:00:00.000+02:00 - tags = [Animal, Cat, Color] - width = 400 - height = 600 11/18/14 13
  • 14.
    Apache Sling –Scripting Inside JSP 11/18/14 14
  • 15.
    Apache Sling –Scripting Inside libs blogapp welcome.jsp welcome json.html 11/18/14 15
  • 16.
    Apache Sling –OSGi-powered ● Provision and deploy bundles ● Configure, register and lookup services ● Eventing ● Web Console 11/18/14 16
  • 17.
  • 18.
    Apache Sling –Serving a request GET /blog/welcome.html ??? /blog/welcome myblog/blog.groovy 11/18/14 18
  • 19.
    Apache Sling –Resource Types blog [blogapp/listing] hello-world jcr:content [blogapp/blog/content] images some-cat.jpg other-cat.jpg 11/18/14 19
  • 20.
    Apache Sling –Script Resolution GET /blog.html Type: blogapp/listing Extension: html Method: GET /libs/blogapp/listing.jsp /libs/blogapp/listing/html.jsp @SlingServlet(resourceTypes=”blogapp/list ing”,...) 11/18/14 20
  • 21.
    Apache Sling –Request Selectors GET /blog.rss.xml Type: blogapp/listing Extension: xml Selector: rss Method: GET /libs/blogapp/listing/rss.html 11/18/14 21
  • 22.
    Apache Sling –Resource Providers JCR MongoDB / /content/ /content/comments /logs FS Cassandra 11/18/14 22
  • 23.
    Apache Sling –JCR 11/18/14 23
  • 24.
    Apache Sling –JCR implementations Apache Jackrabbit Oak 11/18/14 24
  • 25.
  • 26.
    Apache Sling –JCR modeling images some-cat.jpg File upload renditions small.jpg ripple.jpg Observation annotations initial-review ACLs 11/18/14 26
  • 27.
    Apache Sling -JCR etc rendition ripple - orientation = /etc/rendition/ripple/options↵ /orientation/vertical - antialiasing = true - edges = /etc/rendition/ripple/options/↵ edges/wrap - wave type = /etc/rendition/ripple/options/↵ wave_type/simple - period = 20 - amplitude = 5 11/18/14 27
  • 28.
    Apache Sling –Everything is a Resource Everything is a Resource 11/18/14 28
  • 29.
    Apache Sling –Reading from the Repository @SlingServlet(resourceTypes = "blogapp/listing", extensions = "xml", methods = "GET") public class RSSFeedServlet extends SlingSafeMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { // actual implementation } } 11/18/14 29
  • 30.
    Apache Sling –Reading from the Repository Resource res = request.getResource(); ValueMap properties = ↵ res.adaptTo(ValueMap.class); String title = properties.get(“jcr:title”,↵ “Missing”); Post post = res.adaptTo(Post.class); title = post.getTitle(); 11/18/14 30
  • 31.
    Apache Sling -Extensions ● Thread Pools and Scheduled Tasks ● I18n ● Caching ● Models ● Health Checks ● Eventing 11/18/14 31
  • 32.
    Apache Sling -SlingQuery Get the closest Folder parent $(resource).parents("sling:Folder").last(); Get the second child of each resource $(resource1, resource2).children(":eq(1)"); Find children named en or de $(resource).children("#en, #de") 11/18/14 32
  • 33.
    Apache Sling -Deployment ● Single executable Jar or War file – the Sling launchpad ● Configuration defined in multiple text files, defining bundles, configuration, variables, bootstrap commands, etc 11/18/14 33
  • 34.
    Apache Sling –Provisioning Model [feature name=main] [variables] io.version=1.4 [configurations] org.apache.jackrabbit.....SegmentNodeStoreService name="Default NodeStore" repository.home="sling/oak/repository" [artifacts startLevel=5] commons-io/commons-io/${io.version}/jar commons-fileupload/commons-fileupload/1.3.1/jar 11/18/14 34
  • 35.
    Apache Sling -Tooling ● Maven Plugins ● Bundle deployment ● Launchpad creation ● Maven Archetypes ● IDE Tooling ● Eclipse ● Netbeans (external) 11/18/14 35
  • 36.
    Resources ● http://sling.apache.org/ ● http://jackrabbit.apache.org/ 11/18/14 36

Editor's Notes

  • #2 Checklist - disable power management - connect remote control Good morning everyone and welcome to my presentation. My name is Robert Munteanu and for the next 50 minutes we'll be talking about Apache Sling and effective web application development.
  • #3 About me Apache Sling PMC And overall fanboy of the Sling/JCR/OSGi stack Enthusiastic open source contributor, love contributing to developer-oriented projects Eclipse plug-ins Maven plug-ins Bug trackers Development frameworks Working with Adobe in Romania Question "policy" Interrupt me at any time, I'm happy to talk about a subject more in depth AKA speaker.interrupt() How much do you know about Sling Worked with Apache Sling
  • #4 Web frameworks are like onions Have layers Make you cry Especially when you try to peel them Today I want to focus on the layering part :-) Layers of presentation Quick facts and figures about Sling Conceptual foundations of Sling AKA what makes Sling special and worth using Building blocks of Sling AKA core mechanisms through which the conceptual foundations are realized Building Sling applications AKA how do I get my stuff done with Sling
  • #6 History Developed internally at Day Software (now part of Adobe ) Entered the Apache Incubator in 2007 Graduated as a TLP in 2009 Had its 7th release in 2014
  • #7 Bird's eye view of the code Here's a bird's eye view of the code according to OpenHub Built on Java, and apparently a lot of Maven files :-) Increasing rate of contributions and (not immediately visible) increasing number of contributors
  • #8 Rate of contributions at Apache Also a couple of screenshots from OpenHub and status.apache.org Sling is one of the most active ASF projects using Subversion - at least when I took that screenshot :-)
  • #10 These are the 'official' concepts that underly Sling usage and development ; but I'll add one on top, which is not necessarily declared but really comes out as obvious when you start working with Sling Simplicity
  • #11 Apache We don't reinvent the wheel Rather, we make use of a lot of code from other Apache projects I've taken a look at the latest Sling release and counted how many bundles ( or jars ) we have from other Apache Projects You can see the numbers and various projects That's 41/108 for roughly 38% of bundles
  • #12 With a typical web development framework the approach you have is to map various controllers or handlers or whatever at certain paths, which are then served by your application For instance, you have a / handler for the home page, a /blog handler for the blog list and /blog/{0}.html for the individual blogs You're not actually defining a resource space and there's a mismatch between your data model and the resources that you expose The difference with what you do with Apache Sling - and this might seem academic at first , but it makes a huge difference - is that you define the URL space that you serve based on the resources that are contained in your repository So your data model (or your content) actually defines the URL space that your application handles And I'm going to get to Resources and Repository in just a minute
  • #13 Apache Sling provides a repository abstraction You don't ( well, you can, but you don't want to ) work with a specific Data model or persistence API You work with the Sling Repository abstraction And a repository is basically a set of resources arranged in tree format Resources have a name and optional properties Resources can have children All resources except the root have parents Resources are uniquely identifed by their path Interesting point to remember, since there are no numerical ids or UUIDs in Sling ; all references are/should be done by path
  • #14 What does a resource look like? A piece of content, really It must have a name It can (and in practice, always has) have properties Single or multi-valued Of various types - String, Numeric, Date, URL, Binary (typically for files)
  • #15 We have built-in adapters for lots of Scripting engines JSP Server-side Javascript Scala Groovy Ruby (via JRuby) Sightly Which interesting enough is a scripting engine built with Sling in mind And it's trivial to write your own adapter Groovy for instance is 20 lines of code in 2 classes
  • #16 And to add a second meaning to the 'Scripting Inside' concept, scripts live inside the repository Scripts are resources as any other - remember that we discussed that resources can be files Those are some sample scripts living under the /libs directory, which by convention is one of the default location for scripts
  • #17 You probably noticed that we use bundles from Apache Felix from one of the first slides, so that's what we use as an OSGi runtime Sling is built as a collection of bundles - 108 for the Sling 7 release We make heavy use of OSGi services We use those internally, obviously We make extension points available as interfaces In turn clients register implementations of those services as OSGi components and we pick them up For instance that's how you register a new Scripting Engine We also make use of the Event Admin to fire off in case of 'interesting' events We include the Web Console by default and also provide some pages for it But the key points for this are provisioning using bundles and use of OSGi services
  • #19 Coming back a bit to our blog example, let's assume that I have a request for /blog/welcome.html I have a groovy script ( because my blog is so groovy ) which I want to serve the request with How do I do that? Or in Sling vocabulary, how do I resolve the script that I want to serve my request with? It would seem to me that we need to differentiate between various resources. Most likely I want to use a different script for serving a blog page than for my contact page and - why not - for serving an image file.
  • #20 Resource Types For precisely this reason we have a special property indicating the resource type Every resource can have a resource type property It is used to indicate how this resource should be rendered Or rather more generally, how requests to this resource should be handled In this example I've put into square brackets some example resource types You'll notice that there is a form of namespacing, using the '/' character That's intentional, since resource types will get used as relative paths used in script resolution Which finally leads us to...
  • #21 When a request for a resource comes in, the Sling engine tries to infer as much information as possible to help with picking a script to resolve it with In our case, we can infer the resource path, and therefore the resource type We also know the extension and the HTTP method Depending on what scripts we have in the repository, the result of the resolution can be something like this /libs/blogapp/listing.jsp I mentioned /libs before - it's part of the default search path for scripts and the blogapp/listing part is part of the sling:resourceType property So this is the most generic script - just based on the resource type /libs/blogapp/listing/html.jsp However, much like CSS selectors are evaluated and the rules in the most specific selector apply, more specific scripts 'win' over less specific ones In our case, this script also takes into account the extension @SlingServlet And as a general note, wherever a script can participate in resolution, a Servlet can as well A Sling servlet is just an OSGi component, implementing a specific service interface, registered with certain properties Basically any property that can be used in script resolution can also be used when registering Servlets
  • #22 /blog.rss.xml Here's a twist - sometimes you want to represent the same resource in multiple ways, but with the same extension Sling provides a mechanism called 'selectors'. Again, sounds similar to concepts from CSS In this example the selector is 'rss', basically whatever comes between the resource path and the extension So the parameters for script resolution would be Resource type Extension Selector Method And the script resolved would be /libs/blogapp/listing/rss.html
  • #23 We've talked a lot about resources and repositories, but really tip-toped around the idea of how a repository is implemented Unsurprisingly, a Repository is an OSGi service, and can have multiple implementations We have four 'real' ResourceProvider implementations in the Sling codebase JCR Mandatory provider, Sling does not run without it Surprisingly, it is a hierarchical persistence mechanism which looks a lot like the repository abstraction we've been discussing and support all of the mechanims we've been discussing. We'll see a bit more about JCR later in the presentation MongoDB Filesystem Cassandra My impression is that the JCR and MongoDB ones see the most real-world usage What's cool about ResourceProviders is that they can easily live side-by-side If you want to have your repository root handled by JCR and then other paths handled by other providers, it works just fine
  • #24 With that, I'd like to discuss a bit about JCR, since it's crucial to understand that when working with Apache Sling JCR is a specification and a Java API Although there's a PHP bridge as well It is designed for applications which rely heavily on content and has a rich feature set, taking ideas from databases, filesystems, and adding some other niceties on the way Database Run queries against the repository SQL XPath Can participate in transactions Structure/integrity rules by using node types Much like table definitions listing what properties a node accepts Filesystem Structured in a hierarchical manner We've seen this throughout the presentation Access control Defines ACLs at user and group level Streams/binaries Transparent and optimised storage of binaries, with many nice features like binary deduplication and dedicated store for binaries, separated from the 'regular' content Locking And also Unstructured data Sometimes you simply want to define properties on a resource/node Easier to evolve/iterate Faster to start with And you probably don't need the constraints anyway Versioning Observation In-process notifications of changes happening in the repository
  • #25 We now support 2 JCR implementations in Apache Sling Both coming from the Apache Jackrabbit project Jackrabbit ( aka Jackrabbit 2.x ) Reference implementation of the standard Oak ( sometimes known as Jackrabbit 3.x ) Complete rewrite, based on modern principles and designed for today's scalability and concurrency requirements However, Oak is not supported in the latest release, it's only active in the development snapshots
  • #27 JCR modeling #1 At this point I like to start discussing how the content for a JCR/Sling application would look like Assume that we have a collaboration platform for images where people upload images and then discuss based on them The first steps is that someone uploads an image Obviously cat pictures are a hot topic Then, through JCR observation, renditions are created Renditions are derived images, in our scenario a thumbnail and some horribly transformed image, e.g. for uploading on Instagram The next step is to start a conversation about that Now, assuming that we want these discussion private, or at least not visible to anonymous users, we can use ACLs to protect that node This deserves a bit of a wider discussion, since ACLs and security are handled differently in Sling/JCR when compared to other stacks Typically applications connect to an identity provider, which can be as simple as an SQL table or a LDAP server or as complicated as OAuth Then typically security is enforced at application level, ideally in a declarative manner, and connection to the data source is done through a technical user More paranoid applications have multiple technical users, like a read-only and a read-write user. But even though it's more secure, it's cumbersome and I have rarely seen it done in practice By contrast, the Sling/JCR stack has a single source for Authentication and Authorization - the repository. This means that users are not technical users, they are instead actual users which exist in the repository. And also ACLs are defined at the repository level, so there is no way around them. This eliminates a whole class of security vulnerabilities and also makes it easier to reason about the security guarantees. Another point to note is that all data related to the image is stored under the image node. This means that moving and deleting that data is done in a single operations, with consistency being ensured at all times.
  • #28 So here's another crazy idea We've seen binaries stored in the repository We've seen scripts stored in the repository Why not store configuration data in the repository? Let's see how that would look like For /etc/rendition/ripple we have a few properties Some of them are simple numeric or boolean types But other look like repository paths, so let's explore them a bit orientation points to /etc/rendition/ripple/options/orientation/vertical So the actual definition of the vertical orientation is found at that path in the repository Even more, all possible values for the orientation property are defined there, so it makes building UIs or exporting those pieces of information into other systems dead-simple
  • #29 This leads me to what we call the Sling mantra – Everything is a resource. We've seen that – Scripts, application content, binary files, configurations. Even OSGi bundles are typically deployed as files in the repository. So when designing your Sling application, try to let go of the filesystem, System properties, properties files and other foreign mechanisms and place everything in the repository. You will at least get for free ACLs, a unified way of accessing data, change notifications and unified import and export.
  • #30 Let's take a look at how I would handle reading a data from the repository inside a Sling servlet Scripts are more or less the same, but Servlets are more compact for this scenario This is what a servlet 'boilerplate' looks like. You create a class which extends SlingSafeMethodsServlet and override the doGet method. The @SlingServlet annotation is here to make sure that our build tooling generates the needed OSGi configuration files for this class to be picked up as a Servlet by the sling runtime. In general, we try hard to delegate the error-prone tasks, like hand-crafting OSGi manifests or declarative services files to tooling and usage of OSGi is transparent.
  • #31 Let's take a look at how I would handle reading a data from the repository inside a Sling servlet Scripts are more or less the same, but Servlets are more compact for this scenario First of all, the request object is a SlingHttpServletRequest object, which extends the default HttpServletRequest interface with a couple of methods Here we see that we can invoke getResource() This method returns the resource which has been requested Remember that requests are most of the time bound to resources, and not arbitrary paths. So we have the data from the repository easily accessible in one call Sometimes the resources are simple and we're happy to get a couple of well-known properties from it For that we use the adaptable mechanism The root idea behind adapting is that we can transform a resource - and anything that implements the Adaptable interface - into arbitrary objects This is of course done by registering an OSGi service which handles the transformation This is one of the default implementations - getting a ValueMap Basically a Map which allows you to access all the object's properties But you can also plug your own if it suits your application design. And no more DAOs and Services and security checks, just adapt to the object that you want to get and that's it
  • #32 Extensions We have a large number of extensions which can be used with Sling, like Eventing, Thread pools, scheduled tasks, i18n, etc The SlingQuery one is quite fun and I'd like to show you a couple of examples
  • #33 SlingQuery! A query API modeled after the jQuery API which works on the resource level Here are a couple of examples of how queries can look like Usually much more concise that writing the data access code by hand
  • #34 The jar file is started by double-clicking and it starts executing. It embeds the Felix HTTP Service Jetty implementation The war file is - as expected - deployed to a servlet container Both jar and war when first executed unpack the whole application, including a JCR repository. So there's nothing to configure and you have a whole application ready to go in under a minute
  • #35 Provisioning model Simple text files, containing bundles, configurations, settings, variables Composable, multiple such text files - or features - can be aggregated to build an application
  • #36 Maven plugins Bundle deployment Java modules are OSGi bundles, so we use whatever is available for a given tool. For Maven we have the maven-bundle-plugin, but of course you can use any other build tool to assemeble the OSGi bundles. We provide a Maven plugin to deploy those bundles into a running Sling instance Launchpad creation A maven plugin that takes a list of features and produces a runnable jar/war Maven Archetypes Aid with creation of OSGi bundles or launchpads IDE Tooling Eclipse Developed under the Sling project Netbeans 2 implementations, both developed outside the Sling project