All Projects → mfornos → cream

mfornos / cream

Licence: other
Java Content Repository module for Play! framework

Programming Languages

java
68154 projects - #9 most used programming language

Cream module

A module that seamlessly integrates Apache Jackrabbit (JCR 2.0) with Play framework.

Features

  • OCM
    • Uses jcrom as the underlying object-to-content mapper
  • Full text search
    • Indexing PDF, MS Word, Excel, PowerPoint, OpenOffice, RTF, HTML and XML
  • Content versioning
  • Repository observers
  • play.db.Model support
  • CRUD support
  • Data binding and validation

Installation

Install locally this module

$ play install cream-{version}

Declare the proper dependency in conf/dependencies.yml

require:
    - play -> cream {version}

and let Play download and install the dependencies

$ play deps

Usage

Configure Cream in conf/application.conf

## Cream module configuration
cream.jcr.url=file://tmp-repo
cream.jcr.username=admin
cream.jcr.password=admin
cream.jcr.workspace=default
# Path to your jackrabbit configuration.
# A default configuration will be used 
# if you don't specify any
#cream.jcr.configuration=conf/cream-repository.xml 

## Testing
%test.cream.jcr.mode=transient

Annotate your model classes and extend play.modules.cream.Model (not required but convenient). See jcrom and Play validation for further details.

@JcrNode(mixinTypes = { "mix:created", "mix:lastModified", "mix:referenceable" })
public class User extends Model {

    @JcrName // this is the node name
    @Required
    public String name; 

    @JcrProperty
    @Required
    @Email
    public String email;

    @JcrProperty
    @MinSize(5)
    public String password;
    
    ...
}

Note: model classes managed by Cream plugin must be annotated with @JcrNode (normally with at least mix:referenceable) but jcrom doesn’t require it.

You need to open a Jcr session in order to access the model from the controllers. To achieve it you have these options:

1) Do nothing, Cream automatically binds a session per invocation.

public class MyController extends Controller {
    ...
}

If you want to control session parameters (p.ex: the workspace), use @JcrSession

@JcrSession(workspace="myWorkspace")
public class MyController extends Controller {
    ...
}

2) Inject a session in the Controller with @Inject

public class MyController extends Controller {

    @Inject
    static javax.jcr.Session jcrSession;
    
    ...
}

3) Do it manually

public void someMethod() {
    Session session = JCR.getSession();
    try {
        ...
    } finally {
        session.logout();
    }
}

In some situations may be desirable that Cream didn’t open a Jcr session for the invocation, use @JcrNoSession for that effect

@JcrNoSession
public class MyController extends Controller {
    ...
}

An example of Controller

public class MyController extends Controller {
    
    ...
    
    public static void create(@Valid MyEntity entity) {
       if (validation.hasErrors()) {
            ...
       }
       
       entity.create();
       
       ...
    }
    
    public static void index(Integer page) {
        
        JcrQuery result = MyEntity.all();
        List<MyEntity> entities = result.fetch(page, pageSize);
        long totalNumOfEntities = result.count();
        
        
        ...
   }
   
   ...
}

Note: if you don’t specify a Jcr path for the entity, the simple class name will be used by default. If you need to save the entity in another path, set myEntity.path = “/mypath”.

See cream/samples-and-test for more examples.

To use Cream with CRUD simply do nothing special

public class Users extends CRUD {

}

You can use Fixtures normally for your tests and initial data loading.

Full Text Search

Jackrabbit is able to index binary content and text, of course. Jackrabbit text extractors

Full text search is achieved by the means of contains clause:

# 6.7.19 FullTextSearch (p 113)
select * from test where contains(name, 'hello -world')
select * from test where contains(name, $x)
select * from test as t where contains(t.*, 'hello -world')
select * from test as t where contains([t].name, 'hello -world')

Score:

# 6.7.31 FullTextSearchScore (p 122)
select * from test where score()>4
select * from test as x where score(x)<1

Result excerpts. Still not supported in Jackrabbit 2. However you can use the old syntax, for example:

// XXX see
// http://jackrabbit.510166.n4.nabble.com/Use-of-excerpt-with-SQL2-td3249018.html
// waiting for excerpt support with SQL-2
try {
    QueryManager qm = JCR.getQueryManager();
    @SuppressWarnings("deprecation")
    Query q = qm.createQuery(
             "select excerpt(.) from nt:unstructured where jcr:path like '/mypath/%' and contains(., '"
                    + search + "') order by jcr:score desc", Query.SQL);
    QueryResult result = q.execute();
    for (RowIterator it = result.getRows(); it.hasNext();) {
        Row r = it.nextRow();
        Value excerpt = r.getValue("rep:excerpt(.)");
        ...
    }
} catch (RepositoryException e) {
     Logger.error(e.getMessage(), e);
}

For a pragmatic reference of SQL-2 take a look at the official Jackrabbit tests: Jackrabbit SQL-2 tests

Repository Observers

To observe repository events create a class that implements javax.jcr.EventListener and annotate it with @JcrOnEvent. Cream will automatically register it for the current session.

@JcrOnEvent(eventTypes = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_CHANGED, absPath = "/", isDeep = true)
public class LoggingObserver implements EventListener {

    @Override
    public void onEvent(EventIterator events) {
        while (events.hasNext()) {
            Event event = events.nextEvent();
            Logger.info("JcrEvent received: { %s }", event.toString());
        }
    }
}

Content Versioning

Make sure that “mix:versionable” mixin is set on the @JcrNode annotation of your entity:

@JcrNode(mixinTypes = { "mix:created", "mix:lastModified", "mix:versionable" })
public class MyVersionableEntity extends Model {
   ...
}

The following properties are automatically available for your entity: String versionName, Date baseVersionCreated, Date versionCreated and boolean checkedout.

To obtain the version list for an instance of your versionable entity, make a call to myEntity.getVersions().

To restore a version: JcrVersionMapper.restoreVersionByUUID(yourEntityId, versionNameToRestore);

To delete a version: JcrVersionMapper.removeVersionByUUID(yourEntityId, versionName);

Have fun!

References

// and more to come…

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].