A connection to a repository source.
These connections need not support concurrent operations by multiple threads.
Implementing a connector
While most of these methods are straightforward, a few warrant additional information. The {@link #ping(long,TimeUnit)} methodallows DNA to check the connection to see if it is alive. This method can be used in a variety of situations, ranging from verifying that a {@link RepositorySource}'s JavaBean properties are correct to ensuring that a connection is still alive before returning the connection from a connection pool.
The most important method on this interface, though, is the {@link #execute(ExecutionContext,Request)} method, which serves asthe mechanism by which the component using the connector access and manipulates the content exposed by the connector. The first parameter to this method is the {@link ExecutionContext}, which contains the information about environment as well as the subject performing the request.
The second parameter, however, represents a request that is to be processed by the connector. {@link Request} objects can takemany different forms, as there are different classes for each kind of request (see the {org.jboss.dna.graph.request} package for more detail). Each request contains the information a connector needs to do the processing, and it also is the place where the connector places the results (or the error, if one occurs).
Although there are over a dozen different kinds of requests, we do anticipate adding more in future releases. For example, DNA will likely support searching repository content in sources through an additional subclass of {@link Request}. Getting the version history for a node will likely be another kind of request added in an upcoming release.
A connector is technically free to implement the {@link #execute(ExecutionContext,Request)} method in any way, as long as thesemantics are maintained. But DNA provides a {@link RequestProcessor} class that can simplify writing your own connector and atthe same time help insulate your connector from new kinds of requests that may be added in the future. The {@link RequestProcessor} is an abstract class that defines a process(...)
method for each concrete {@link Request}subclass. In other words, there is a {@link RequestProcessor#process(org.jboss.dna.graph.request.CompositeRequest)} method, a{@link RequestProcessor#process(org.jboss.dna.graph.request.ReadNodeRequest)} method, and so on.
To use a request processor in your connector, simply subclass {@link RequestProcessor} and override all of the abstract methodsand optionally override any of the other methods that have a default implementation. In many cases, the default implementations of the process(...)
methods are sufficient but probably not efficient or optimum. If that is the case, simply provide your own methods that perform the request in a manner that is efficient for your source. However, if performance is not a big issue, all of the concrete methods will provide the correct behavior. And remember, you can always provide better implementations later, so it's often best to keep things simple at first.
Then, in your connector's {@link #execute(ExecutionContext,Request)} method, instantiate your {@link RequestProcessor}subclass and pass the {@link #execute(ExecutionContext,Request) execute(...)} method's Request parameter directly into the therequest processor's {@link RequestProcessor#process(Request)} method, which will determine the appropriate method given theactual Request object and will then invoke that method. For example:
public void execute( ExecutionContext context, Request request ) throws RepositorySourceException { RequestProcessor processor = new RequestProcessor(context); try { proc.process(request); } finally { proc.close(); } }
If you do this, the bulk of your connector implementation will be in the RequestProcessor implementation methods. This not only is more maintainable, it also lends itself to easier testing. And should any new request types be added in the future, your connector may work just fine without any changes. In fact, if the {@link RequestProcessor} class can implement meaningfulmethods for those new request types, your connector may "just work". Or, at least your connector will still be binary compatible, even if your connector won't support any of the new features.
Finally, how should the connector handle exceptions? As mentioned above, each {@link Request} object has a{@link Request#setError(Throwable) slot} where the connector can set any exception encountered during processing. This not onlyhandles the exception, but in the case of a {@link CompositeRequest} it also correctly associates the problem with the request.However, it is perfectly acceptable to throw an exception if the connection becomes invalid (e.g., there is a communication failure) or if a fatal error would prevent subsequent requests from being processed.