001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.connector.federation.executor;
023
024 import java.util.Set;
025 import net.jcip.annotations.NotThreadSafe;
026 import org.jboss.dna.common.util.CheckArg;
027 import org.jboss.dna.connector.federation.Projection;
028 import org.jboss.dna.graph.ExecutionContext;
029 import org.jboss.dna.graph.Location;
030 import org.jboss.dna.graph.connectors.RepositoryConnection;
031 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
032 import org.jboss.dna.graph.connectors.RepositorySource;
033 import org.jboss.dna.graph.connectors.RepositorySourceException;
034 import org.jboss.dna.graph.properties.DateTime;
035 import org.jboss.dna.graph.properties.Path;
036 import org.jboss.dna.graph.properties.PathFactory;
037 import org.jboss.dna.graph.properties.PathNotFoundException;
038 import org.jboss.dna.graph.properties.Property;
039 import org.jboss.dna.graph.requests.CopyBranchRequest;
040 import org.jboss.dna.graph.requests.CreateNodeRequest;
041 import org.jboss.dna.graph.requests.DeleteBranchRequest;
042 import org.jboss.dna.graph.requests.MoveBranchRequest;
043 import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
044 import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
045 import org.jboss.dna.graph.requests.ReadNodeRequest;
046 import org.jboss.dna.graph.requests.Request;
047 import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
048 import org.jboss.dna.graph.requests.processor.RequestProcessor;
049
050 /**
051 * @author Randall Hauch
052 */
053 @NotThreadSafe
054 public class SingleProjectionCommandExecutor extends RequestProcessor {
055
056 private final Projection projection;
057 private final PathFactory pathFactory;
058 private final RepositoryConnectionFactory connectionFactory;
059 private RepositoryConnection connection;
060
061 /**
062 * @param context the execution context in which the executor will be run; may not be null
063 * @param sourceName the name of the {@link RepositorySource} that is making use of this executor; may not be null or empty
064 * @param projection the projection used for the cached information; may not be null and must have exactly one
065 * {@link Projection#getRules() rule}
066 * @param connectionFactory the factory for {@link RepositoryConnection} instances
067 */
068 public SingleProjectionCommandExecutor( ExecutionContext context,
069 String sourceName,
070 Projection projection,
071 RepositoryConnectionFactory connectionFactory ) {
072 this(context, sourceName, null, projection, connectionFactory);
073 }
074
075 /**
076 * @param context the execution context in which the executor will be run; may not be null
077 * @param sourceName the name of the {@link RepositorySource} that is making use of this executor; may not be null or empty
078 * @param now the current time; may be null if the system time is to be used
079 * @param projection the projection used for the cached information; may not be null and must have exactly one
080 * {@link Projection#getRules() rule}
081 * @param connectionFactory the factory for {@link RepositoryConnection} instances
082 */
083 public SingleProjectionCommandExecutor( ExecutionContext context,
084 String sourceName,
085 DateTime now,
086 Projection projection,
087 RepositoryConnectionFactory connectionFactory ) {
088 super(sourceName, context, now);
089 assert connectionFactory != null;
090 assert projection != null;
091 assert projection.getRules().size() == 1;
092 this.projection = projection;
093 this.connectionFactory = connectionFactory;
094 this.pathFactory = context.getValueFactories().getPathFactory();
095 assert this.pathFactory != null;
096 }
097
098 protected RepositoryConnection getConnection() throws RepositorySourceException {
099 if (connection == null) {
100 // Create a connection ...
101 connection = this.connectionFactory.createConnection(this.projection.getSourceName());
102 }
103 return connection;
104 }
105
106 /**
107 * {@inheritDoc}
108 *
109 * @see RequestProcessor#close()
110 */
111 @Override
112 public void close() {
113 if (this.connection != null) {
114 try {
115 this.connection.close();
116 } finally {
117 this.connection = null;
118 }
119 }
120 super.close();
121 }
122
123 /**
124 * {@inheritDoc}
125 *
126 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllChildrenRequest)
127 */
128 @Override
129 public void process( ReadAllChildrenRequest request ) {
130 Location locationInSource = projectIntoSource(request.of());
131 ReadAllChildrenRequest projected = new ReadAllChildrenRequest(locationInSource);
132 getConnection().execute(this.getExecutionContext(), projected);
133 if (projected.hasError()) {
134 return;
135 }
136 for (Location child : projected.getChildren()) {
137 request.addChild(child);
138 }
139 }
140
141 /**
142 * {@inheritDoc}
143 *
144 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllPropertiesRequest)
145 */
146 @Override
147 public void process( ReadAllPropertiesRequest request ) {
148 Location locationInSource = projectIntoSource(request.at());
149 ReadAllPropertiesRequest projected = new ReadAllPropertiesRequest(locationInSource);
150 getConnection().execute(this.getExecutionContext(), projected);
151 if (projected.hasError()) {
152 projectError(projected, request.at(), request);
153 return;
154 }
155 for (Property property : projected.getProperties()) {
156 request.addProperty(property);
157 }
158 }
159
160 /**
161 * {@inheritDoc}
162 *
163 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadNodeRequest)
164 */
165 @Override
166 public void process( ReadNodeRequest request ) {
167 Location locationInSource = projectIntoSource(request.at());
168 ReadNodeRequest projected = new ReadNodeRequest(locationInSource);
169 getConnection().execute(this.getExecutionContext(), projected);
170 if (projected.hasError()) {
171 projectError(projected, request.at(), request);
172 return;
173 }
174 for (Property property : projected.getProperties()) {
175 request.addProperty(property);
176 }
177 for (Location child : projected.getChildren()) {
178 request.addChild(child);
179 }
180 }
181
182 /**
183 * {@inheritDoc}
184 *
185 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CreateNodeRequest)
186 */
187 @Override
188 public void process( CreateNodeRequest request ) {
189 Location locationInSource = projectIntoSource(request.at());
190 CreateNodeRequest projected = new CreateNodeRequest(locationInSource, request.properties());
191 getConnection().execute(this.getExecutionContext(), projected);
192 if (projected.hasError()) {
193 projectError(projected, request.at(), request);
194 return;
195 }
196 }
197
198 /**
199 * {@inheritDoc}
200 *
201 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.UpdatePropertiesRequest)
202 */
203 @Override
204 public void process( UpdatePropertiesRequest request ) {
205 Location locationInSource = projectIntoSource(request.on());
206 UpdatePropertiesRequest projected = new UpdatePropertiesRequest(locationInSource, request.properties());
207 getConnection().execute(this.getExecutionContext(), projected);
208 if (projected.hasError()) {
209 projectError(projected, request.on(), request);
210 return;
211 }
212 }
213
214 /**
215 * {@inheritDoc}
216 *
217 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
218 */
219 @Override
220 public void process( DeleteBranchRequest request ) {
221 Location locationInSource = projectIntoSource(request.at());
222 DeleteBranchRequest projected = new DeleteBranchRequest(locationInSource);
223 getConnection().execute(this.getExecutionContext(), projected);
224 if (projected.hasError()) {
225 projectError(projected, request.at(), request);
226 return;
227 }
228 }
229
230 /**
231 * {@inheritDoc}
232 *
233 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
234 */
235 @Override
236 public void process( MoveBranchRequest request ) {
237 Location fromLocationInSource = projectIntoSource(request.from());
238 Location intoLocationInSource = projectIntoSource(request.into());
239 MoveBranchRequest projected = new MoveBranchRequest(fromLocationInSource, intoLocationInSource);
240 getConnection().execute(this.getExecutionContext(), projected);
241 if (projected.hasError()) {
242 projectError(projected, null, request);
243 return;
244 }
245 }
246
247 /**
248 * {@inheritDoc}
249 *
250 * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
251 */
252 @Override
253 public void process( CopyBranchRequest request ) {
254 Location fromLocationInSource = projectIntoSource(request.from());
255 Location intoLocationInSource = projectIntoSource(request.into());
256 CopyBranchRequest projected = new CopyBranchRequest(fromLocationInSource, intoLocationInSource);
257 getConnection().execute(this.getExecutionContext(), projected);
258 if (projected.hasError()) {
259 projectError(projected, null, request);
260 return;
261 }
262 }
263
264 protected Location projectIntoSource( Location pathInRepository ) {
265 Path path = pathInRepository.getPath();
266 CheckArg.isNotNull(path, "pathInRepository.getPath()");
267 Set<Path> paths = this.projection.getPathsInSource(path, pathFactory);
268 if (paths.isEmpty()) return null;
269 Path projectedPath = paths.iterator().next();
270 Location location = null;
271 if (pathInRepository.hasIdProperties()) {
272 location = new Location(projectedPath, pathInRepository.getIdProperties());
273 } else {
274 new Location(projectedPath);
275 }
276 return location;
277 }
278
279 protected Location projectIntoRepository( Location pathInSource ) {
280 Path path = pathInSource.getPath();
281 CheckArg.isNotNull(path, "pathInSource.getPath()");
282 Path projectedPath = this.projection.getPathsInRepository(path, pathFactory).iterator().next();
283 Location location = null;
284 if (pathInSource.hasIdProperties()) {
285 location = new Location(projectedPath, pathInSource.getIdProperties());
286 } else {
287 new Location(projectedPath);
288 }
289 return location;
290 }
291
292 protected void projectError( Request original,
293 Location originalLocation,
294 Request projected ) {
295 Throwable error = original.getError();
296 if (error instanceof PathNotFoundException) {
297 PathNotFoundException pnf = (PathNotFoundException)error;
298 Path lowestExisting = pnf.getLowestAncestorThatDoesExist();
299 if (lowestExisting != null) lowestExisting = projectIntoRepository(new Location(lowestExisting)).getPath();
300 if (originalLocation == null) originalLocation = projectIntoRepository(pnf.getLocation());
301 error = new PathNotFoundException(originalLocation, lowestExisting, pnf.getMessage());
302 }
303 projected.setError(error);
304 }
305
306 }