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 }