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>
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.
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, 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”.
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.