Shooting rabbits with sling
Introduction to Apache Jackrabbit & Apache Sling
JCR
• Content Repository API for Java• JSR-170 & JSR-283• javax.jcr
• Object database• Hierarchical data model• Apache Jackrabbit – reference implementation
Mantra: everything is content
• Content is content– Blogs, articles, posts, etc.
• Structured data– List of addresses in e-mail database
• Unstructured data– Word document
• ACLs• Code
Content hierarchy
• JCR has tree-like data model• Repository consists of items• Item can be node or property• Node children are properties or other nodes• Properties are leaves
Node
• Nodes form content hierarchy• Nodes are named• Each node has primary type specifying it’s structure (allowed
and required children and properties)– Something like class– Eg. myapp:Contact requires properties myapp:givenName and myapp:familyName
• Nodes can also have mixin types– Something like interface– Eg. mix:versionable, mix:lockable or myapp:Emailable
• Popular types:– nt:base, nt:unstructured, nt:folder
Property
• Property contains data• Types:– string, binary, long, double, date, boolean, name,
path, reference• Can be multivalued
Searching
• Node names and properties are indexed• Jackrabbit uses Apache Lucene• Supported query languages:– XPath– JCR-SQL– JCR-SQL2 (recommended)
SQL2SELECT * FROM [cq:PageContent] AS sWHERE ISDESCENDANTNODE([/content])AND s.[jcr:title] = ’Moja strona’
• Main purpose: find node by property contents• Avoid queries with parent path (as it’s not
indexed)– It’s better to create a mixin or marker property
• We don’t JOIN• SQL and XPath are isomorphic
Versioning
• Any subtree can be versioned• Add mixin mix:versionable• node.checkin()– Creates new version– Makes the node read-only
• node.checkout()– Allows to modify the node
• Usage examples:– Page versions at many levels
Observation
• Event listener• We can filter events with:
– Event type– Path– Node types– An explicit list of nodes
• Usage examples:– Automatic workflows– Generating thumbnails– “Last modified” date– Indexing in internal and external search engine
Other features
• Locking• Access control– Users & groups– Groups can be members of other groups– Privileges on nodes to read, write, etc.
JCR – advantages and problems
• Advantages– Site structure is easy to reflect– Flexible– Hierarchical structure
• Disadvantages– Storing large amount of structured data is neither easy nor efficient
• Don’t load CSV file with 1 000 000 rows
– Data has to be denormalized (as there is no JOINs)– Clustering is tricky
• Master-slave works OK• Waiting for Jackrabbit 3.0 – codename Oak
– Transactions…
Apache Sling
HTTP access to JCR repository
Apache Sling
• Web framework• RESTful access to JCR nodes• Powered by OSGi• Support multiple scripting languages (JSP,
Groovy, …)• Open source, developed by Adobe within
Apache foundation
REST# Create / Update$ curl -u admin:admin –d name=“Java User Group” –d city=Poznan \localhost:8080/content/hello
# Read$ curl localhost:8080/content/hello.tidy.json
# Delete$ curl -X DELETE -u admin:admin \localhost:8080/content/hello
Resource URL
• Resource path: /content/hello– http://localhost:8080/content/hello.xml– http://localhost:8080/content/hello.json– http://localhost:8080/content/hello.html
• There are simple built-in renderers• Each can be overridden
sling:resourceType
• In order to create custom rendition we need to set sling:resourceType property
• It’s a JCR path to some renderer• Renderer can be JSP, Java Servlet, Scala,
Python, Groovy, Ruby or ESP (internal Sling language, kind of backend JS)
• Content-centric: you don’t invoke script directly
Sample HTML renderer<html><head><title>ESP example</title></head><body> <h1>Hello<%= currentNode.getProperty('name') %> </h1> <h2><%= currentNode.getProperty('city') %> </h2></body></html>
How does it work?
• Get node path from URL
• Get extension• Get HTTP method
GET /content/home.
html
• Find sling:resourceType
• Choose appropriate script (POST.jsp, json.jsp, etc.)
/apps/jug/hellocomponent • Render node using
found renderer and appropriate script
Hello JUG!
URL decomposition
/content/corporate/jobs/developer.print.a4.html/mysuffix
• Resource path• Selectors• Extension• Suffix
Resource path
/content/corporate/jobs/developer.print.a4.html/mysuffix
• Substring before the first dot• Path to the resource in JCR• This part of the URL defines data.
– Rest defines way of the presentation.
Extension
/content/corporate/jobs/developer.print.a4.html/mysuffix
• Defines content format• Most common: html, json, xml• But may be png
Selectors
/content/corporate/jobs/developer.print.a4.html/mysuffix
• Specifies additional variants of the given content type• Optional• Multiple selectors are allowed
Suffix
/content/corporate/jobs/developer.print.a4.html/mysuffix
• Additional information passed to the rendering script• Similar to GET ?name=value parameter, but can be cached
Script resolutionGET /content/corporate/jobs/developer.print.a4.html/mysuffix
/content/corporate/jobs/developer/sling:resourceType = cognifide/hr/jobs
/apps/cognifide/hr/jobs:1. jobs.print.a4.GET.html.esp2. jobs.print.a4.html.esp3. jobs.print.a4.esp4. jobs.print.GET.html.esp5. jobs.print.html.esp6. jobs.print.esp7. jobs.GET.html.esp8. jobs.html.esp9. jobs.GET.esp10. jobs.esp
Composed resourcesPage
title
Left column Main
<html><head><title><%= currentNode.getProperty(’title') %></title></head> <body><div class=“left_column”><sling:include path=“left” resourceType=“foundation/parsys”/></div><div class=“main”><sling:include path=“main” resourceType=“foundation/parsys”/><div></body></html>
Paragraph system<c:forEach var=“par” items=“${resource.children}”><sling:include path=“${par.path}” resourceType=“${par[‘sling:resourceType’]}”/></c:forEach>
Left column
Article list
Twitter widget
Contact info
Resource Resolver
• In JCR we had Node• In Sling we have Resource• Virtual tree of resources, reflecting the JCR• ResourceResolver – transforms nodes to resources• It’s possible to create own ResourceResolvers and reflect
other data sources– Filesystem,– MongoDB,– PostgreSQL
• Many ResourceResolvers may work together– Like mount in UNIX
Resolver usageResource res = resourceResolver.getResource(“/content/hello”);ModifiableValueMap map = res.adaptTo(ModifiableValueMap.class);String name = map.get(“name”, String.class);map.put(“name”, name.toUpperCase());resourceResolver.commit();
Node node = res.adaptTo(javax.jcr.Node);Session = resourceResolver.adaptTo(javax.jcr.Session);
Why do we use resolver?
• API is friendlier than JCR• Sling provides us resources and resolver in
many places– Servlets– Scripts
Servlets
• Like ordinary servlets but…• Can be assigned to:– Paths– Selectors– Extensions– Resource types (so can act as rendering script)
• doGet(), doPost() methods are invoked with– SlingHttpServletRequest and …Response– Additional methods for getting requested resource,
resolver, decompose URL, etc.
Sample Sling servlet@Component@Service@SlingServlet(resourceTypes = ”jug/hellocomponent”)public class AuthCheckerServlet extends SlingSafeMethodsServlet {
@Referenceprivate ResourceResolverFactory resolverFactory;
public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse
response) {response.getWriter().println(“Hello world”);
}}
Sling – pros and cons
• Similar to JCR• Pros– Natural reflection of site and filesystem structure
• Document repositories, Digital Asset Management
– OSGi stack– Javascript has easy access to repository
• Cons– Security issues
• internal resources available as xml and json,• handling user generated content
– Lack of free tools, eg. repo explorer
Q&A
Top Related