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