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 }