001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.connector;
025    
026    import java.util.concurrent.TimeUnit;
027    import javax.transaction.xa.XAResource;
028    import net.jcip.annotations.NotThreadSafe;
029    import org.jboss.dna.graph.ExecutionContext;
030    import org.jboss.dna.graph.cache.CachePolicy;
031    import org.jboss.dna.graph.property.PathNotFoundException;
032    import org.jboss.dna.graph.property.ReferentialIntegrityException;
033    import org.jboss.dna.graph.request.CompositeRequest;
034    import org.jboss.dna.graph.request.Request;
035    import org.jboss.dna.graph.request.processor.RequestProcessor;
036    
037    /**
038     * A connection to a repository source.
039     * <p>
040     * These connections need not support concurrent operations by multiple threads.
041     * </p>
042     * <h3>Implementing a connector</h3>
043     * <p>
044     * While most of these methods are straightforward, a few warrant additional information. The {@link #ping(long, TimeUnit)} method
045     * allows DNA to check the connection to see if it is alive. This method can be used in a variety of situations, ranging from
046     * verifying that a {@link RepositorySource}'s JavaBean properties are correct to ensuring that a connection is still alive before
047     * returning the connection from a connection pool.
048     * </p>
049     * <p>
050     * DNA hasn't yet defined the event mechanism, so connectors don't have any methods to invoke on the
051     * {@link RepositorySourceListener}. This will be defined in the next release, so feel free to manage the listeners now. Note that
052     * by default the {@link RepositorySourceCapabilities} returns false for supportsEvents().
053     * </p>
054     * <p>
055     * The most important method on this interface, though, is the {@link #execute(ExecutionContext, Request)} method, which serves as
056     * the mechanism by which the component using the connector access and manipulates the content exposed by the connector. The first
057     * parameter to this method is the {@link ExecutionContext}, which contains the information about environment as well as the
058     * subject performing the request.
059     * </p>
060     * <p>
061     * The second parameter, however, represents a request that is to be processed by the connector. {@link Request} objects can take
062     * many different forms, as there are different classes for each kind of request (see the {org.jboss.dna.graph.request} package
063     * for more detail). Each request contains the information a connector needs to do the processing, and it also is the place where
064     * the connector places the results (or the error, if one occurs).
065     * </p>
066     * <p>
067     * Although there are over a dozen different kinds of requests, we do anticipate adding more in future releases. For example, DNA
068     * will likely support searching repository content in sources through an additional subclass of {@link Request}. Getting the
069     * version history for a node will likely be another kind of request added in an upcoming release.
070     * </p>
071     * <p>
072     * A connector is technically free to implement the {@link #execute(ExecutionContext, Request)} method in any way, as long as the
073     * semantics are maintained. But DNA provides a {@link RequestProcessor} class that can simplify writing your own connector and at
074     * the same time help insulate your connector from new kinds of requests that may be added in the future. The
075     * {@link RequestProcessor} is an abstract class that defines a <code>process(...)</code> method for each concrete {@link Request}
076     * subclass. In other words, there is a {@link RequestProcessor#process(org.jboss.dna.graph.request.CompositeRequest)} method, a
077     * {@link RequestProcessor#process(org.jboss.dna.graph.request.ReadNodeRequest)} method, and so on.
078     * </p>
079     * <p>
080     * To use a request processor in your connector, simply subclass {@link RequestProcessor} and override all of the abstract methods
081     * and optionally override any of the other methods that have a default implementation. In many cases, the default implementations
082     * of the <code>process(...)</code> methods are <i>sufficient</i> but probably not <i>efficient or optimum.</i> If that is the
083     * case, simply provide your own methods that perform the request in a manner that is efficient for your source. However, if
084     * performance is not a big issue, all of the concrete methods will provide the correct behavior. And remember, you can always
085     * provide better implementations later, so it's often best to keep things simple at first.
086     * </p>
087     * <p>
088     * Then, in your connector's {@link #execute(ExecutionContext, Request)} method, instantiate your {@link RequestProcessor}
089     * subclass and pass the {@link #execute(ExecutionContext, Request) execute(...)} method's Request parameter directly into the the
090     * request processor's {@link RequestProcessor#process(Request)} method, which will determine the appropriate method given the
091     * actual Request object and will then invoke that method. For example:
092     * 
093     * <pre>
094     * public void execute( ExecutionContext context,
095     *                      Request request ) throws RepositorySourceException {
096     *     RequestProcessor processor = new RequestProcessor(context);
097     *     try {
098     *         proc.process(request);
099     *     } finally {
100     *         proc.close();
101     *     }
102     * }
103     * </pre>
104     * 
105     * If you do this, the bulk of your connector implementation will be in the RequestProcessor implementation methods. This not only
106     * is more maintainable, it also lends itself to easier testing. And should any new request types be added in the future, your
107     * connector may work just fine without any changes. In fact, if the {@link RequestProcessor} class can implement meaningful
108     * methods for those new request types, your connector may "just work". Or, at least your connector will still be binary
109     * compatible, even if your connector won't support any of the new features.
110     * </p>
111     * <p>
112     * Finally, how should the connector handle exceptions? As mentioned above, each {@link Request} object has a
113     * {@link Request#setError(Throwable) slot} where the connector can set any exception encountered during processing. This not only
114     * handles the exception, but in the case of a {@link CompositeRequest} it also correctly associates the problem with the request.
115     * However, it is perfectly acceptable to throw an exception if the connection becomes invalid (e.g., there is a communication
116     * failure) or if a fatal error would prevent subsequent requests from being processed.
117     * </p>
118     * 
119     * @author Randall Hauch
120     */
121    @NotThreadSafe
122    public interface RepositoryConnection {
123    
124        /**
125         * Get the name for this repository source. This value should be the same as that {@link RepositorySource#getName() returned}
126         * by the same {@link RepositorySource} that created this connection.
127         * 
128         * @return the identifier; never null or empty
129         */
130        String getSourceName();
131    
132        /**
133         * Return the transactional resource associated with this connection. The transaction manager will use this resource to manage
134         * the participation of this connection in a distributed transaction.
135         * 
136         * @return the XA resource, or null if this connection is not aware of distributed transactions
137         */
138        XAResource getXAResource();
139    
140        /**
141         * Ping the underlying system to determine if the connection is still valid and alive.
142         * 
143         * @param time the length of time to wait before timing out
144         * @param unit the time unit to use; may not be null
145         * @return true if this connection is still valid and can still be used, or false otherwise
146         * @throws InterruptedException if the thread has been interrupted during the operation
147         */
148        boolean ping( long time,
149                      TimeUnit unit ) throws InterruptedException;
150    
151        /**
152         * Set the listener that is to receive notifications to changes to content within this source.
153         * 
154         * @param listener the new listener, or null if no component is interested in the change notifications
155         */
156        void setListener( RepositorySourceListener listener );
157    
158        /**
159         * Get the default cache policy for this repository. If none is provided, a global cache policy will be used.
160         * 
161         * @return the default cache policy
162         */
163        CachePolicy getDefaultCachePolicy();
164    
165        /**
166         * Execute the supplied commands against this repository source.
167         * 
168         * @param context the environment in which the commands are being executed; never null
169         * @param request the request to be executed; never null
170         * @throws PathNotFoundException if the request(s) contain paths to nodes that do not exist
171         * @throws ReferentialIntegrityException if the request is or contains a delete operation, where the delete could not be
172         *         performed because some references to deleted nodes would have remained after the delete operation completed
173         * @throws RepositorySourceException if there is a problem loading the node data
174         */
175        void execute( ExecutionContext context,
176                      Request request ) throws RepositorySourceException;
177    
178        /**
179         * Close this connection to signal that it is no longer needed and that any accumulated resources are to be released.
180         */
181        void close();
182    }