Shooting rabbits with sling Introduction to Apache Jackrabbit & Apache Sling
JCR Content Repository API for Java JSR-170 & JSR-283 Object database 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: Can be multivalued string, binary, long, double, date, boolean, name, path, reference Can be multivalued Show examples here: CRXDE and Eclipse “Helloworld”
Searching Node names and properties are indexed Jackrabbit uses Apache Lucene Supported query languages: XPath JCR-SQL JCR-SQL2 (recommended)
SQL2 Main purpose: find node by property contents 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 Eclipse example Versioning
Observation Event listener We can filter events with: Usage examples: 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 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…
HTTP access to JCR repository 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> jug/hellocomponent
How does it work? /apps/jug/hellocomponent GET /content/home.html 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 resolution GET /content/corporate/jobs/developer.print.a4.html/mysuffix /content/corporate/jobs/developer/sling:resourceType = cognifide/hr/jobs /apps/cognifide/hr/jobs: jobs.print.a4.GET.html.esp jobs.print.a4.html.esp jobs.print.a4.esp jobs.print.GET.html.esp jobs.print.html.esp jobs.print.esp jobs.GET.html.esp jobs.html.esp jobs.GET.esp jobs.esp
Composed resources Page Left column Main <html> 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 Cons 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 Show CQ as demo – what page?
Q&A