View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.connector;
25  
26  import java.util.concurrent.TimeUnit;
27  import javax.transaction.xa.XAResource;
28  import net.jcip.annotations.NotThreadSafe;
29  import org.modeshape.graph.ExecutionContext;
30  import org.modeshape.graph.cache.CachePolicy;
31  import org.modeshape.graph.property.PathNotFoundException;
32  import org.modeshape.graph.property.ReferentialIntegrityException;
33  import org.modeshape.graph.request.CompositeRequest;
34  import org.modeshape.graph.request.Request;
35  import org.modeshape.graph.request.processor.RequestProcessor;
36  
37  /**
38   * A connection to a repository source.
39   * <p>
40   * These connections need not support concurrent operations by multiple threads.
41   * </p>
42   * <h3>Implementing a connector</h3>
43   * <p>
44   * While most of these methods are straightforward, a few warrant additional information. The {@link #ping(long, TimeUnit)} method
45   * allows ModeShape to check the connection to see if it is alive. This method can be used in a variety of situations, ranging from
46   * verifying that a {@link RepositorySource}'s JavaBean properties are correct to ensuring that a connection is still alive before
47   * returning the connection from a connection pool.
48   * </p>
49   * <p>
50   * The most important method on this interface, though, is the {@link #execute(ExecutionContext, Request)} method, which serves as
51   * the mechanism by which the component using the connector access and manipulates the content exposed by the connector. The first
52   * parameter to this method is the {@link ExecutionContext}, which contains the information about environment as well as the
53   * subject performing the request.
54   * </p>
55   * <p>
56   * The second parameter, however, represents a request that is to be processed by the connector. {@link Request} objects can take
57   * many different forms, as there are different classes for each kind of request (see the {org.modeshape.graph.request} package
58   * for more detail). Each request contains the information a connector needs to do the processing, and it also is the place where
59   * the connector places the results (or the error, if one occurs).
60   * </p>
61   * <p>
62   * Although there are over a dozen different kinds of requests, we do anticipate adding more in future releases. For example, ModeShape
63   * will likely support searching repository content in sources through an additional subclass of {@link Request}. Getting the
64   * version history for a node will likely be another kind of request added in an upcoming release.
65   * </p>
66   * <p>
67   * A connector is technically free to implement the {@link #execute(ExecutionContext, Request)} method in any way, as long as the
68   * semantics are maintained. But ModeShape provides a {@link RequestProcessor} class that can simplify writing your own connector and at
69   * the same time help insulate your connector from new kinds of requests that may be added in the future. The
70   * {@link RequestProcessor} is an abstract class that defines a <code>process(...)</code> method for each concrete {@link Request}
71   * subclass. In other words, there is a {@link RequestProcessor#process(org.modeshape.graph.request.CompositeRequest)} method, a
72   * {@link RequestProcessor#process(org.modeshape.graph.request.ReadNodeRequest)} method, and so on.
73   * </p>
74   * <p>
75   * To use a request processor in your connector, simply subclass {@link RequestProcessor} and override all of the abstract methods
76   * and optionally override any of the other methods that have a default implementation. In many cases, the default implementations
77   * of the <code>process(...)</code> methods are <i>sufficient</i> but probably not <i>efficient or optimum.</i> If that is the
78   * case, simply provide your own methods that perform the request in a manner that is efficient for your source. However, if
79   * performance is not a big issue, all of the concrete methods will provide the correct behavior. And remember, you can always
80   * provide better implementations later, so it's often best to keep things simple at first.
81   * </p>
82   * <p>
83   * Then, in your connector's {@link #execute(ExecutionContext, Request)} method, instantiate your {@link RequestProcessor}
84   * subclass and pass the {@link #execute(ExecutionContext, Request) execute(...)} method's Request parameter directly into the the
85   * request processor's {@link RequestProcessor#process(Request)} method, which will determine the appropriate method given the
86   * actual Request object and will then invoke that method. For example:
87   * 
88   * <pre>
89   * public void execute( ExecutionContext context,
90   *                      Request request ) throws RepositorySourceException {
91   *     RequestProcessor processor = new RequestProcessor(context);
92   *     try {
93   *         proc.process(request);
94   *     } finally {
95   *         proc.close();
96   *     }
97   * }
98   * </pre>
99   * 
100  * If you do this, the bulk of your connector implementation will be in the RequestProcessor implementation methods. This not only
101  * is more maintainable, it also lends itself to easier testing. And should any new request types be added in the future, your
102  * connector may work just fine without any changes. In fact, if the {@link RequestProcessor} class can implement meaningful
103  * methods for those new request types, your connector may "just work". Or, at least your connector will still be binary
104  * compatible, even if your connector won't support any of the new features.
105  * </p>
106  * <p>
107  * Finally, how should the connector handle exceptions? As mentioned above, each {@link Request} object has a
108  * {@link Request#setError(Throwable) slot} where the connector can set any exception encountered during processing. This not only
109  * handles the exception, but in the case of a {@link CompositeRequest} it also correctly associates the problem with the request.
110  * However, it is perfectly acceptable to throw an exception if the connection becomes invalid (e.g., there is a communication
111  * failure) or if a fatal error would prevent subsequent requests from being processed.
112  * </p>
113  */
114 @NotThreadSafe
115 public interface RepositoryConnection {
116 
117     /**
118      * Get the name for this repository source. This value should be the same as that {@link RepositorySource#getName() returned}
119      * by the same {@link RepositorySource} that created this connection.
120      * 
121      * @return the identifier; never null or empty
122      */
123     String getSourceName();
124 
125     /**
126      * Return the transactional resource associated with this connection. The transaction manager will use this resource to manage
127      * the participation of this connection in a distributed transaction.
128      * 
129      * @return the XA resource, or null if this connection is not aware of distributed transactions
130      */
131     XAResource getXAResource();
132 
133     /**
134      * Ping the underlying system to determine if the connection is still valid and alive.
135      * 
136      * @param time the length of time to wait before timing out
137      * @param unit the time unit to use; may not be null
138      * @return true if this connection is still valid and can still be used, or false otherwise
139      * @throws InterruptedException if the thread has been interrupted during the operation
140      */
141     boolean ping( long time,
142                   TimeUnit unit ) throws InterruptedException;
143 
144     /**
145      * Get the default cache policy for this repository. If none is provided, a global cache policy will be used.
146      * 
147      * @return the default cache policy
148      */
149     CachePolicy getDefaultCachePolicy();
150 
151     /**
152      * Execute the supplied commands against this repository source.
153      * 
154      * @param context the environment in which the commands are being executed; never null
155      * @param request the request to be executed; never null
156      * @throws PathNotFoundException if the request(s) contain paths to nodes that do not exist
157      * @throws ReferentialIntegrityException if the request is or contains a delete operation, where the delete could not be
158      *         performed because some references to deleted nodes would have remained after the delete operation completed
159      * @throws RepositorySourceException if there is a problem loading the node data
160      */
161     void execute( ExecutionContext context,
162                   Request request ) throws RepositorySourceException;
163 
164     /**
165      * Close this connection to signal that it is no longer needed and that any accumulated resources are to be released.
166      */
167     void close();
168 }