Java Hooks and Methods

Cordra supports writing lifecycle hooks and type methods entirely in Java. This may be of benefit not simply for language preference reasons, for example if have a need for a multi-threaded background process or if you need to integrate with existing code that is written in Java.

The cordra-hooks-support library can be included in your Gradle or Maven build files.

Gradle:

compile group: 'net.cnri.cordra', name: 'cordra-hooks-support', version: '2.5.0'

Maven:

<dependency>
    <groupId>net.cnri.cordra</groupId>
    <artifactId>cordra-hooks-support</artifactId>
    <version>2.5.0</version>
</dependency>

Lifecycle Hooks

To implement lifecycle hooks in Java create a new class that implements CordraTypeInterface. This interface contains no-op default methods so you need only override those methods that you wish to implement.

@CordraType("Foo")
public class FooCordraType implements CordraTypeInterface {

}

Note that this class is annotated with the annotation @CordraType which has an element (optionally called name; if both are specified name takes precedence over value). The @CordraType indicates to Cordra that this class should be loaded and the annotation element indicates which Cordra type to associate it with. In this example if you had a Cordra type called “Foo” any lifecycle hooks implemented in this class would be used for objects of type Foo. The class name FooCordraType is used for the Cordra type name if the annotation element is omitted, and is otherwise irrelevant.

@CordraType("Foo")
public class FooCordraType implements CordraTypeInterface {

    @Override
    public CordraObject beforeSchemaValidation(CordraObject obj, HooksContext context) throws CordraException {
        obj.content.getAsJsonObject().addProperty("name", "added example property");
        return obj;
    }
}

The above example demonstrates implementing the beforeSchemaValidation lifecycle hook. Here the hook is adding a new property “name” to the content of the object. The parameter CordraObject obj has the same interface as the Java Cordra client library. See Cordra HTTP REST Client Library - Java Version for examples of using CordraObject. After making changes to the CordraObject, return it to end the hook.

All of the supported lifecycle hooks with their signatures are shown below:

DefaultAcls getAuthConfig(HooksContext context) throws CordraException {
    return null;
}

CordraObject beforeSchemaValidation(CordraObject obj, HooksContext context) throws CordraException {
    return obj;
}

CordraObject beforeSchemaValidationWithId(CordraObject obj, HooksContext context) throws CordraException {
    return obj;
}

CordraObject onObjectResolution(CordraObject obj, HooksContext context) throws CordraException {
    return obj;
}

void onPayloadResolution(CordraObject co, HooksContext context) throws CordraException {}

CordraObject objectForIndexing(CordraObject obj, HooksContext context) throws CordraException {
    return obj;
}

void beforeStorage(CordraObject co, HooksContext context) throws CordraException {}

void afterCreateOrUpdate(CordraObject co, HooksContext context) throws CordraException {}

void beforeDelete(CordraObject co, HooksContext context) throws CordraException {}

void afterDelete(CordraObject co, HooksContext context) throws CordraException {}

void onUnload() throws CordraException {}

Note that there is an additional onUnload method you can override. This is called when Cordra unloads the class, for example if you update the java payload containing the jar file with a newer version. You might choose to use it if you need to stop any background processes.

Service-Level Lifecycle Hooks

Some lifecycle hooks are at the service level rather than related to a particular type. To implement those in Java create a class the implements CordraServiceHooksInterface and give it the annotation @CordraServiceHooks:

@CordraServiceHooks
public class DesignCordraType implements CordraServiceHooksInterface {

}

All of the supported service-level lifecycle hooks with their signatures are shown below:

default List<HandleValue> createHandleValues(CordraObject co, HooksContext context) {
    return null;
}

default String customizeQuery(String query, HooksContext context) {
    return query;
}

default SearchRequest customizeQueryAndParams(SearchRequest queryAndParams, HooksContext context) {
    return queryAndParams;
}

default AuthenticationResult authenticate(RequestAuthenticationInfo authInfo, HooksContext context) {
    return null;
}

If the service-level hooks also implement CordraTypeInterface, those hooks will be global defaults that apply to all objects except where the object’s particular type overrides the hook.

Type Methods

Type methods, both instance and static, can also be implemented in Java.

@CordraType("Bar")
public class BarCordraType {

    @CordraMethod
    public JsonElement exampleInstanceMethod(CordraObject co, HooksContext context) {
        return new JsonObject();
    }

    @CordraMethod("test/123")
    public JsonElement anotherExampleInstanceMethod(CordraObject co, HooksContext context) {
        return new JsonObject();
    }

    @CordraMethod({"echo", "test/xyz"})
    public static JsonElement echo(HooksContext context) throws IOException {
        JsonElement params = context.getParams();
        return params;
    }
}

As before create a class and give it the @CordraType annotation with a name that corresponds with the name of the Cordra type object.

To create an instance Cordra method write a method on your class that takes as its arguments a CordraObject and a HooksContext. Then give that method the @CordraMethod annotation. See the method called exampleInstanceMethod in the above example. If you wish to use a different name for the method, for example one that contains characters that are not permitted in Java method names, you can specify an annotation element, optionally called name or names (if multiple annotation elements are specified, names takes precedence over name which takes precedence over value).

To create a static Cordra method write a method on your class and give it the static access modifier. See the method called echo in the above example.

The @CordraMethod annotation has another annotation element called allowGet; if set to true the method can be called using GET in addition to POST. Note that to set both the method names and allowGet you must include names or name.

@CordraMethod(names={"echo", "test/xyz"}, allowGet=true)
public static JsonElement echo(HooksContext context) throws IOException {
    JsonElement params = context.getParams();
    return params;
}

Static methods can also be implemented at the service level, in the class annotated with @CordraServiceHooks; such methods can be called by targeting the object id “service”.

Building and Deployment

You should compile and package your java project into a “fat jar”. Which is to say any dependencies you have should be included in the package.

To deploy your jar file you should store it as a payload on an object of type Schema or on the CordraDesign object. The payload must have the name “java”. You need not have a single @CordraType in a single jar nor do you need to store this jar payload on a Schema object with the corresponding type name.

When you save the Schema or CordraDesign object Cordra will, at runtime, find any classes that are appropriately annotated and load them into their own class loader. Which is to say each jar file deployed as a payload is given its own class loader. This approach allows other jars to be loaded in such a way that they do not interfere with each other.