Apache Sling

Apache Sling is a content-centric web application framework:

  • Built around RESTful principles, embraces the web
  • Uses JCR for content storage — or other data sources via Resource Providers
  • Supports Scripts (JSR 223) or Servlets for processing
  • Highly modular and based on OSGi
  • Healthy community: >30 Committers (mostly from Adobe and other companies)
  • >300 modules on GitHub

Started as internal project at Day Software, Apache Incubator project since 2007, top-level project since 2009.

REST Principles

REST stands for "REpresentational State Transfer" — an architectural style for distributed systems defined in 2000 by Roy Fielding.

  • A Resource can be anything (but has to be addressable)
  • Resources are independent from their representation — a web page is not a resource, it's a representation of one
  • An URL identifies a resource — URLs have an implicit hierarchy
  • Methods perform operations on resources (GET, POST, PUT, DELETE…) — operation is not part of the URL
  • HTTP status codes indicate result success

Benefits: Performance, Scalability, Simplicity, Modifiability, Cacheability.

Sling Uses RESTful URLs

Un-RESTful URL in "traditional" apps:

/schedule.jsp?event=1&year=2015&id=1&format=JSON

RESTful URLs in Sling:

/conference/2015/day1/rookie-session.json
/conference/2015/day1/rookie-session.xml

URL addresses a Resource, not a script. Representation selection via extension.

cURL — Write Data to Repository

# Create a node at /content/mynode with two properties
curl -u admin:admin 
  -F"sling:resourceType=matrix/sentinel" 
  -F"title=Sentinel Outpost" 
  http://localhost:8080/content/mynode

# This HTTP POST is intercepted by the default Sling POST Servlet.
# Authentication required to get write access.

cURL — Read Data from Repository

// HTTP GET with JSON extension:
// http://localhost:8080/content/mynode.json

{
  "jcr:primaryType": "sling:Folder",
  "jcr:createdBy": "admin",
  "jcr:created": "Thu Nov 26 2015 11:22:39 GMT+0100",
  "title": "Sentinel Outpost",
  "sling:resourceType": "matrix/sentinel"
}

// Node type automatically chosen by Sling
// Alternative in XML: http://localhost:8080/content/mynode.xml

Upload a Render Script

# HTTP POST: Create two folders
curl -u admin:admin -F"jcr:primaryType=sling:Folder" http://localhost:8080/apps/matrix
curl -u admin:admin -F"jcr:primaryType=sling:Folder" http://localhost:8080/apps/matrix/sentinel

# HTTP PUT: Upload the script
curl -u admin:admin -T sentinel.html http://localhost:8080/apps/matrix/sentinel/sentinel.html

# Content of sentinel.html (HTL):
# <h1>Hello World!</h1>
# <p>${properties.title}</p>

# Now GET http://localhost:8080/content/mynode.html
# Sling detects the script via script resolution and renders it

Resources and Resource Types

Resources are typed. A "content" resource has a sling:resourceType property pointing to the Sling component containing script(s) to render the resource.

  • Resource type is a repository path (can be relative to script search paths)
  • Resource type is optional if the resource is just used for storage
  • Sling components are resources as well — containing scripts rather than content
  • With sling:resourceSuperType you can build hierarchies of resource types for generalization in script resolution

Resource Providers

A resource provider maps the resource hierarchy to a storage system. Default: JCR resource provider.

Multiple resource providers are mapped to the same resource tree. There is no concept for multiple workspaces or repositories in Sling.

Example: Main resource provider is JCR with Jackrabbit Oak. On path /content/usergenerated a different resource provider is mounted — all read/writes there go to a different store, everything else goes to JCR.

Sling GET Servlet

If no custom script or servlet is in place, all GET requests are handled by the standard GET servlet:

  • .html/.xml/.txt — dump resource data as HTML, XML or plain text
  • .json — dump resource data as JSON
  • .<level>.json — include child resources (e.g. .5.json = 5 levels, .infinity.json = all levels)
  • .tidy.<level>.json — formatted JSON output

Important: Configure in Felix console to switch off some/all of these features on production instances!

Sling POST Servlet

Supports writing data back to repository without custom code:

  • Creating or updating resources — maps POST parameters to property names
  • Control data types (Number, Boolean, Date)
  • Delete, Move, Copy, Import, Checkin, Checkout content

Access Restrictions

All access to the repository is subject to access restrictions:

  • Sling Launchpad: Read access to all resources, write access to none
  • If more access is needed, the user must authenticate with credentials authorized with proper access rights
  • JCR allows very fine-grained control of access rights on path level
  • All default servlets, custom scripts/servlets, and every access via the Sling API respects the ACLs

Sling Initial Content

Sling provides support for initial content to be deployed with bundles, installed when the bundle is started. Declared with the Sling-Initial-Content bundle header.

  • Files & Folders: directly mapped to nt:folder and nt:file nodes in JCR
  • XML: XML file containing JCR data structures
  • JSON: JSON file containing JCR data structures (best option — XML has problems with multi-valued properties)

Sling Initial Content — Bundle Header

<plugin>
  <groupId>biz.aQute.bnd</groupId>
  <artifactId>bnd-maven-plugin</artifactId>
  <configuration>
    <bnd>
      <!-- include application path as initial content -->
      Sling-Initial-Content: 
        SLING-INF/app-root;overwrite:=true;ignoreImportProviders:=xml;path:=/apps/myapp
    </bnd>
  </configuration>
</plugin>

<!-- Imports content from SLING-INF/app-root in the JAR to /apps/myapp -->

Sling API

Additionally to the REST interfaces, Sling provides a Java API used by OSGi components and scripts on the server-side:

  • The Sling API extends the Servlet API to provide Sling-specific and resource-related features (e.g. URL decomposition)
  • The Sling Resource API provides read/write operations to manage the resource hierarchy, transparent from the underlying resource providers
  • Entry points for customizing resource handling, authentication, security and helper functions

Sling Request Processing

Sling takes a unique approach: a request URL is first resolved to a resource, then based on the resource it selects the servlet or script to handle the request.

The request handling can be further customized by:

  • Applying servlet filters
  • Applying Sling Mapping for "SEO-friendly short URLs"
  • Using the "Recent Requests" Felix Web Console plugin to debug request processing

Sling Launchpad

Sling uses a very thin launcher to run Sling and OSGi: the Launchpad. May be launched as a standalone application or as a Web Application (WAR).

Created using the Sling Feature Model — a collection of OSGi Bundle references and configurations. Makes it easy to build own application starters with all required bundles and configuration flexibility.