Content Manager Library
The Content Manager Library offers linguistic abstractions over the content model and interface of the Content Manager service . In this role, it acts both as a client library and as a service-side library for plugin developments. In particular, it is a dependency of the service as well as a dependency of service clients.
The library includes:
- the API for
gDoc
trees; - the API for
gDoc
tree predicates; - the stubs of the service automatically generated from the WSDL definition of its port-types;
- the high-level calls, a set of abstractions over the service stubs;
- a Java protocol handler and associated facilities for deriving and resolving content URIs, i.e. resolvable URIs to arbitrary nodes of
gDoc
trees.
We have previously presented most of the APIs for gDoc
trees and tree predicates. We concentrate here on high-level calls and content URIs, completing the presentation of the tree and tree predicate APIs in the process.
High-Level Calls
High-level calls are Java objects that model single-step or multi-step interactions with the Content Management service. The objects encapsulate stub-based interactions behind local object-oriented interfaces that offer transparencies over the remote interfaces of the service port-types.
The local interfaces are based on language features that are not found in the service stubs, including high-level models of inputs and outputs, method overloading, parametric types, asynchronous callbacks.
Behind these abstractions, the call objects engage in optimised and best-effort interactions with the WS-Resources of the services; in particular, they can hide from clients the complexity of resource discovery while keeping visible the remote nature of the interactions and the possibility of their failure.
High-level calls are defined in the package org.gcube.contentmanagement.contentmanager.stubs.calls
and in the package org.gcube.contentmanagement.contentmanager.stubs.calls.iterators
. The main components are depicted below:
-
BaseCall
: the base class for all high-level calls. -
FactoryCall
: aBaseCall
that represents calls to the code>Factory</code> resource of the service. -
FactoryParams
: used inFactoryCall
to model the input of operations to the code>Factory</code> resource of the service. -
FactoryConsumer
: used inFactoryCall
to callback invokers of the asynchronous operation of the code>Factory</code> resource of the service. -
ManagerCall
: an abstract extension ofBaseCall
for calls to the Collection Managers of the service. -
ReadManagerCall
: aManagerCall
that represents calls to <core>ReadManager</code> resources of the service. -
WriteManagerCall
: aManagerCall
that represents calls to <core>WriteManager</code> resources of the service. -
MappingRegistry
: a central registry of type mappings for I/O. -
Constants
: a collection of service-specific constants. -
Utils
: a collection of utilities for I/O conversions.
-
BaseRSIterators<T>
: the base class for all iterators backed by a ResultSet of records that can be parsed by aResultSetParser<T>>.
- <code>ResultParser<T>: a parser of ResultSet records into objects of type
T
. -
GDocParser
: aResultParser
ofgDoc
trees that uses thegDoc
native API. -
AddOutcomeParser
: aResultParser
ofAddOutcome
s. -
UpdateFailureParser
: aResultParser
ofUpdateFailureOutcome
s.
-
RSIterator<T>
: aBaseRSIterator
that delivers parsing failures synchronously. -
RSIterator<T>
: aRSIterator
that uses aGDocParser
.
-
AsyncRSIterator<T>
: aBaseRSIterator
that tolerates parsing failures and delivers them asynchronously, to aFaultReader
. -
FaultReader
: a processor of parsing failures during ResultSet iterations.
-
RSCollection<T>
: a lazy collection that can iterated over by aAsyncRSIterator<T%>
. -
GDocRSCollection
: anRSCollection
that uses aAsyncRSIterator<GDoc%>
.
In what follows, we exemplify the use of FactoryCall
s, ReadManagerCall
s, and WriteManagerCalls
.
Factory Calls
A FactoryCall
is created in a a scope:
//some scope GCUBEScope scope = ..... FactoryCall call = new FactoryCall(scope);
In a secure infrastructure, the call may also be created with a security manager:
//some scope GCUBEScope scope = ..... //some security manager = .... GCUBESecurityManager manager = .... FactoryCall call = new FactoryCall(scope,manager);
The call may then be issued, i.e. used to create CollectionManagers. In line with the operations of the remote port-type, this can be done synchronously or asynchronously.
The synchronous invocation requires the preparation of FactoryParameters
;
FactoryParameters params = new FactoryParameters() ; params.setPlugin("..somepluginname..."); params.setBroadcast(false); //the DOM serialisation of plugin-specific creation parameters org.w3c.dom.Element payload = ... params.setPayload(payload) //issue the call List<EprPair> eprs = call.create(params); //process the response for (EprPair pair : eprs) .... pair.getPorttype() ... pair.getEpr() ...
note: typically, plugin will offer object bindings for the payloads that they support. The payload input to the |
The asynchronous invocation requires the additional preparation of a FactoryConsumer
:
//prepare as above FactoryParameters params = ..... //creates consumer FactoryConsumer consumer = new FactoryConsumer { protected void onCompletion(List<EprPair> eprs) { .... process pairs as above }; protected void onFailure(Exception e) { ... handle failure }; }; //issue the call call.createASync(params,consumer);
In both interactions above, the FactoryCall
will attempt to discover Factory
WS-Resources that host the plugin named in the parameters. It will then try to interact with each resource in turn, until one responds successfully or else indicates that continuing will be to no avail (by returning a GCUBEUnretrievableFault
).
note: clients can obtain and customise the query that underlies the strategy (cf. note: while call objects are often created anew for individual calls to the remote port-type, clients can use the same object for multiple calls (though this is unlikely for |
Clients who know and wish to target a specific Factory
resource, can disable the best-effort strategy by configuring the call with a reference to its endpoint:
//a reference to the endpoint of a Content Manager RI EndpointReferenceType epr = ... call.setEndpointReferenceType(epr); //alternatively: call.setEndpoint("... somehostname ...",".. someport ..");
ReadManager Calls
A ReadManagerCall
gives high-level write access to the content of a given collection, as allowed by a ReadManager
resource bound to that collection.
It follows the same patterns already illustrated for FactoryCall
s. In particular, it is created in a scope and, optionally, with a security manager.
//some scope GCUBEScope scope = ..... ReadManagerCall call = new ReadManagerCall(scope); //some security manager = .... GCUBESecurityManager manager = .... ReadManagerCall secureCall = new ReadManagerCall(scope,manager);
As a further option, it may be crated with the identifier of the target collection:
//some scope GCUBEScope scope = ..... ReadManagerCall call = new ReadManagerCall("... some collection identifier ...",scope); //some security manager = .... GCUBESecurityManager manager = .... ReadManagerCall secureCall = new ReadManagerCall("... some collection identifier ...",scope,manager);
note: the collection identifier may also be set after call construction (cf. |
The call object may be configured as a FactoryCall
, i.e. setting reference to resource endpoint for targeted interactions (cf. setEndpointReference(EndpointReference)
), or else relying on implicit discovery and best-effort strategy. In the latter case, the query that underlie the strategy can be customised and reset (cf. getQuery()
,resetQuery()
).
The call object may then be used to retrieve gDoc
trees from the target collection. To this end, its operations may be classified in two groups: the those that return single trees and those that return multiple trees. The first class includes lookup operations while the second class includes both lookup and query operations based on tree predicates. Multi-valued operations are execute asynchronously at the service, based on the ResultSet mechanism.
The following example illustrates the use single-valued lookups:
//synchronous: return one gDoc tree GDoc doc1 = call.get("... tree root identifier ..."); //some tree predicate to use for pruning Predicate projection = .... //synchronous: prune and return one gDoc tree GDoc doc2 = call.get("... tree root identifier ...",projection);
Here, get(String)
and get(String,Predicate)
bind the output tree to the object model of gDoc
tree API.
We note that there are semantically equivalent operations that return DOM bindings, so as to raise no further parsing costs if a binding other than to the gDoc
tree API is required upstream (cf. getAsElement(String)
and getAsElement(String,Predicate)
).
Muti-valued lookups may be exemplified as follows:
//a locator to a ResultSet of tree root identifiers, produced using standard ResultSet production idioms RSLocator identifiers = .... //asynchronous: returns a locator to a remote ResultSet of gDoc trees with given identifiers RSLocator locator1 = call.get(identifiers); //asynchronous: returns a locator to a remote ResultSet of gDoc trees with given identifiers, pruned by a tree predicate RSLocator locator2 = call.get(identifiers,predicate);
The ResultSets returned by the lookups contain XML representations of gDoc
trees. Standard ResultSet consumption idioms may then be used to extract the XML representations and bind them to object models of choice. The library supports more transparent idioms, however:
//a locator to a ResultSet of gDoc trees. RSLocator locator = .... GDocRSCollection docs = new GDocRSCollection(locator); //use standard for (GDoc doc : doc) ...process document...
Here, GDocRSCollection
is a collection of gDoc
trees which is backed by the ResultSet identified by the locator. The collection is 'lazily' assembled, in that it does not allow direct access to its elements, but can only be iterated over with standard language idioms, as shown. The iteration subsumes XML bindings to the native object model and hides binding failures in the process. Clients that wish to process failures can do so asynchronously with respect to the iteration, by previously registering a FaultListener
with the collection (e.g. at construction time):
//a locator to a ResultSet of gDoc trees. RSLocator locator = .... FaultListener listener = new FaultListener() { @Override void onFault(String unparsedResult, Throwable failure) {...process failure...} } GDocRSCollection docs = new GDocRSCollection(locator, listener); for (GDoc doc : doc) ...process document...
note: a note: a |
Clients which are not well-served by the asynchronous delivery of failures can instead opt for a GDocRSIterator
, which again offers binding transparencies but delivers failures synchronously:
//a locator to a ResultSet of gDoc trees. RSLocator locator = .... GDocRSIterator it = new GDocRSCollection(iterator); while (it.hasNext) { ... try { GDoc doc = it.next(); ....process document... } catch (Throwable failure) { ...handle failure... } ... }
note: |
Finally, we give an example of queries for gDoc
trees:
//asynchronous: return a locator to a remote ResultSet of many gDoc trees pruned by a tree predicate RSLocator locator3 = call.get(projection); //some tree predicate to use for filtering Predicate filter = .... //asynchronous: return a locator to a remote ResultSet of many pruned gDoc trees that satisfy a given filter RSLocator locator4= call.get(projection,filter); //asynchronous: return a locator to a remote ResultSet of all the gDoc trees in the collection RSLocator locator5 = call.get();
Again, the ResultSets returned by the queries can be consumed with standard ResultSet consumption idioms.