Shooting rabbits with sling Introduction to Apache Jackrabbit & Apache Sling

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)
SQL2
SELECT * FROM [cq:PageContent] AS s
WHERE 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?
/apps/jug/hellocomponent
• 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.)
• 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 resolution
GET /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.esp
2. jobs.print.a4.html.esp
3. jobs.print.a4.esp
4. jobs.print.GET.html.esp
5. jobs.print.html.esp
6. jobs.print.esp
7. jobs.GET.html.esp
8. jobs.html.esp
9. jobs.GET.esp
10. jobs.esp
Composed resources
Page
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
Left column
Article
list
Twitter
widget
Contact
info
<c:forEach var=“par” items=“${resource.children}”>
<sling:include
path=“${par.path}”
resourceType=“${par[‘sling:resourceType’]}”/>
</c:forEach>
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 usage
Resource 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 {
@Reference
private 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