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 * Unless otherwise indicated, all code in JBoss DNA is licensed 010 * 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.inmemory; 025 026 import java.util.HashMap; 027 import java.util.HashSet; 028 import java.util.LinkedList; 029 import java.util.List; 030 import java.util.Map; 031 import java.util.Set; 032 import java.util.UUID; 033 import org.jboss.dna.common.i18n.I18n; 034 import org.jboss.dna.common.util.CheckArg; 035 import org.jboss.dna.graph.DnaLexicon; 036 import org.jboss.dna.graph.ExecutionContext; 037 import org.jboss.dna.graph.GraphI18n; 038 import org.jboss.dna.graph.JcrLexicon; 039 import org.jboss.dna.graph.Location; 040 import org.jboss.dna.graph.property.Name; 041 import org.jboss.dna.graph.property.Path; 042 import org.jboss.dna.graph.property.PathFactory; 043 import org.jboss.dna.graph.property.PathNotFoundException; 044 import org.jboss.dna.graph.property.Property; 045 import org.jboss.dna.graph.property.PropertyFactory; 046 import org.jboss.dna.graph.property.Path.Segment; 047 import org.jboss.dna.graph.request.CloneWorkspaceRequest; 048 import org.jboss.dna.graph.request.CopyBranchRequest; 049 import org.jboss.dna.graph.request.CreateNodeRequest; 050 import org.jboss.dna.graph.request.CreateWorkspaceRequest; 051 import org.jboss.dna.graph.request.DeleteBranchRequest; 052 import org.jboss.dna.graph.request.DestroyWorkspaceRequest; 053 import org.jboss.dna.graph.request.GetWorkspacesRequest; 054 import org.jboss.dna.graph.request.InvalidWorkspaceException; 055 import org.jboss.dna.graph.request.MoveBranchRequest; 056 import org.jboss.dna.graph.request.ReadAllChildrenRequest; 057 import org.jboss.dna.graph.request.ReadAllPropertiesRequest; 058 import org.jboss.dna.graph.request.Request; 059 import org.jboss.dna.graph.request.UpdatePropertiesRequest; 060 import org.jboss.dna.graph.request.VerifyWorkspaceRequest; 061 import org.jboss.dna.graph.request.processor.RequestProcessor; 062 063 /** 064 * A {@link RequestProcessor} implementation that operates on an {@link InMemoryRepository} and its 065 * {@link InMemoryRepository.Workspace workspaces}. 066 */ 067 public class InMemoryRequestProcessor extends RequestProcessor { 068 private final PathFactory pathFactory; 069 private final PropertyFactory propertyFactory; 070 private final InMemoryRepository repository; 071 072 protected InMemoryRequestProcessor( ExecutionContext context, 073 InMemoryRepository repository ) { 074 super(repository.getSourceName(), context); 075 this.repository = repository; 076 pathFactory = context.getValueFactories().getPathFactory(); 077 propertyFactory = context.getPropertyFactory(); 078 } 079 080 @Override 081 public void process( ReadAllChildrenRequest request ) { 082 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 083 InMemoryNode node = getTargetNode(workspace, request, request.of()); 084 if (node == null) return; 085 Location actualLocation = getActualLocation(request.of().getPath(), node); 086 Path path = actualLocation.getPath(); 087 // Get the names of the children ... 088 List<InMemoryNode> children = node.getChildren(); 089 for (InMemoryNode child : children) { 090 Segment childName = child.getName(); 091 Path childPath = pathFactory.create(path, childName); 092 request.addChild(childPath, propertyFactory.create(DnaLexicon.UUID, child.getUuid())); 093 } 094 request.setActualLocationOfNode(actualLocation); 095 setCacheableInfo(request); 096 } 097 098 @Override 099 public void process( ReadAllPropertiesRequest request ) { 100 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 101 InMemoryNode node = getTargetNode(workspace, request, request.at()); 102 if (node == null) return; 103 // Get the properties of the node ... 104 Location actualLocation = getActualLocation(request.at().getPath(), node); 105 request.addProperty(propertyFactory.create(DnaLexicon.UUID, node.getUuid())); 106 for (Property property : node.getProperties().values()) { 107 request.addProperty(property); 108 } 109 request.setActualLocationOfNode(actualLocation); 110 setCacheableInfo(request); 111 } 112 113 @Override 114 public void process( CopyBranchRequest request ) { 115 InMemoryRepository.Workspace workspace = getWorkspace(request, request.fromWorkspace()); 116 InMemoryRepository.Workspace newWorkspace = getWorkspace(request, request.intoWorkspace()); 117 if (workspace == null || newWorkspace == null) return; 118 InMemoryNode node = getTargetNode(workspace, request, request.from()); 119 if (node == null) return; 120 // Look up the new parent, which must exist ... 121 Path newParentPath = request.into().getPath(); 122 Name desiredName = request.desiredName(); 123 InMemoryNode newParent = newWorkspace.getNode(newParentPath); 124 Map<UUID, UUID> copyMap = workspace.equals(newWorkspace) ? new HashMap<UUID, UUID>() : null; 125 InMemoryNode newNode = workspace.copyNode(getExecutionContext(), 126 node, 127 newWorkspace, 128 newParent, 129 desiredName, 130 true, 131 copyMap); 132 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName()); 133 Location oldLocation = getActualLocation(request.from().getPath(), node); 134 Location newLocation = Location.create(newPath, newNode.getUuid()); 135 request.setActualLocations(oldLocation, newLocation); 136 } 137 138 @Override 139 public void process( CreateNodeRequest request ) { 140 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 141 if (workspace == null) return; 142 Path parent = request.under().getPath(); 143 CheckArg.isNotNull(parent, "request.under().getPath()"); 144 InMemoryNode node = null; 145 // Look up the parent node, which must exist ... 146 InMemoryNode parentNode = workspace.getNode(parent); 147 if (parentNode == null) { 148 Path lowestExisting = workspace.getLowestExistingPath(parent); 149 request.setError(new PathNotFoundException(request.under(), lowestExisting, 150 GraphI18n.inMemoryNodeDoesNotExist.text(parent))); 151 } 152 UUID uuid = null; 153 for (Property property : request.properties()) { 154 if (property.getName().equals(DnaLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) { 155 uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next()); 156 break; 157 } 158 } 159 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid); 160 assert node != null; 161 Path path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName()); 162 // Now add the properties to the supplied node ... 163 for (Property property : request.properties()) { 164 Name propName = property.getName(); 165 if (property.size() == 0) { 166 node.getProperties().remove(propName); 167 continue; 168 } 169 if (!propName.equals(DnaLexicon.UUID)) { 170 node.getProperties().put(propName, property); 171 } 172 } 173 Location actualLocation = getActualLocation(path, node); 174 request.setActualLocationOfNode(actualLocation); 175 } 176 177 @Override 178 public void process( DeleteBranchRequest request ) { 179 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 180 if (workspace == null) return; 181 InMemoryNode node = getTargetNode(workspace, request, request.at()); 182 if (node == null) return; 183 workspace.removeNode(getExecutionContext(), node); 184 Location actualLocation = getActualLocation(request.at().getPath(), node); 185 request.setActualLocationOfNode(actualLocation); 186 } 187 188 @Override 189 public void process( MoveBranchRequest request ) { 190 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 191 if (workspace == null) return; 192 193 InMemoryNode node = getTargetNode(workspace, request, request.from()); 194 if (node == null) return; 195 // Look up the new parent, which must exist ... 196 Path newParentPath = request.into().getPath(); 197 InMemoryNode newParent = workspace.getNode(newParentPath); 198 workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent); 199 assert node.getParent() == newParent; 200 Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName()); 201 Location oldLocation = getActualLocation(request.from().getPath(), node); 202 Location newLocation = Location.create(newPath, newParent.getUuid()); 203 request.setActualLocations(oldLocation, newLocation); 204 } 205 206 @Override 207 public void process( UpdatePropertiesRequest request ) { 208 InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace()); 209 InMemoryNode node = getTargetNode(workspace, request, request.on()); 210 if (node == null) return; 211 // Now set (or remove) the properties to the supplied node ... 212 for (Map.Entry<Name, Property> propertyEntry : request.properties().entrySet()) { 213 Property property = propertyEntry.getValue(); 214 if (property == null) { 215 node.getProperties().remove(propertyEntry.getKey()); 216 continue; 217 } 218 Name propName = property.getName(); 219 if (!propName.equals(DnaLexicon.UUID)) { 220 node.getProperties().put(propName, property); 221 } 222 } 223 Location actualLocation = getActualLocation(request.on().getPath(), node); 224 request.setActualLocationOfNode(actualLocation); 225 } 226 227 /** 228 * {@inheritDoc} 229 * 230 * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest) 231 */ 232 @Override 233 public void process( CreateWorkspaceRequest request ) { 234 InMemoryRepository.Workspace workspace = repository.createWorkspace(getExecutionContext(), 235 request.desiredNameOfNewWorkspace(), 236 request.conflictBehavior()); 237 if (workspace == null) { 238 String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(), 239 repository.getSourceName()); 240 request.setError(new InvalidWorkspaceException(msg)); 241 } else { 242 InMemoryNode root = workspace.getRoot(); 243 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid())); 244 request.setActualWorkspaceName(workspace.getName()); 245 } 246 } 247 248 /** 249 * {@inheritDoc} 250 * 251 * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest) 252 */ 253 @Override 254 public void process( DestroyWorkspaceRequest request ) { 255 if (!repository.destroyWorkspace(request.workspaceName())) { 256 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName()); 257 request.setError(new InvalidWorkspaceException(msg)); 258 } 259 } 260 261 /** 262 * {@inheritDoc} 263 * 264 * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest) 265 */ 266 @Override 267 public void process( GetWorkspacesRequest request ) { 268 Set<String> names = repository.getWorkspaceNames(); 269 request.setAvailableWorkspaceNames(new HashSet<String>(names)); 270 setCacheableInfo(request); 271 } 272 273 /** 274 * {@inheritDoc} 275 * 276 * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest) 277 */ 278 @Override 279 public void process( VerifyWorkspaceRequest request ) { 280 InMemoryRepository.Workspace original = getWorkspace(request, request.workspaceName()); 281 if (original != null) { 282 Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath(); 283 request.setActualRootLocation(Location.create(path, original.getRoot().getUuid())); 284 request.setActualWorkspaceName(original.getName()); 285 } 286 } 287 288 /** 289 * {@inheritDoc} 290 * 291 * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest) 292 */ 293 @Override 294 public void process( CloneWorkspaceRequest request ) { 295 // Find the original workspace that we're cloning ... 296 final ExecutionContext context = getExecutionContext(); 297 String targetWorkspaceName = request.desiredNameOfTargetWorkspace(); 298 String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned(); 299 InMemoryRepository.Workspace original = repository.getWorkspace(context, nameOfWorkspaceToBeCloned); 300 InMemoryRepository.Workspace target = repository.getWorkspace(context, targetWorkspaceName); 301 if (original == null) { 302 switch (request.cloneConflictBehavior()) { 303 case DO_NOT_CLONE: 304 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned, 305 repository.getSourceName()); 306 request.setError(new InvalidWorkspaceException(msg)); 307 return; 308 case SKIP_CLONE: 309 target = repository.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior()); 310 if (target == null) { 311 msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName()); 312 request.setError(new InvalidWorkspaceException(msg)); 313 } else { 314 InMemoryNode root = target.getRoot(); 315 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid())); 316 request.setActualWorkspaceName(target.getName()); 317 } 318 return; 319 } 320 } 321 assert original != null; 322 target = repository.createWorkspace(context, 323 targetWorkspaceName, 324 request.targetConflictBehavior(), 325 nameOfWorkspaceToBeCloned); 326 if (target == null) { 327 // Since the original was there, the only reason the target wasn't created was because the workspace already existed 328 // ... 329 String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName()); 330 request.setError(new InvalidWorkspaceException(msg)); 331 } else { 332 InMemoryNode root = target.getRoot(); 333 request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid())); 334 request.setActualWorkspaceName(target.getName()); 335 } 336 } 337 338 protected Location getActualLocation( Path path, 339 InMemoryNode node ) { 340 if (path == null) { 341 // Find the path on the node ... 342 LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>(); 343 InMemoryNode n = node; 344 while (n != null) { 345 if (n.getParent() == null) break; 346 segments.addFirst(n.getName()); 347 n = n.getParent(); 348 } 349 path = pathFactory.createAbsolutePath(segments); 350 } 351 return Location.create(path, node.getUuid()); 352 } 353 354 protected InMemoryRepository.Workspace getWorkspace( Request request, 355 String workspaceName ) { 356 // Get the workspace for this request ... 357 InMemoryRepository.Workspace workspace = repository.getWorkspace(getExecutionContext(), workspaceName); 358 if (workspace == null) { 359 String msg = GraphI18n.workspaceDoesNotExistInRepository.text(workspaceName, repository.getSourceName()); 360 request.setError(new InvalidWorkspaceException(msg)); 361 } 362 return workspace; 363 } 364 365 protected InMemoryNode getTargetNode( InMemoryRepository.Workspace workspace, 366 Request request, 367 Location location ) { 368 if (workspace == null) return null; 369 // Check first for the UUID ... 370 InMemoryNode node = null; 371 UUID uuid = location.getUuid(); 372 if (uuid != null) { 373 node = workspace.getNode(uuid); 374 } 375 Path path = null; 376 if (node == null) { 377 // Look up the node with the supplied path ... 378 path = location.getPath(); 379 if (path != null) { 380 node = workspace.getNode(path); 381 } 382 } 383 if (node == null) { 384 if (path == null) { 385 if (uuid == null) { 386 // Missing both path and UUID ... 387 I18n msg = GraphI18n.inMemoryConnectorRequestsMustHavePathOrUuid; 388 request.setError(new IllegalArgumentException(msg.text())); 389 return null; 390 } 391 // Missing path, and could not find by UUID ... 392 request.setError(new PathNotFoundException(location, pathFactory.createRootPath(), 393 GraphI18n.inMemoryNodeDoesNotExist.text(path))); 394 return null; 395 } 396 // Could not find the node given the supplied path, so find the lowest path that does exist ... 397 Path lowestExisting = workspace.getLowestExistingPath(path); 398 request.setError(new PathNotFoundException(location, lowestExisting, GraphI18n.inMemoryNodeDoesNotExist.text(path))); 399 } 400 return node; 401 } 402 }