Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/twcable/jackalope

An in-memory implementation of the JCR with stubbing capabilities for Apache Sling
https://github.com/twcable/jackalope

Last synced: about 1 month ago
JSON representation

An in-memory implementation of the JCR with stubbing capabilities for Apache Sling

Awesome Lists containing this project

README

        

![Jackalope](jackalope.png)

[![Build Status](https://travis-ci.org/TWCable/jackalope.svg?branch=master)](https://travis-ci.org/TWCable/jackalope)

[ ![Download](https://api.bintray.com/packages/twcable/aem/jackalope/images/download.svg) ](https://bintray.com/twcable/aem/jackalope/_latestVersion)

## PURPOSE

Jackalope is an in-memory implementation of the JCR with stubbing capabilities for Apache Sling.

The goal of Jackalope is to better enable unit testing JCR representations of complex objects structures.
Java objects can normally be simply represented in the JCR as nodes with properties.

Simple mocking of the underlying JCR and Sling interfaces *can* be used to unit test reading and writing
these kinds of objects. However, when object aggregations like Sling component structures need to be
represented, the inability of simple mock objects to manage state become a real limitation.

The obvious solution is to use a JCR implementation that uses memory as its storage. There are, in fact, memory-based JCR implementations -- including one that is distributed with the Jackrabbit project. (Jackrabbit is the reference implementation for the JCR JSR.) All of these, however, require far too much in setup and resources to be useful for unit testing. They are designed to be long running, multi-threaded processes.

Our solution to this problem is to develop a simple and fast JCR implementation that can be used in unit tests.
It does not implement the complete JCR spec, but just the parts that we've needed, including the basic facilities for reading and writing repository workspaces.

There is another great project from [Citytech called Prosper](https://github.com/Citytechinc/prosper), which was released after Jackalope was written internally at Time Warner Cable. Each project has its own set of features, but the *primary* difference between Jackalope and Prosper is that Prosper uses Groovy string-based metaprogramming for building its trees, which has all the advantages and disadvantages of a fully dynamic API. Choose the one that best your needs/style: Choice is good. :-)

## Versions

The 3.x line targets AEM 6.x, whereas the 2.x versions target AEM 5.6.

Versioning follows the [Semantic Versioning standard](http://semver.org/)

## Packages

The library is composed of 3 main packages.

### Builder (com.twcable.jackalope)

This is the primary interface that should be used by clients of the library.
The `JCRBuilder` class contains factory methods that can be used to create a virtual repository for use in test cases.

To bring this class's methods in, typically you would do:
```groovy
import static JCRBuilder.repostory
import static JCRBuilder.node
import static JCRBuilder.property
```

### Sling Implementation (com.twcable.jackalope.sling)

This package contains the classes that implement the primary Sling API classes like `Resource` and `ResourceResolver`.
Users may want to use `SimpleResourceResolverFactory` to inject into services and servlets.

### JCR Implementation (com.twcable.jackalope.jcr)

This package contains the classes that implement the primary JCR API classes like `Node` and `Property`.

## Examples

### Building and using a partial repository

```groovy
given:
def repository = repository(
node("content",
node("test1",
node("callingrates",
node("intl-direct-dial",
property("sling:resourceType", "admin/components/content/callingratetable"),
node("france",
property("sling:resourceType", "admin/components/content/callingrate"),
property("additional-minute-rate", "0.60"))))))).build()
def resolver = new SimpleResourceResolverFactory(repository).administrativeResourceResolver
def resource = resolver.getResource("/content/test1/callingrates/intl-direct-dial")

when:
def callingRateTable = new CallingRateTable(resource)

then:
callingRateTable.getRate("france")
callingRateTable.getRate("france").additionalMinuteRate == "0.60"
```

The resource resolver factory can be used to test servlets and services by injection.

```groovy
def repository = repository(
node("content",
node("test1",
node("callingrates",
node("intl-direct-dial",
property("sling:resourceType", "admin/components/content/callingratetable"),
node("france",
property("sling:resourceType", "admin/components/content/callingrate"),
property("additional-minute-rate", "0.60"))))))).build()
def servlet = new CallingRatesImportServlet(new SimpleResourceResolverFactory(repository))
```

### Building and using a node tree

Some classes are designed to read and write node trees and do not require the full repository
implementation. These classes can build and use nodes directly.

```groovy
def node = node("content",
node("test1",
node("callingrates",
node("intl-direct-dial",
property("sling:resourceType", "admin/components/content/callingratetable"),
node("france",
property("sling:resourceType", "admin/components/content/callingrate"),
property("additional-minute-rate", "0.60"))))))).build()
```

### Returning a query result

Queries are also supported. A JCRQueryBuilder is used to create a query manager that associates queries
with fixed result sets that can be used for testing.

```groovy
def node = node("result").build()
JCRQueryBuilder.queryManager(node.session, query("query", "language", result(node))).build()

when:
def queryResult = node.session.workspace.queryManager.createQuery("query", "language").execute()

then:
queryResult.nodes.hasNext()

when:
def results = Lists.newArrayList(queryResult.nodes)

then:
results[0] == node
```

## BUILDING

Jackalope uses gradle as its build system:

`./gradlew build`

# Including In Your Build

[ ![Download](https://api.bintray.com/packages/twcable/aem/jackalope/images/download.svg) ](https://bintray.com/twcable/aem/jackalope/_latestVersion)

Jackalope can be used by including the following in your
build files (assuming Gradle):

```groovy
repositories {
maven {
url "http://dl.bintray.com/twcable/aem"
}
}

testCompile 'com.twcable.jackalope:jackalope:3.0.2'
```

# Releasing

For the developers of Jackalope, please read [the documentation for creating and releasing a new version](docs/RELEASING.adoc).

# LICENSE

Copyright 2015 Time Warner Cable, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the License.