View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.connector.map;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.HashSet;
29  import java.util.LinkedList;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.UUID;
34  import org.modeshape.common.i18n.I18n;
35  import org.modeshape.common.util.CheckArg;
36  import org.modeshape.graph.ModeShapeLexicon;
37  import org.modeshape.graph.ExecutionContext;
38  import org.modeshape.graph.GraphI18n;
39  import org.modeshape.graph.JcrLexicon;
40  import org.modeshape.graph.Location;
41  import org.modeshape.graph.observe.Observer;
42  import org.modeshape.graph.property.Name;
43  import org.modeshape.graph.property.Path;
44  import org.modeshape.graph.property.PathFactory;
45  import org.modeshape.graph.property.PathNotFoundException;
46  import org.modeshape.graph.property.Property;
47  import org.modeshape.graph.property.PropertyFactory;
48  import org.modeshape.graph.property.Path.Segment;
49  import org.modeshape.graph.query.QueryResults;
50  import org.modeshape.graph.request.AccessQueryRequest;
51  import org.modeshape.graph.request.CloneBranchRequest;
52  import org.modeshape.graph.request.CloneWorkspaceRequest;
53  import org.modeshape.graph.request.CopyBranchRequest;
54  import org.modeshape.graph.request.CreateNodeRequest;
55  import org.modeshape.graph.request.CreateWorkspaceRequest;
56  import org.modeshape.graph.request.DeleteBranchRequest;
57  import org.modeshape.graph.request.DestroyWorkspaceRequest;
58  import org.modeshape.graph.request.FullTextSearchRequest;
59  import org.modeshape.graph.request.GetWorkspacesRequest;
60  import org.modeshape.graph.request.InvalidRequestException;
61  import org.modeshape.graph.request.InvalidWorkspaceException;
62  import org.modeshape.graph.request.LockBranchRequest;
63  import org.modeshape.graph.request.MoveBranchRequest;
64  import org.modeshape.graph.request.ReadAllChildrenRequest;
65  import org.modeshape.graph.request.ReadAllPropertiesRequest;
66  import org.modeshape.graph.request.Request;
67  import org.modeshape.graph.request.UnlockBranchRequest;
68  import org.modeshape.graph.request.UpdatePropertiesRequest;
69  import org.modeshape.graph.request.VerifyWorkspaceRequest;
70  import org.modeshape.graph.request.processor.RequestProcessor;
71  
72  /**
73   * The default implementation of the {@link RequestProcessor} for map repositories.
74   */
75  public class MapRequestProcessor extends RequestProcessor {
76      private final PathFactory pathFactory;
77      private final PropertyFactory propertyFactory;
78      private final MapRepository repository;
79      private final boolean updatesAllowed;
80  
81      public MapRequestProcessor( ExecutionContext context,
82                                  MapRepository repository,
83                                  Observer observer,
84                                  boolean updatesAllowed ) {
85          super(repository.getSourceName(), context, observer);
86          this.repository = repository;
87          pathFactory = context.getValueFactories().getPathFactory();
88          propertyFactory = context.getPropertyFactory();
89          this.updatesAllowed = updatesAllowed;
90      }
91  
92      /**
93       * {@inheritDoc}
94       * 
95       * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.ReadAllChildrenRequest)
96       */
97      @Override
98      public void process( ReadAllChildrenRequest request ) {
99          MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
100         MapNode node = getTargetNode(workspace, request, request.of());
101         if (node == null) {
102             assert request.hasError();
103             return;
104         }
105 
106         Location actualLocation = getActualLocation(request.of(), node);
107         assert actualLocation != null;
108         Path path = actualLocation.getPath();
109         // Get the names of the children ...
110         List<MapNode> children = node.getChildren();
111         for (MapNode child : children) {
112             Segment childName = child.getName();
113             Path childPath = pathFactory.create(path, childName);
114             request.addChild(childPath, propertyFactory.create(ModeShapeLexicon.UUID, child.getUuid()));
115         }
116         request.setActualLocationOfNode(actualLocation);
117         setCacheableInfo(request);
118     }
119 
120     @Override
121     public void process( LockBranchRequest request ) {
122         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
123         MapNode node = getTargetNode(workspace, request, request.at());
124         if (node == null) return;
125 
126         workspace.lockNode(node, request.lockScope(), request.lockTimeoutInMillis());
127 
128         Location actualLocation = getActualLocation(request.at(), node);
129         request.setActualLocation(actualLocation);
130         recordChange(request);
131     }
132 
133     @Override
134     public void process( UnlockBranchRequest request ) {
135         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
136         MapNode node = getTargetNode(workspace, request, request.at());
137         if (node == null) return;
138 
139         workspace.unlockNode(node);
140 
141         Location actualLocation = getActualLocation(request.at(), node);
142         request.setActualLocation(actualLocation);
143         recordChange(request);
144     }
145 
146     @Override
147     public void process( ReadAllPropertiesRequest request ) {
148         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
149         MapNode node = getTargetNode(workspace, request, request.at());
150         if (node == null) {
151             assert request.hasError();
152             return;
153         }
154 
155         // Get the properties of the node ...
156         Location actualLocation = getActualLocation(request.at(), node);
157         request.addProperty(propertyFactory.create(ModeShapeLexicon.UUID, node.getUuid()));
158         for (Property property : node.getProperties().values()) {
159             request.addProperty(property);
160         }
161 
162         assert actualLocation != null;
163         request.setActualLocationOfNode(actualLocation);
164         setCacheableInfo(request);
165     }
166 
167     /**
168      * {@inheritDoc}
169      * 
170      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.CloneBranchRequest)
171      */
172     @Override
173     public void process( CloneBranchRequest request ) {
174         if (!updatesAllowed(request)) return;
175 
176         MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
177         MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
178         if (workspace == null || newWorkspace == null) return;
179         MapNode node = getTargetNode(workspace, request, request.from());
180         if (node == null) return;
181 
182         // Look up the new parent, which must exist ...
183         Path newParentPath = request.into().getPath();
184         MapNode newParent = newWorkspace.getNode(newParentPath);
185         Set<Location> removedExistingNodes = new HashSet<Location>();
186         MapNode newNode = workspace.cloneNode(getExecutionContext(),
187                                               node,
188                                               newWorkspace,
189                                               newParent,
190                                               request.desiredName(),
191                                               request.desiredSegment(),
192                                               request.removeExisting(),
193                                               removedExistingNodes);
194         Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
195         Location oldLocation = getActualLocation(request.from(), node);
196         Location newLocation = Location.create(newPath, newNode.getUuid());
197         request.setActualLocations(oldLocation, newLocation);
198         request.setRemovedNodes(Collections.unmodifiableSet(removedExistingNodes));
199         recordChange(request);
200     }
201 
202     /**
203      * {@inheritDoc}
204      * 
205      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.CopyBranchRequest)
206      */
207     @Override
208     public void process( CopyBranchRequest request ) {
209         if (!updatesAllowed(request)) return;
210 
211         MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
212         MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
213         if (workspace == null || newWorkspace == null) return;
214         MapNode node = getTargetNode(workspace, request, request.from());
215         if (node == null) return;
216 
217         // Look up the new parent, which must exist ...
218         Path newParentPath = request.into().getPath();
219         Name desiredName = request.desiredName();
220         MapNode newParent = newWorkspace.getNode(newParentPath);
221         MapNode newNode = workspace.copyNode(getExecutionContext(), node, newWorkspace, newParent, desiredName, true);
222         Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
223         Location oldLocation = getActualLocation(request.from(), node);
224         Location newLocation = Location.create(newPath, newNode.getUuid());
225         request.setActualLocations(oldLocation, newLocation);
226         recordChange(request);
227     }
228 
229     /**
230      * {@inheritDoc}
231      * 
232      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.CreateNodeRequest)
233      */
234     @Override
235     public void process( CreateNodeRequest request ) {
236         if (!updatesAllowed(request)) return;
237 
238         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
239         if (workspace == null) return;
240         Path parent = request.under().getPath();
241         CheckArg.isNotNull(parent, "request.under().getPath()");
242         MapNode node = null;
243         // Look up the parent node, which must exist ...
244 
245         MapNode parentNode = workspace.getNode(parent);
246         if (parentNode == null) {
247             Path lowestExisting = workspace.getLowestExistingPath(parent);
248             request.setError(new PathNotFoundException(request.under(), lowestExisting, GraphI18n.nodeDoesNotExist.text(parent)));
249             return;
250         }
251 
252         UUID uuid = null;
253         // Make a list of the properties that we will store: all props except dna:uuid and jcr:uuid
254         List<Property> propsToStore = new ArrayList<Property>(request.properties().size());
255         for (Property property : request.properties()) {
256             if (property.getName().equals(ModeShapeLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) {
257                 uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
258             } else {
259                 if (property.size() > 0) propsToStore.add(property);
260             }
261         }
262 
263         switch (request.conflictBehavior()) {
264             case APPEND:
265                 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
266                 break;
267             case DO_NOT_REPLACE:
268                 for (MapNode child : parentNode.getChildren()) {
269                     if (request.named().equals(child.getName().getName())) {
270                         node = child;
271                         break;
272                     }
273                 }
274                 if (node == null) {
275                     node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
276                 }
277                 break;
278             case REPLACE:
279                 // See if the node already exists (this doesn't record an error on the request) ...
280                 node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
281                 if (node != null) {
282                     workspace.removeNode(getExecutionContext(), node);
283                 }
284                 node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
285                 break;
286             case UPDATE:
287                 // See if the node already exists (this doesn't record an error on the request) ...
288                 node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
289                 if (node == null) {
290                     node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid, propsToStore);
291                 } // otherwise, we found it and we're setting any properties below
292                 break;
293         }
294         assert node != null;
295         Path path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName());
296 
297         Location actualLocation = getActualLocation(Location.create(path), node);
298         request.setActualLocationOfNode(actualLocation);
299         recordChange(request);
300     }
301 
302     /**
303      * {@inheritDoc}
304      * 
305      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.DeleteBranchRequest)
306      */
307     @Override
308     public void process( DeleteBranchRequest request ) {
309         if (!updatesAllowed(request)) return;
310 
311         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
312         if (workspace == null) return;
313         MapNode node = getTargetNode(workspace, request, request.at());
314         if (node == null) return;
315         workspace.removeNode(getExecutionContext(), node);
316         Location actualLocation = getActualLocation(request.at(), node);
317         request.setActualLocationOfNode(actualLocation);
318         recordChange(request);
319     }
320 
321     /**
322      * {@inheritDoc}
323      * 
324      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.MoveBranchRequest)
325      */
326     @Override
327     public void process( MoveBranchRequest request ) {
328         if (!updatesAllowed(request)) return;
329 
330         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
331         if (workspace == null) return;
332 
333         MapNode beforeNode = request.before() != null ? getTargetNode(workspace, request, request.before()) : null;
334         MapNode node = getTargetNode(workspace, request, request.from());
335         if (node == null) return;
336         if (request.hasError()) return; // if beforeNode could not be found
337         // Look up the new parent, which must exist ...
338         Path newParentPath;
339 
340         if (request.into() != null) {
341             newParentPath = request.into().getPath();
342         } else {
343             // into or before cannot both be null
344             assert beforeNode != null;
345 
346             // Build the path from the before node to the root.
347             LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
348             MapNode current = beforeNode.getParent();
349             while (!current.equals(workspace.getRoot())) {
350                 segments.addFirst(current.getName());
351                 current = current.getParent();
352             }
353             newParentPath = getExecutionContext().getValueFactories().getPathFactory().createAbsolutePath(segments);
354         }
355 
356         MapNode newParent = workspace.getNode(newParentPath);
357         if (newParent == null) {
358             Path lowestExisting = workspace.getLowestExistingPath(newParentPath);
359             request.setError(new PathNotFoundException(request.into(), lowestExisting,
360                                                        GraphI18n.nodeDoesNotExist.text(newParentPath)));
361             return;
362         }
363         workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent, beforeNode);
364         assert node.getParent().equals(newParent);
365         Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
366         Location oldLocation = getActualLocation(request.from(), node);
367         Location newLocation = Location.create(newPath, node.getUuid());
368         request.setActualLocations(oldLocation, newLocation);
369         recordChange(request);
370     }
371 
372     /**
373      * {@inheritDoc}
374      * 
375      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.UpdatePropertiesRequest)
376      */
377     @Override
378     public void process( UpdatePropertiesRequest request ) {
379         if (!updatesAllowed(request)) return;
380 
381         MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
382         MapNode node = getTargetNode(workspace, request, request.on());
383         if (node == null) return;
384         // Now set (or remove) the properties to the supplied node ...
385         for (Map.Entry<Name, Property> propertyEntry : request.properties().entrySet()) {
386             Property property = propertyEntry.getValue();
387             if (property == null) {
388                 node.removeProperty(propertyEntry.getKey());
389                 continue;
390             }
391             Name propName = property.getName();
392             if (!propName.equals(ModeShapeLexicon.UUID)) {
393                 if (node.getProperties().get(propName) == null) {
394                     // It is a new property ...
395                     request.setNewProperty(propName);
396                 }
397                 node.setProperty(property);
398             }
399         }
400         Location actualLocation = getActualLocation(request.on(), node);
401         request.setActualLocationOfNode(actualLocation);
402         recordChange(request);
403     }
404 
405     /**
406      * {@inheritDoc}
407      * 
408      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.CreateWorkspaceRequest)
409      */
410     @Override
411     public void process( CreateWorkspaceRequest request ) {
412         if (!updatesAllowed(request)) return;
413 
414         MapWorkspace workspace = repository.createWorkspace(getExecutionContext(),
415                                                             request.desiredNameOfNewWorkspace(),
416                                                             request.conflictBehavior());
417         if (workspace == null) {
418             String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(),
419                                                                            repository.getSourceName());
420             request.setError(new InvalidWorkspaceException(msg));
421         } else {
422             MapNode root = workspace.getRoot();
423             request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
424             request.setActualWorkspaceName(workspace.getName());
425             recordChange(request);
426         }
427     }
428 
429     /**
430      * {@inheritDoc}
431      * 
432      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.DestroyWorkspaceRequest)
433      */
434     @Override
435     public void process( DestroyWorkspaceRequest request ) {
436         if (!updatesAllowed(request)) return;
437 
438         MapWorkspace workspace = repository.getWorkspace(request.workspaceName());
439         if (workspace != null) {
440             MapNode root = workspace.getRoot();
441             request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
442             recordChange(request);
443         } else {
444             String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName());
445             request.setError(new InvalidWorkspaceException(msg));
446         }
447     }
448 
449     /**
450      * {@inheritDoc}
451      * 
452      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.GetWorkspacesRequest)
453      */
454     @Override
455     public void process( GetWorkspacesRequest request ) {
456         Set<String> names = repository.getWorkspaceNames();
457         request.setAvailableWorkspaceNames(new HashSet<String>(names));
458         setCacheableInfo(request);
459     }
460 
461     /**
462      * {@inheritDoc}
463      * 
464      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.VerifyWorkspaceRequest)
465      */
466     @Override
467     public void process( VerifyWorkspaceRequest request ) {
468         MapWorkspace original = getWorkspace(request, request.workspaceName());
469         if (original != null) {
470             Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
471             request.setActualRootLocation(Location.create(path, original.getRoot().getUuid()));
472             request.setActualWorkspaceName(original.getName());
473         }
474     }
475 
476     /**
477      * {@inheritDoc}
478      * 
479      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.CloneWorkspaceRequest)
480      */
481     @Override
482     public void process( CloneWorkspaceRequest request ) {
483         if (!updatesAllowed(request)) return;
484 
485         // Find the original workspace that we're cloning ...
486         final ExecutionContext context = getExecutionContext();
487         String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
488         String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned();
489         MapWorkspace original = repository.getWorkspace(nameOfWorkspaceToBeCloned);
490         MapWorkspace target = repository.getWorkspace(targetWorkspaceName);
491 
492         if (target != null) {
493             String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
494             request.setError(new InvalidWorkspaceException(msg));
495             return;
496         }
497 
498         if (original == null) {
499             switch (request.cloneConflictBehavior()) {
500                 case DO_NOT_CLONE:
501                     String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned,
502                                                                                   repository.getSourceName());
503                     request.setError(new InvalidWorkspaceException(msg));
504                     return;
505                 case SKIP_CLONE:
506                     target = repository.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior());
507                     assert target != null;
508 
509                     MapNode root = target.getRoot();
510                     request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
511                     request.setActualWorkspaceName(target.getName());
512                     return;
513             }
514         }
515         assert original != null;
516         target = repository.createWorkspace(context,
517                                             targetWorkspaceName,
518                                             request.targetConflictBehavior(),
519                                             nameOfWorkspaceToBeCloned);
520         assert target != null;
521         MapNode root = target.getRoot();
522         request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
523         request.setActualWorkspaceName(target.getName());
524         recordChange(request);
525     }
526 
527     /**
528      * {@inheritDoc}
529      * 
530      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.AccessQueryRequest)
531      */
532     @Override
533     public void process( AccessQueryRequest request ) {
534         MapWorkspace workspace = getWorkspace(request, request.workspace());
535         if (workspace == null) return;
536         final ExecutionContext context = getExecutionContext();
537         QueryResults results = workspace.query(context, request);
538         if (results != null) {
539             request.setResults(results.getTuples(), results.getStatistics());
540         } else {
541             super.processUnknownRequest(request);
542         }
543     }
544 
545     /**
546      * {@inheritDoc}
547      * 
548      * @see org.modeshape.graph.request.processor.RequestProcessor#process(org.modeshape.graph.request.FullTextSearchRequest)
549      */
550     @Override
551     public void process( FullTextSearchRequest request ) {
552         MapWorkspace workspace = getWorkspace(request, request.workspace());
553         if (workspace == null) return;
554         final ExecutionContext context = getExecutionContext();
555         QueryResults results = workspace.search(context, request.expression());
556         if (results != null) {
557             request.setResults(results.getColumns(), results.getTuples(), results.getStatistics());
558         } else {
559             super.processUnknownRequest(request);
560         }
561     }
562 
563     protected Location getActualLocation( Location location,
564                                           MapNode node ) {
565         Path path = location.getPath();
566         if (path == null) {
567             // Find the path on the node ...
568             LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
569             MapNode n = node;
570             while (n != null) {
571                 if (n.getParent() == null) break;
572                 segments.addFirst(n.getName());
573                 n = n.getParent();
574             }
575             path = pathFactory.createAbsolutePath(segments);
576         }
577         // If there is a UUID in the location, it should match the node's.
578         assert location.getUuid() == null || location.getUuid().equals(node.getUuid());
579         if (location.hasIdProperties()) {
580             return location.with(path);
581         }
582         return Location.create(path, node.getUuid());
583     }
584 
585     protected MapWorkspace getWorkspace( Request request,
586                                          String workspaceName ) {
587         // Get the workspace for this request ...
588         MapWorkspace workspace = repository.getWorkspace(workspaceName);
589         if (workspace == null) {
590             String msg = GraphI18n.workspaceDoesNotExistInRepository.text(workspaceName, repository.getSourceName());
591             request.setError(new InvalidWorkspaceException(msg));
592         }
593         return workspace;
594     }
595 
596     protected boolean updatesAllowed( Request request ) {
597         if (!updatesAllowed) {
598             request.setError(new InvalidRequestException(GraphI18n.sourceIsReadOnly.text(getSourceName())));
599         }
600         return !request.hasError();
601     }
602 
603     protected MapNode getTargetNode( MapWorkspace workspace,
604                                      Request request,
605                                      Location location ) {
606         if (workspace == null) return null;
607         // Check first for the UUID ...
608         MapNode node = null;
609         UUID uuid = location.getUuid();
610         if (uuid != null) {
611             node = workspace.getNode(uuid);
612         }
613         Path path = null;
614         if (node == null) {
615             // Look up the node with the supplied path ...
616             path = location.getPath();
617             if (path != null) {
618                 node = workspace.getNode(path);
619             }
620         }
621         if (node == null && request != null) {
622             if (path == null) {
623                 if (uuid == null) {
624                     // Missing both path and UUID ...
625                     I18n msg = GraphI18n.inMemoryConnectorRequestsMustHavePathOrUuid;
626                     request.setError(new IllegalArgumentException(msg.text()));
627                     return null;
628                 }
629                 // Missing path, and could not find by UUID ...
630                 request.setError(new PathNotFoundException(location, pathFactory.createRootPath(),
631                                                            GraphI18n.nodeDoesNotExist.text(path)));
632                 return null;
633             }
634             // Could not find the node given the supplied path, so find the lowest path that does exist ...
635             Path lowestExisting = workspace.getLowestExistingPath(path);
636             request.setError(new PathNotFoundException(location, lowestExisting, GraphI18n.nodeDoesNotExist.text(path)));
637         }
638         return node;
639     }
640 }