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;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.Reader;
30 import java.math.BigDecimal;
31 import java.net.URI;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Date;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.UUID;
44 import java.util.concurrent.TimeUnit;
45 import net.jcip.annotations.Immutable;
46 import net.jcip.annotations.NotThreadSafe;
47 import org.modeshape.common.collection.EmptyIterator;
48 import org.modeshape.common.collection.Problems;
49 import org.modeshape.common.i18n.I18n;
50 import org.modeshape.common.util.CheckArg;
51 import org.modeshape.graph.cache.CachePolicy;
52 import org.modeshape.graph.connector.RepositoryConnection;
53 import org.modeshape.graph.connector.RepositoryConnectionFactory;
54 import org.modeshape.graph.connector.RepositorySource;
55 import org.modeshape.graph.connector.RepositorySourceException;
56 import org.modeshape.graph.io.GraphImporter;
57 import org.modeshape.graph.property.Binary;
58 import org.modeshape.graph.property.DateTime;
59 import org.modeshape.graph.property.Name;
60 import org.modeshape.graph.property.NameFactory;
61 import org.modeshape.graph.property.Path;
62 import org.modeshape.graph.property.PathNotFoundException;
63 import org.modeshape.graph.property.Property;
64 import org.modeshape.graph.property.PropertyFactory;
65 import org.modeshape.graph.property.Reference;
66 import org.modeshape.graph.property.ValueFactory;
67 import org.modeshape.graph.property.ValueFormatException;
68 import org.modeshape.graph.property.Path.Segment;
69 import org.modeshape.graph.query.QueryContext;
70 import org.modeshape.graph.query.QueryEngine;
71 import org.modeshape.graph.query.QueryResults;
72 import org.modeshape.graph.query.QueryResults.Columns;
73 import org.modeshape.graph.query.model.QueryCommand;
74 import org.modeshape.graph.query.model.TypeSystem;
75 import org.modeshape.graph.query.optimize.Optimizer;
76 import org.modeshape.graph.query.optimize.RuleBasedOptimizer;
77 import org.modeshape.graph.query.plan.CanonicalPlanner;
78 import org.modeshape.graph.query.plan.PlanHints;
79 import org.modeshape.graph.query.plan.PlanNode;
80 import org.modeshape.graph.query.plan.Planner;
81 import org.modeshape.graph.query.process.AbstractAccessComponent;
82 import org.modeshape.graph.query.process.ProcessingComponent;
83 import org.modeshape.graph.query.process.Processor;
84 import org.modeshape.graph.query.process.QueryProcessor;
85 import org.modeshape.graph.query.process.SelectComponent.Analyzer;
86 import org.modeshape.graph.query.validate.Schemata;
87 import org.modeshape.graph.request.AccessQueryRequest;
88 import org.modeshape.graph.request.BatchRequestBuilder;
89 import org.modeshape.graph.request.CacheableRequest;
90 import org.modeshape.graph.request.CloneWorkspaceRequest;
91 import org.modeshape.graph.request.CompositeRequest;
92 import org.modeshape.graph.request.CreateNodeRequest;
93 import org.modeshape.graph.request.CreateWorkspaceRequest;
94 import org.modeshape.graph.request.FullTextSearchRequest;
95 import org.modeshape.graph.request.InvalidRequestException;
96 import org.modeshape.graph.request.InvalidWorkspaceException;
97 import org.modeshape.graph.request.ReadAllChildrenRequest;
98 import org.modeshape.graph.request.ReadAllPropertiesRequest;
99 import org.modeshape.graph.request.ReadBranchRequest;
100 import org.modeshape.graph.request.ReadNodeRequest;
101 import org.modeshape.graph.request.ReadPropertyRequest;
102 import org.modeshape.graph.request.Request;
103 import org.modeshape.graph.request.RequestBuilder;
104 import org.modeshape.graph.request.RequestType;
105 import org.modeshape.graph.request.UnsupportedRequestException;
106 import org.modeshape.graph.request.VerifyWorkspaceRequest;
107 import org.modeshape.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
108 import org.modeshape.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
109 import org.xml.sax.SAXException;
110
111 /**
112 * A graph representation of the content within a {@link RepositorySource}, including mechanisms to interact and manipulate that
113 * content. The graph is designed to be an <i><a href="http://en.wikipedia.org/wiki/Domain_Specific_Language">embedded domain
114 * specific language</a></i>, meaning calls to it are designed to read like sentences even though they are really just Java
115 * methods. And to be more readable, methods can be chained together.
116 */
117 @NotThreadSafe
118 public class Graph {
119
120 protected static final Iterator<Property> EMPTY_PROPERTIES = new EmptyIterator<Property>();
121 protected static final Iterable<Property> NO_PROPERTIES = new Iterable<Property>() {
122 public final Iterator<Property> iterator() {
123 return EMPTY_PROPERTIES;
124 }
125 };
126
127 /**
128 * Create a graph instance that uses the supplied repository and {@link ExecutionContext context}.
129 *
130 * @param sourceName the name of the source that should be used
131 * @param connectionFactory the factory of repository connections
132 * @param context the context in which all executions should be performed
133 * @return the new graph
134 * @throws IllegalArgumentException if the source or context parameters are null
135 * @throws RepositorySourceException if a source with the supplied name does not exist
136 */
137 public static Graph create( String sourceName,
138 RepositoryConnectionFactory connectionFactory,
139 ExecutionContext context ) {
140 return new Graph(sourceName, connectionFactory, context);
141 }
142
143 /**
144 * Create a graph instance that uses the supplied {@link RepositoryConnection} and {@link ExecutionContext context}.
145 *
146 * @param connection the connection that should be used
147 * @param context the context in which all executions should be performed
148 * @return the new graph
149 * @throws IllegalArgumentException if the connection or context parameters are null
150 */
151 public static Graph create( final RepositoryConnection connection,
152 ExecutionContext context ) {
153 CheckArg.isNotNull(connection, "connection");
154 final String connectorSourceName = connection.getSourceName();
155 RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
156 public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
157 if (connectorSourceName.equals(sourceName)) return connection;
158 return null;
159 }
160 };
161 return new Graph(connectorSourceName, connectionFactory, context);
162 }
163
164 /**
165 * Create a graph instance that uses the supplied {@link RepositoryConnection} and {@link ExecutionContext context}.
166 *
167 * @param source the source that should be used
168 * @param context the context in which all executions should be performed
169 * @return the new graph
170 * @throws IllegalArgumentException if the connection or context parameters are null
171 */
172 public static Graph create( final RepositorySource source,
173 ExecutionContext context ) {
174 CheckArg.isNotNull(source, "source");
175 final String connectorSourceName = source.getName();
176 RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
177 public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
178 if (connectorSourceName.equals(sourceName)) return source.getConnection();
179 return null;
180 }
181 };
182 return new Graph(connectorSourceName, connectionFactory, context);
183 }
184
185 private final String sourceName;
186 private final RepositoryConnectionFactory connectionFactory;
187 protected final ExecutionContext context;
188 protected final RequestBuilder requests;
189 protected final Conjunction<Graph> nextGraph;
190 private Workspace currentWorkspace;
191 private QueryEngine queryEngine;
192
193 protected Graph( String sourceName,
194 RepositoryConnectionFactory connectionFactory,
195 ExecutionContext context ) {
196 CheckArg.isNotNull(sourceName, "sourceName");
197 CheckArg.isNotNull(connectionFactory, "connectionFactory");
198 CheckArg.isNotNull(context, "context");
199 this.sourceName = sourceName;
200 this.connectionFactory = connectionFactory;
201 this.context = context;
202 this.nextGraph = new Conjunction<Graph>() {
203 public Graph and() {
204 return Graph.this;
205 }
206 };
207 this.requests = new RequestBuilder() {
208 @Override
209 protected <T extends Request> T process( T request ) {
210 Graph.this.execute(request);
211 return request;
212 }
213 };
214 }
215
216 /**
217 * Get the RepositoryConnectionFactory that this graph uses to create {@link RepositoryConnection repository connections}.
218 *
219 * @return the factory repository connections used by this graph; never null
220 */
221 public RepositoryConnectionFactory getConnectionFactory() {
222 return connectionFactory;
223 }
224
225 /**
226 * The name of the repository that will be used by this graph. This name is passed to the {@link #getConnectionFactory()
227 * connection factory} when this graph needs to {@link RepositoryConnectionFactory#createConnection(String) obtain} a
228 * {@link RepositoryConnection repository connection}.
229 *
230 * @return the name of the source
231 */
232 public String getSourceName() {
233 return sourceName;
234 }
235
236 /**
237 * Get the context of execution within which operations on this graph are performed.
238 *
239 * @return the execution context; never null
240 */
241 public ExecutionContext getContext() {
242 return context;
243 }
244
245 /**
246 * Obtain a connection to the source, execute the supplied request, and check the request for {@link Request#getError()
247 * errors}. If an error is found, then it is thrown (or wrapped by a {@link RepositorySourceException} if the error is not a
248 * {@link RuntimeException}.
249 * <p>
250 * This method is called automatically when the {@link #requests request builder} creates each request.
251 * </p>
252 *
253 * @param request the request to be executed (may be a {@link CompositeRequest}.
254 * @throws PathNotFoundException if the request used a node that did not exist
255 * @throws InvalidRequestException if the request was not valid
256 * @throws InvalidWorkspaceException if the workspace used in the request was not valid
257 * @throws UnsupportedRequestException if the request was not supported by the source
258 * @throws RepositorySourceException if an error occurs during execution
259 * @throws RuntimeException if a runtime error occurs during execution
260 */
261 protected void execute( Request request ) {
262 RepositoryConnection connection = Graph.this.getConnectionFactory().createConnection(getSourceName());
263 if (connection == null) {
264 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
265 }
266 try {
267 connection.execute(Graph.this.getContext(), request);
268 } finally {
269 connection.close();
270 }
271 if (request.hasError()) {
272 Throwable error = request.getError();
273 if (error instanceof RuntimeException) throw (RuntimeException)error;
274 throw new RepositorySourceException(getSourceName(), error);
275 }
276 }
277
278 /**
279 * Get the default cache policy for this graph. May be null if such a policy has not been defined for thie
280 * {@link #getSourceName() source}.
281 *
282 * @return the default cache policy, or null if no such policy has been defined for the source
283 * @throws RepositorySourceException if no repository source with the {@link #getSourceName() name} could be found
284 */
285 public CachePolicy getDefaultCachePolicy() {
286 RepositoryConnection connection = this.connectionFactory.createConnection(getSourceName());
287 if (connection == null) {
288 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
289 }
290 try {
291 return connection.getDefaultCachePolicy();
292 } finally {
293 connection.close();
294 }
295 }
296
297 /**
298 * Utility method to set the workspace that will be used by this graph.
299 *
300 * @param workspaceName the name of the workspace; may not be null
301 * @param actualRootLocation the actual location of the root node in the workspace; may not be null
302 * @return the workspace; never null
303 */
304 protected Workspace setWorkspace( String workspaceName,
305 Location actualRootLocation ) {
306 assert workspaceName != null;
307 assert actualRootLocation != null;
308 this.currentWorkspace = new GraphWorkspace(workspaceName, actualRootLocation);
309 return this.currentWorkspace;
310 }
311
312 /**
313 * Get the name of the current workspace being used by this graph. If the graph has not yet been instructed to
314 * {@link #useWorkspace(String) use} or {@link #createWorkspace() create} a workspace, this method will assume that the
315 * source's default workspace is to be used and will obtain from the source the name of that default workspace.
316 *
317 * @return the name of the current workspace; never null
318 * @see #getCurrentWorkspace()
319 */
320 public String getCurrentWorkspaceName() {
321 return getCurrentWorkspace().getName();
322 }
323
324 /**
325 * Get the name of the current workspace being used by this graph. If the graph has not yet been instructed to
326 * {@link #useWorkspace(String) use} or {@link #createWorkspace() create} a workspace, this method will assume that the
327 * source's default workspace is to be used and will obtain from the source the name of that default workspace. If the source
328 * does not have a default workspace, this method will fail with an {@link InvalidWorkspaceException}.
329 *
330 * @return the name of the current workspace; never null
331 * @see #getCurrentWorkspaceName()
332 * @throws InvalidWorkspaceException if there is no current workspace
333 */
334 public Workspace getCurrentWorkspace() {
335 if (this.currentWorkspace == null) {
336 useWorkspace(null);
337 }
338 assert this.currentWorkspace != null;
339 return this.currentWorkspace;
340 }
341
342 /**
343 * Get the set of workspace names that are known to this source and accessible by this {@link #getContext() context}.
344 *
345 * @return the set of workspace names; never null
346 */
347 public Set<String> getWorkspaces() {
348 return requests.getWorkspaces().getAvailableWorkspaceNames();
349 }
350
351 /**
352 * Switch this graph to use another existing workspace in the same source.
353 *
354 * @param workspaceName the name of the existing workspace that this graph should begin using, or null if the graph should use
355 * the "default" workspace in the source (if there is one)
356 * @return the workspace; never null
357 * @throws InvalidWorkspaceException if the workspace with the supplied name does not exist, or if null is supplied as the
358 * workspace name but the source does not have a default workspace
359 */
360 public Workspace useWorkspace( String workspaceName ) {
361 VerifyWorkspaceRequest request = requests.verifyWorkspace(workspaceName);
362 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
363 }
364
365 /**
366 * Create a new workspace in the source used by this graph. This graph's workspace will be set as soon as the new workspace is
367 * created, and all subsequent operations will use the new workspace (until it is changed again by
368 * {@link #useWorkspace(String) using another workspace} or {@link #createWorkspace() creating another}.
369 *
370 * @return the interface used to complete the request to create a new workspace; never null
371 */
372 public CreateWorkspace createWorkspace() {
373 return new CreateWorkspace() {
374 /**
375 * {@inheritDoc}
376 *
377 * @see org.modeshape.graph.Graph.NameWorkspace#named(java.lang.String)
378 */
379 public Workspace named( String workspaceName ) {
380 CreateWorkspaceRequest request = requests.createWorkspace(workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
381 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
382 }
383
384 /**
385 * {@inheritDoc}
386 *
387 * @see org.modeshape.graph.Graph.CreateWorkspace#namedSomethingLike(java.lang.String)
388 */
389 public Workspace namedSomethingLike( String workspaceName ) {
390 CreateWorkspaceRequest request = requests.createWorkspace(workspaceName,
391 CreateConflictBehavior.CREATE_WITH_ADJUSTED_NAME);
392 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
393 }
394
395 /**
396 * {@inheritDoc}
397 *
398 * @see org.modeshape.graph.Graph.CreateWorkspace#clonedFrom(java.lang.String)
399 */
400 public NameWorkspace clonedFrom( final String nameOfWorkspaceToClone ) {
401 return new NameWorkspace() {
402 /**
403 * {@inheritDoc}
404 *
405 * @see org.modeshape.graph.Graph.NameWorkspace#named(java.lang.String)
406 */
407 public Workspace named( String nameOfWorkspaceToCreate ) {
408 CloneWorkspaceRequest request = requests.cloneWorkspace(nameOfWorkspaceToClone,
409 nameOfWorkspaceToCreate,
410 CreateConflictBehavior.DO_NOT_CREATE,
411 CloneConflictBehavior.DO_NOT_CLONE);
412 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
413 }
414
415 /**
416 * {@inheritDoc}
417 *
418 * @see org.modeshape.graph.Graph.NameWorkspace#namedSomethingLike(java.lang.String)
419 */
420 public Workspace namedSomethingLike( String nameOfWorkspaceToCreate ) {
421 CloneWorkspaceRequest request = requests.cloneWorkspace(nameOfWorkspaceToClone,
422 nameOfWorkspaceToCreate,
423 CreateConflictBehavior.CREATE_WITH_ADJUSTED_NAME,
424 CloneConflictBehavior.DO_NOT_CLONE);
425 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
426 }
427 };
428 }
429 };
430 }
431
432 /**
433 * Request to lock the specified node. This request is submitted to the repository immediately.
434 *
435 * @param at the node that is to be locked
436 * @return an object that allows the scope of the lock to be defined
437 */
438 public LockScope<LockTimeout<Conjunction<Graph>>> lock( Node at ) {
439 return lock(at.getLocation());
440 }
441
442 /**
443 * Request to lock the node at the given path. This request is submitted to the repository immediately.
444 *
445 * @param atPath the path of the node that is to be locked
446 * @return an object that allows the scope of the lock to be defined
447 */
448 public LockScope<LockTimeout<Conjunction<Graph>>> lock( String atPath ) {
449 return lock(Location.create(createPath(atPath)));
450 }
451
452 /**
453 * Request to lock the node at the given path. This request is submitted to the repository immediately.
454 *
455 * @param at the path of the node that is to be locked
456 * @return an object that allows the scope of the lock to be defined
457 */
458 public LockScope<LockTimeout<Conjunction<Graph>>> lock( Path at ) {
459 return lock(Location.create(at));
460 }
461
462 /**
463 * Request to lock the node with the given UUID. This request is submitted to the repository immediately.
464 *
465 * @param at the UUID of the node that is to be locked
466 * @return an object that allows the scope of the lock to be defined
467 */
468 public LockScope<LockTimeout<Conjunction<Graph>>> lock( UUID at ) {
469 return lock(Location.create(at));
470 }
471
472 /**
473 * Request to lock the node with the given unique identification property. This request is submitted to the repository
474 * immediately.
475 *
476 * @param idProperty the unique identifying property of the node that is to be locked
477 * @return an object that allows the scope of the lock to be defined
478 */
479 public LockScope<LockTimeout<Conjunction<Graph>>> lock( Property idProperty ) {
480 return lock(Location.create(idProperty));
481 }
482
483 /**
484 * Request to lock the node with the given identification properties. The identification properties should uniquely identify a
485 * single node. This request is submitted to the repository immediately.
486 *
487 * @param firstIdProperty the first identification property of the node that is to be copied
488 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
489 * @return an object that allows the scope of the lock to be defined
490 */
491 public LockScope<LockTimeout<Conjunction<Graph>>> lock( Property firstIdProperty,
492 Property... additionalIdProperties ) {
493 return lock(Location.create(firstIdProperty, additionalIdProperties));
494 }
495
496 /**
497 * Request to lock the node at the given location. This request is submitted to the repository immediately.
498 *
499 * @param at the location of the node that is to be locked
500 * @return an object that allows the scope of the lock to be defined
501 */
502 public LockScope<LockTimeout<Conjunction<Graph>>> lock( Location at ) {
503 return new LockAction<Conjunction<Graph>>(this.nextGraph, at) {
504 @Override
505 protected Conjunction<Graph> submit( Location target,
506 org.modeshape.graph.request.LockBranchRequest.LockScope lockScope,
507 long lockTimeoutInMillis ) {
508 String workspaceName = getCurrentWorkspaceName();
509 requests.lockBranch(workspaceName, target, lockScope, lockTimeoutInMillis);
510 return and();
511 }
512 };
513 }
514
515 /**
516 * Request to unlock the specified node. This request is submitted to the repository immediately.
517 *
518 * @param at the node that is to be unlocked
519 * @return an object that may be used to start another request
520 */
521 public Conjunction<Graph> unlock( Node at ) {
522 return unlock(at.getLocation());
523 }
524
525 /**
526 * Request to unlock the node at the given path. This request is submitted to the repository immediately.
527 *
528 * @param atPath the path of the node that is to be unlocked
529 * @return an object that may be used to start another request
530 */
531 public Conjunction<Graph> unlock( String atPath ) {
532 return unlock(Location.create(createPath(atPath)));
533 }
534
535 /**
536 * Request to unlock the node at the given path. This request is submitted to the repository immediately.
537 *
538 * @param at the path of the node that is to be unlocked
539 * @return an object that may be used to start another request
540 */
541 public Conjunction<Graph> unlock( Path at ) {
542 return unlock(Location.create(at));
543 }
544
545 /**
546 * Request to unlock the node with the given UUID. This request is submitted to the repository immediately.
547 *
548 * @param at the UUID of the node that is to be unlocked
549 * @return an object that may be used to start another request
550 */
551 public Conjunction<Graph> unlock( UUID at ) {
552 return unlock(Location.create(at));
553 }
554
555 /**
556 * Request to unlock the node with the given unique identification property. This request is submitted to the repository
557 * immediately.
558 *
559 * @param idProperty the unique identifying property of the node that is to be unlocked
560 * @return an object that may be used to start another request
561 */
562 public Conjunction<Graph> unlock( Property idProperty ) {
563 return unlock(Location.create(idProperty));
564 }
565
566 /**
567 * Request to unlock the node with the given identification properties. The identification properties should uniquely identify
568 * a single node. This request is submitted to the repository immediately.
569 *
570 * @param firstIdProperty the first identification property of the node that is to be copied
571 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
572 * @return an object that may be used to start another request
573 */
574 public Conjunction<Graph> unlock( Property firstIdProperty,
575 Property... additionalIdProperties ) {
576 return unlock(Location.create(firstIdProperty, additionalIdProperties));
577 }
578
579 /**
580 * Request to unlock the node at the given location. This request is submitted to the repository immediately.
581 *
582 * @param at the location of the node that is to be unlocked
583 * @return an object that may be used to start another request
584 */
585 public Conjunction<Graph> unlock( Location at ) {
586 String workspaceName = getCurrentWorkspaceName();
587 requests.unlockBranch(workspaceName, at);
588 return this.nextGraph;
589 }
590
591 /**
592 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
593 * <code>into(...)</code> method on the returned {@link Move} object.
594 * <p>
595 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
596 * method is called.
597 * </p>
598 *
599 * @param from the node that is to be moved.
600 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
601 * be moved
602 */
603 public Move<Conjunction<Graph>> move( Node from ) {
604 return move(from.getLocation());
605 }
606
607 /**
608 * Begin the request to move a node at the specified location into a parent node at a different location, which is specified
609 * via the <code>into(...)</code> method on the returned {@link Move} object.
610 * <p>
611 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
612 * method is called.
613 * </p>
614 *
615 * @param from the location of the node that is to be moved.
616 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
617 * be moved
618 */
619 public Move<Conjunction<Graph>> move( Location from ) {
620 return new MoveAction<Conjunction<Graph>>(this.nextGraph, from) {
621 @Override
622 protected Conjunction<Graph> submit( Locations from,
623 Location into,
624 Location before,
625 Name newName ) {
626 String workspaceName = getCurrentWorkspaceName();
627 do {
628 requests.moveBranch(from.getLocation(), into, before, workspaceName, newName);
629 } while ((from = from.next()) != null);
630 return and();
631 }
632 };
633 }
634
635 /**
636 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
637 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
638 * <p>
639 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
640 * method is called.
641 * </p>
642 *
643 * @param fromPath the path to the node that is to be moved.
644 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
645 * be moved
646 */
647 public Move<Conjunction<Graph>> move( String fromPath ) {
648 return move(Location.create(createPath(fromPath)));
649 }
650
651 /**
652 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
653 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
654 * <p>
655 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
656 * method is called.
657 * </p>
658 *
659 * @param from the path to the node that is to be moved.
660 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
661 * be moved
662 */
663 public Move<Conjunction<Graph>> move( Path from ) {
664 return move(Location.create(from));
665 }
666
667 /**
668 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which is
669 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
670 * <p>
671 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
672 * method is called.
673 * </p>
674 *
675 * @param from the UUID of the node that is to be moved.
676 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
677 * be moved
678 */
679 public Move<Conjunction<Graph>> move( UUID from ) {
680 return move(Location.create(from));
681 }
682
683 /**
684 * Begin the request to move a node with the specified unique identification property into a parent node at a different
685 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification
686 * property should uniquely identify a single node.
687 * <p>
688 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
689 * method is called.
690 * </p>
691 *
692 * @param idProperty the unique identification property of the node that is to be moved.
693 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
694 * be moved
695 */
696 public Move<Conjunction<Graph>> move( Property idProperty ) {
697 return move(Location.create(idProperty));
698 }
699
700 /**
701 * Begin the request to move a node with the specified identification properties into a parent node at a different location,
702 * which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification properties
703 * should uniquely identify a single node.
704 * <p>
705 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
706 * method is called.
707 * </p>
708 *
709 * @param firstIdProperty the first identification property of the node that is to be moved
710 * @param additionalIdProperties the remaining identification properties of the node that is to be moved
711 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is to
712 * be moved
713 */
714 public Move<Conjunction<Graph>> move( Property firstIdProperty,
715 Property... additionalIdProperties ) {
716 return move(Location.create(firstIdProperty, additionalIdProperties));
717 }
718
719 /**
720 * Begin the request to clone a node at the specified location into a parent node at a different location, which is specified
721 * via the <code>into(...)</code> method on the returned {@link Clone} object.
722 * <p>
723 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
724 * behavior} is specified.
725 * </p>
726 * <p>
727 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
728 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
729 * copy operation always generates new UUIDs).
730 * </p>
731 *
732 * @param from the location of the node that is to be cloned.
733 * @return the object that can be used to specify the location of the node where the node is to be cloned
734 */
735 public Clone<Graph> clone( Location from ) {
736 return new CloneAction<Graph>(this, from) {
737 @Override
738 protected Graph submit( String fromWorkspaceName,
739 Location from,
740 String intoWorkspaceName,
741 Location into,
742 Name desiredName,
743 Segment desiredSegment,
744 boolean removeExisting ) {
745 requests.cloneBranch(from,
746 fromWorkspaceName,
747 into,
748 intoWorkspaceName,
749 desiredName,
750 desiredSegment,
751 removeExisting);
752 return and();
753 }
754 };
755 }
756
757 /**
758 * Begin the request to clone the specified node into a parent node at a different location, which is specified via the
759 * <code>into(...)</code> method on the returned {@link Clone} object.
760 * <p>
761 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
762 * behavior} is specified.
763 * </p>
764 * <p>
765 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
766 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
767 * copy operation always generates new UUIDs).
768 * </p>
769 *
770 * @param from the node that is to be copied.
771 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
772 * be copied
773 */
774 public Clone<Graph> clone( Node from ) {
775 return clone(from.getLocation());
776 }
777
778 /**
779 * Begin the request to clone a node located at the supplied path into a parent node at a different location, which is
780 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
781 * <p>
782 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
783 * behavior} is specified.
784 * </p>
785 * <p>
786 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
787 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
788 * copy operation always generates new UUIDs).
789 * </p>
790 *
791 * @param fromPath the path to the node that is to be copied.
792 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
793 * be copied
794 */
795 public Clone<Graph> clone( String fromPath ) {
796 return clone(Location.create(createPath(fromPath)));
797 }
798
799 /**
800 * Begin the request to clone a node located at the supplied path into a parent node at a different location, which is
801 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
802 * <p>
803 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
804 * behavior} is specified.
805 * </p>
806 * <p>
807 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
808 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
809 * copy operation always generates new UUIDs).
810 * </p>
811 *
812 * @param from the path to the node that is to be copied.
813 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
814 * be copied
815 */
816 public Clone<Graph> clone( Path from ) {
817 return clone(Location.create(from));
818 }
819
820 /**
821 * Begin the request to clone a node with the specified unique identifier into a parent node at a different location, which is
822 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
823 * <p>
824 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
825 * behavior} is specified.
826 * </p>
827 * <p>
828 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
829 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
830 * copy operation always generates new UUIDs).
831 * </p>
832 *
833 * @param from the UUID of the node that is to be copied.
834 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
835 * be copied
836 */
837 public Clone<Graph> clone( UUID from ) {
838 return clone(Location.create(from));
839 }
840
841 /**
842 * Begin the request to clone a node with the specified unique identification property into a parent node at a different
843 * location, which is specified via the <code>into(...)</code> method on the returned {@link Clone} object. The identification
844 * property should uniquely identify a single node.
845 * <p>
846 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
847 * behavior} is specified.
848 * </p>
849 * <p>
850 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
851 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
852 * copy operation always generates new UUIDs).
853 * </p>
854 *
855 * @param idProperty the unique identification property of the node that is to be copied.
856 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
857 * be copied
858 */
859 public Clone<Graph> clone( Property idProperty ) {
860 return clone(Location.create(idProperty));
861 }
862
863 /**
864 * Begin the request to clone a node with the specified identification properties into a parent node at a different location,
865 * which is specified via the <code>into(...)</code> method on the returned {@link Clone} object. The identification
866 * properties should uniquely identify a single node.
867 * <p>
868 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the {@link WithUuids UUID
869 * behavior} is specified.
870 * </p>
871 * <p>
872 * The clone operation differs from the copy operation in that it must replicate nodes from one workspace to another (the copy
873 * operations supports replicating nodes within a workspace as well as across workspaces) and that it preserves UUIDs (the
874 * copy operation always generates new UUIDs).
875 * </p>
876 *
877 * @param firstIdProperty the first identification property of the node that is to be copied
878 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
879 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
880 * be copied
881 */
882 public Clone<Graph> clone( Property firstIdProperty,
883 Property... additionalIdProperties ) {
884 return clone(Location.create(firstIdProperty, additionalIdProperties));
885 }
886
887 /**
888 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
889 * <code>into(...)</code> method on the returned {@link Copy} object.
890 * <p>
891 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
892 * method is called.
893 * </p>
894 *
895 * @param from the node that is to be copied.
896 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
897 * be copied
898 */
899 public Copy<Graph> copy( Node from ) {
900 return copy(from.getLocation());
901 }
902
903 /**
904 * Begin the request to copy a node at the specified location into a parent node at a different location, which is specified
905 * via the <code>into(...)</code> method on the returned {@link Copy} object.
906 * <p>
907 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
908 * method is called.
909 * </p>
910 *
911 * @param from the location of the node that is to be copied.
912 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
913 * be copied
914 */
915 public Copy<Graph> copy( Location from ) {
916 return new CopyAction<Graph>(this, from) {
917 @Override
918 protected Graph submit( String fromWorkspaceName,
919 Locations from,
920 Location into,
921 Name childName ) {
922 String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName();
923 do {
924 requests.copyBranch(from.getLocation(),
925 workspaceName,
926 into,
927 getCurrentWorkspaceName(),
928 childName,
929 NodeConflictBehavior.APPEND);
930 } while ((from = from.next()) != null);
931 return and();
932 }
933 };
934 }
935
936 /**
937 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
938 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
939 * <p>
940 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
941 * method is called.
942 * </p>
943 *
944 * @param fromPath the path to the node that is to be copied.
945 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
946 * be copied
947 */
948 public Copy<Graph> copy( String fromPath ) {
949 return copy(Location.create(createPath(fromPath)));
950 }
951
952 /**
953 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
954 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
955 * <p>
956 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
957 * method is called.
958 * </p>
959 *
960 * @param from the path to the node that is to be copied.
961 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
962 * be copied
963 */
964 public Copy<Graph> copy( Path from ) {
965 return copy(Location.create(from));
966 }
967
968 /**
969 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which is
970 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
971 * <p>
972 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
973 * method is called.
974 * </p>
975 *
976 * @param from the UUID of the node that is to be copied.
977 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
978 * be copied
979 */
980 public Copy<Graph> copy( UUID from ) {
981 return copy(Location.create(from));
982 }
983
984 /**
985 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
986 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification
987 * property should uniquely identify a single node.
988 * <p>
989 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
990 * method is called.
991 * </p>
992 *
993 * @param idProperty the unique identification property of the node that is to be copied.
994 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
995 * be copied
996 */
997 public Copy<Graph> copy( Property idProperty ) {
998 return copy(Location.create(idProperty));
999 }
1000
1001 /**
1002 * Begin the request to copy a node with the specified identification properties into a parent node at a different location,
1003 * which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification properties
1004 * should uniquely identify a single node.
1005 * <p>
1006 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
1007 * method is called.
1008 * </p>
1009 *
1010 * @param firstIdProperty the first identification property of the node that is to be copied
1011 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
1012 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node is to
1013 * be copied
1014 */
1015 public Copy<Graph> copy( Property firstIdProperty,
1016 Property... additionalIdProperties ) {
1017 return copy(Location.create(firstIdProperty, additionalIdProperties));
1018 }
1019
1020 /**
1021 * Request to delete the specified node. This request is submitted to the repository immediately.
1022 *
1023 * @param at the node that is to be deleted
1024 * @return an object that may be used to start another request
1025 */
1026 public Conjunction<Graph> delete( Node at ) {
1027 requests.deleteBranch(at.getLocation(), getCurrentWorkspaceName());
1028 return nextGraph;
1029 }
1030
1031 /**
1032 * Request to delete the node at the given location. This request is submitted to the repository immediately.
1033 *
1034 * @param at the location of the node that is to be deleted
1035 * @return an object that may be used to start another request
1036 */
1037 public Conjunction<Graph> delete( Location at ) {
1038 requests.deleteBranch(at, getCurrentWorkspaceName());
1039 return nextGraph;
1040 }
1041
1042 /**
1043 * Request to delete the node at the given path. This request is submitted to the repository immediately.
1044 *
1045 * @param atPath the path of the node that is to be deleted
1046 * @return an object that may be used to start another request
1047 */
1048 public Conjunction<Graph> delete( String atPath ) {
1049 return delete(Location.create(createPath(atPath)));
1050 }
1051
1052 /**
1053 * Request to delete the node at the given path. This request is submitted to the repository immediately.
1054 *
1055 * @param at the path of the node that is to be deleted
1056 * @return an object that may be used to start another request
1057 */
1058 public Conjunction<Graph> delete( Path at ) {
1059 return delete(Location.create(at));
1060 }
1061
1062 /**
1063 * Request to delete the node with the given UUID. This request is submitted to the repository immediately.
1064 *
1065 * @param at the UUID of the node that is to be deleted
1066 * @return an object that may be used to start another request
1067 */
1068 public Conjunction<Graph> delete( UUID at ) {
1069 return delete(Location.create(at));
1070 }
1071
1072 /**
1073 * Request to delete the node with the given unique identification property. This request is submitted to the repository
1074 * immediately.
1075 *
1076 * @param idProperty the unique identifying property of the node that is to be deleted
1077 * @return an object that may be used to start another request
1078 */
1079 public Conjunction<Graph> delete( Property idProperty ) {
1080 return delete(Location.create(idProperty));
1081 }
1082
1083 /**
1084 * Request to delete the node with the given identification properties. The identification properties should uniquely identify
1085 * a single node. This request is submitted to the repository immediately.
1086 *
1087 * @param firstIdProperty the first identification property of the node that is to be copied
1088 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
1089 * @return an object that may be used to start another request
1090 */
1091 public Conjunction<Graph> delete( Property firstIdProperty,
1092 Property... additionalIdProperties ) {
1093 return delete(Location.create(firstIdProperty, additionalIdProperties));
1094 }
1095
1096 /**
1097 * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
1098 * the new node, or complete/submit the request and return the location, node, or graph.
1099 * <p>
1100 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1101 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1102 * parent or new node.
1103 * </p>
1104 *
1105 * @param atPath the path to the node that is to be created.
1106 * @return an object that may be used to start another request
1107 */
1108 public CreateAt<Graph> createAt( String atPath ) {
1109 return createAt(createPath(atPath));
1110 }
1111
1112 /**
1113 * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
1114 * the new node, or complete/submit the request and return the location, node, or graph.
1115 * <p>
1116 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1117 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1118 * parent or new node.
1119 * </p>
1120 *
1121 * @param at the path to the node that is to be created.
1122 * @return an object that may be used to start another request
1123 */
1124 public CreateAt<Graph> createAt( final Path at ) {
1125 CheckArg.isNotNull(at, "at");
1126 final Path parent = at.getParent();
1127 final Name childName = at.getLastSegment().getName();
1128 final String workspaceName = getCurrentWorkspaceName();
1129 return new CreateAt<Graph>() {
1130 private final List<Property> properties = new LinkedList<Property>();
1131
1132 public CreateAt<Graph> and( UUID uuid ) {
1133 PropertyFactory factory = getContext().getPropertyFactory();
1134 properties.add(factory.create(ModeShapeLexicon.UUID, uuid));
1135 return this;
1136 }
1137
1138 public CreateAt<Graph> and( Property property ) {
1139 properties.add(property);
1140 return this;
1141 }
1142
1143 public CreateAt<Graph> and( Iterable<Property> properties ) {
1144 for (Property property : properties) {
1145 this.properties.add(property);
1146 }
1147 return this;
1148 }
1149
1150 public CreateAt<Graph> and( String name,
1151 Object... values ) {
1152 ExecutionContext context = getContext();
1153 PropertyFactory factory = context.getPropertyFactory();
1154 NameFactory nameFactory = context.getValueFactories().getNameFactory();
1155 properties.add(factory.create(nameFactory.create(name), values));
1156 return this;
1157 }
1158
1159 public CreateAt<Graph> and( Name name,
1160 Object... values ) {
1161 ExecutionContext context = getContext();
1162 PropertyFactory factory = context.getPropertyFactory();
1163 properties.add(factory.create(name, values));
1164 return this;
1165 }
1166
1167 public CreateAt<Graph> and( Property property,
1168 Property... additionalProperties ) {
1169 properties.add(property);
1170 for (Property additionalProperty : additionalProperties) {
1171 properties.add(additionalProperty);
1172 }
1173 return this;
1174 }
1175
1176 public CreateAt<Graph> with( UUID uuid ) {
1177 return and(uuid);
1178 }
1179
1180 public CreateAt<Graph> with( Property property ) {
1181 return and(property);
1182 }
1183
1184 public CreateAt<Graph> with( Iterable<Property> properties ) {
1185 return and(properties);
1186 }
1187
1188 public CreateAt<Graph> with( Property property,
1189 Property... additionalProperties ) {
1190 return and(property, additionalProperties);
1191 }
1192
1193 public CreateAt<Graph> with( String name,
1194 Object... values ) {
1195 return and(name, values);
1196 }
1197
1198 public CreateAt<Graph> with( Name name,
1199 Object... values ) {
1200 return and(name, values);
1201 }
1202
1203 public Location getLocation() {
1204 Location parentLoc = Location.create(parent);
1205 CreateNodeRequest request = requests.createNode(parentLoc, workspaceName, childName, this.properties.iterator());
1206 return request.getActualLocationOfNode();
1207 }
1208
1209 public Node getNode() {
1210 Location parentLoc = Location.create(parent);
1211 CreateNodeRequest request = requests.createNode(parentLoc, workspaceName, childName, this.properties.iterator());
1212 return getNodeAt(request.getActualLocationOfNode());
1213 }
1214
1215 public Graph and() {
1216 requests.createNode(Location.create(parent), workspaceName, childName, this.properties.iterator());
1217 return Graph.this;
1218 }
1219 };
1220 }
1221
1222 /**
1223 * Begin the request to create a node located at the supplied path.
1224 * <p>
1225 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1226 * is called.
1227 * </p>
1228 *
1229 * @param atPath the path to the node that is to be created.
1230 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1231 * node where the node is to be created
1232 */
1233 public Create<Graph> create( String atPath ) {
1234 return create(createPath(atPath));
1235 }
1236
1237 /**
1238 * Begin the request to create a node located at the supplied path.
1239 * <p>
1240 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1241 * is called.
1242 * </p>
1243 *
1244 * @param atPath the path to the node that is to be created.
1245 * @param property a property for the new node
1246 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1247 * node where the node is to be created
1248 */
1249 public Create<Graph> create( String atPath,
1250 Property property ) {
1251 return create(createPath(atPath)).with(property);
1252 }
1253
1254 /**
1255 * Begin the request to create a node located at the supplied path.
1256 * <p>
1257 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1258 * is called.
1259 * </p>
1260 *
1261 * @param atPath the path to the node that is to be created.
1262 * @param firstProperty a property for the new node
1263 * @param additionalProperties additional properties for the new node
1264 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1265 * node where the node is to be created
1266 */
1267 public Create<Graph> create( String atPath,
1268 Property firstProperty,
1269 Property... additionalProperties ) {
1270 return create(createPath(atPath)).with(firstProperty, additionalProperties);
1271 }
1272
1273 /**
1274 * Begin the request to create a node located at the supplied path.
1275 * <p>
1276 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1277 * is called.
1278 * </p>
1279 *
1280 * @param at the path to the node that is to be created.
1281 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1282 * node where the node is to be created
1283 */
1284 public final Create<Graph> create( Path at ) {
1285 CheckArg.isNotNull(at, "at");
1286 Path parent = at.getParent();
1287 Name name = at.getLastSegment().getName();
1288 return create(Location.create(parent), name);
1289 }
1290
1291 protected final CreateAction<Graph> create( Location parent,
1292 Name child ) {
1293 return new CreateAction<Graph>(this, parent, getCurrentWorkspaceName(), child) {
1294 @Override
1295 protected Graph submit( Location parent,
1296 String workspaceName,
1297 Name childName,
1298 Collection<Property> properties,
1299 NodeConflictBehavior behavior ) {
1300 requests.createNode(parent, workspaceName, childName, properties.iterator(), behavior);
1301 return Graph.this;
1302 }
1303
1304 };
1305 }
1306
1307 /**
1308 * Begin the request to create a node located at the supplied path.
1309 * <p>
1310 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1311 * is called.
1312 * </p>
1313 *
1314 * @param at the path to the node that is to be created.
1315 * @param properties the iterator over the properties for the new node
1316 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1317 * node where the node is to be created
1318 */
1319 public Create<Graph> create( Path at,
1320 Iterable<Property> properties ) {
1321 Create<Graph> action = create(at);
1322 for (Property property : properties) {
1323 action.and(property);
1324 }
1325 return action;
1326 }
1327
1328 /**
1329 * Begin the request to create a node located at the supplied path.
1330 * <p>
1331 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1332 * is called.
1333 * </p>
1334 *
1335 * @param at the path to the node that is to be created.
1336 * @param property a property for the new node
1337 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1338 * node where the node is to be created
1339 */
1340 public Create<Graph> create( Path at,
1341 Property property ) {
1342 return create(at).with(property);
1343 }
1344
1345 /**
1346 * Begin the request to create a node located at the supplied path.
1347 * <p>
1348 * Like all other methods on the {@link Graph}, the request will be performed when the no-argument {@link Create#and()} method
1349 * is called.
1350 * </p>
1351 *
1352 * @param at the path to the node that is to be created.
1353 * @param firstProperty a property for the new node
1354 * @param additionalProperties additional properties for the new node
1355 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1356 * node where the node is to be created
1357 */
1358 public Create<Graph> create( Path at,
1359 Property firstProperty,
1360 Property... additionalProperties ) {
1361 return create(at).with(firstProperty, additionalProperties);
1362 }
1363
1364 /**
1365 * Begin the request to create a node under the existing parent node at the supplied location. Use this method if you are
1366 * creating a node when you have the {@link Location} of a parent from a previous request.
1367 * <p>
1368 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>node(...)</code>
1369 * method is called on the returned object
1370 * </p>
1371 *
1372 * @param parent the location of the parent
1373 * @return the object used to start creating a node
1374 */
1375 public CreateNode<Conjunction<Graph>> createUnder( final Location parent ) {
1376 final NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
1377 CheckArg.isNotNull(parent, "parent");
1378 return new CreateNode<Conjunction<Graph>>() {
1379 public Conjunction<Graph> node( String name,
1380 Property... properties ) {
1381 Name child = nameFactory.create(name);
1382 requests.createNode(parent, getCurrentWorkspaceName(), child, properties);
1383 return nextGraph;
1384 }
1385
1386 public Conjunction<Graph> node( String name,
1387 Iterator<Property> properties ) {
1388 Name child = nameFactory.create(name);
1389 requests.createNode(parent, getCurrentWorkspaceName(), child, properties);
1390 return nextGraph;
1391 }
1392
1393 public Conjunction<Graph> node( String name,
1394 Iterable<Property> properties ) {
1395 Name child = nameFactory.create(name);
1396 requests.createNode(parent, getCurrentWorkspaceName(), child, properties.iterator());
1397 return nextGraph;
1398 }
1399 };
1400 }
1401
1402 public AddValue<Graph> addValue( Object value ) {
1403 return new AddValueAction<Graph>(this, this.getCurrentWorkspaceName(), value) {
1404
1405 @Override
1406 protected Graph submit( String workspaceName,
1407 Location on,
1408 Name property,
1409 List<Object> values ) {
1410 requests.addValues(workspaceName, on, property, values);
1411 return nextGraph.and();
1412 }
1413 };
1414 }
1415
1416 public RemoveValue<Graph> removeValue( Object value ) {
1417 return new RemoveValueAction<Graph>(this, this.getCurrentWorkspaceName(), value) {
1418
1419 @Override
1420 protected Graph submit( String workspaceName,
1421 Location on,
1422 Name property,
1423 List<Object> values ) {
1424 requests.removeValues(workspaceName, on, property, values);
1425 return nextGraph.and();
1426 }
1427 };
1428 }
1429
1430 /**
1431 * Set the properties on a node.
1432 *
1433 * @param properties the properties to set
1434 * @return the remove request object that should be used to specify the node on which the properties are to be set.
1435 */
1436 public On<Conjunction<Graph>> set( final Property... properties ) {
1437 return new On<Conjunction<Graph>>() {
1438 public Conjunction<Graph> on( Location location ) {
1439 requests.setProperties(location, getCurrentWorkspaceName(), properties);
1440 return nextGraph;
1441 }
1442
1443 public Conjunction<Graph> on( String path ) {
1444 return on(Location.create(createPath(path)));
1445 }
1446
1447 public Conjunction<Graph> on( Path path ) {
1448 return on(Location.create(path));
1449 }
1450
1451 public Conjunction<Graph> on( Property idProperty ) {
1452 return on(Location.create(idProperty));
1453 }
1454
1455 public Conjunction<Graph> on( Property firstIdProperty,
1456 Property... additionalIdProperties ) {
1457 return on(Location.create(firstIdProperty, additionalIdProperties));
1458 }
1459
1460 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1461 return on(Location.create(idProperties));
1462 }
1463
1464 public Conjunction<Graph> on( UUID uuid ) {
1465 return on(Location.create(uuid));
1466 }
1467 };
1468 }
1469
1470 /**
1471 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
1472 * value(s) and the location of the node onto which the property should be set.
1473 *
1474 * @param propertyName the property name
1475 * @return the interface used to specify the values
1476 */
1477 public SetValues<Conjunction<Graph>> set( String propertyName ) {
1478 Name name = getContext().getValueFactories().getNameFactory().create(propertyName);
1479 return set(name);
1480 }
1481
1482 /**
1483 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
1484 * value(s) and the location of the node onto which the property should be set.
1485 *
1486 * @param propertyName the property name
1487 * @return the interface used to specify the values
1488 */
1489 public SetValues<Conjunction<Graph>> set( final Name propertyName ) {
1490 return new SetValues<Conjunction<Graph>>() {
1491 public SetValuesTo<Conjunction<Graph>> on( final Location location ) {
1492 return new SetValuesTo<Conjunction<Graph>>() {
1493 public Conjunction<Graph> to( Node value ) {
1494 Reference ref = (Reference)convertReferenceValue(value);
1495 Property property = getContext().getPropertyFactory().create(propertyName, ref);
1496 requests.setProperty(location, getCurrentWorkspaceName(), property);
1497 return nextGraph;
1498 }
1499
1500 public Conjunction<Graph> to( Location value ) {
1501 Reference ref = (Reference)convertReferenceValue(value);
1502 Property property = getContext().getPropertyFactory().create(propertyName, ref);
1503 requests.setProperty(location, getCurrentWorkspaceName(), property);
1504 return nextGraph;
1505 }
1506
1507 protected Conjunction<Graph> toValue( Object value ) {
1508 Property property = getContext().getPropertyFactory().create(propertyName, value);
1509 requests.setProperty(location, getCurrentWorkspaceName(), property);
1510 return nextGraph;
1511 }
1512
1513 public Conjunction<Graph> to( String value ) {
1514 return toValue(value);
1515 }
1516
1517 public Conjunction<Graph> to( int value ) {
1518 return toValue(Integer.valueOf(value));
1519 }
1520
1521 public Conjunction<Graph> to( long value ) {
1522 return toValue(Long.valueOf(value));
1523 }
1524
1525 public Conjunction<Graph> to( boolean value ) {
1526 return toValue(Boolean.valueOf(value));
1527 }
1528
1529 public Conjunction<Graph> to( float value ) {
1530 return toValue(Float.valueOf(value));
1531 }
1532
1533 public Conjunction<Graph> to( double value ) {
1534 return toValue(Double.valueOf(value));
1535 }
1536
1537 public Conjunction<Graph> to( BigDecimal value ) {
1538 return toValue(value);
1539 }
1540
1541 public Conjunction<Graph> to( Calendar value ) {
1542 return toValue(value);
1543 }
1544
1545 public Conjunction<Graph> to( Date value ) {
1546 return toValue(value);
1547 }
1548
1549 public Conjunction<Graph> to( DateTime value ) {
1550 return toValue(value);
1551 }
1552
1553 public Conjunction<Graph> to( Name value ) {
1554 return toValue(value);
1555 }
1556
1557 public Conjunction<Graph> to( Path value ) {
1558 return toValue(value);
1559 }
1560
1561 public Conjunction<Graph> to( Reference value ) {
1562 return toValue(value);
1563 }
1564
1565 public Conjunction<Graph> to( URI value ) {
1566 return toValue(value);
1567 }
1568
1569 public Conjunction<Graph> to( UUID value ) {
1570 return toValue(value);
1571 }
1572
1573 public Conjunction<Graph> to( Binary value ) {
1574 return toValue(value);
1575 }
1576
1577 public Conjunction<Graph> to( byte[] value ) {
1578 return toValue(value);
1579 }
1580
1581 public Conjunction<Graph> to( InputStream stream,
1582 long approximateLength ) {
1583 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
1584 return toValue(value);
1585 }
1586
1587 public Conjunction<Graph> to( Reader reader,
1588 long approximateLength ) {
1589 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
1590 return toValue(value);
1591 }
1592
1593 public Conjunction<Graph> to( Object value ) {
1594 value = convertReferenceValue(value);
1595 Property property = getContext().getPropertyFactory().create(propertyName, value);
1596 requests.setProperty(location, getCurrentWorkspaceName(), property);
1597 return nextGraph;
1598 }
1599
1600 public Conjunction<Graph> to( Object firstValue,
1601 Object... otherValues ) {
1602 firstValue = convertReferenceValue(firstValue);
1603 for (int i = 0, len = otherValues.length; i != len; ++i) {
1604 otherValues[i] = convertReferenceValue(otherValues[i]);
1605 }
1606 Property property = getContext().getPropertyFactory().create(propertyName, firstValue, otherValues);
1607 requests.setProperty(location, getCurrentWorkspaceName(), property);
1608 return nextGraph;
1609 }
1610
1611 public Conjunction<Graph> to( Object[] values ) {
1612 for (int i = 0, len = values.length; i != len; ++i) {
1613 values[i] = convertReferenceValue(values[i]);
1614 }
1615 Property property = getContext().getPropertyFactory().create(propertyName, values);
1616 requests.setProperty(location, getCurrentWorkspaceName(), property);
1617 return nextGraph;
1618 }
1619
1620 public Conjunction<Graph> to( Iterable<?> values ) {
1621 List<Object> valueList = new LinkedList<Object>();
1622 for (Object value : values) {
1623 value = convertReferenceValue(value);
1624 valueList.add(value);
1625 }
1626 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
1627 requests.setProperty(location, getCurrentWorkspaceName(), property);
1628 return nextGraph;
1629 }
1630
1631 public Conjunction<Graph> to( Iterator<?> values ) {
1632 List<Object> valueList = new LinkedList<Object>();
1633 while (values.hasNext()) {
1634 Object value = values.next();
1635 valueList.add(value);
1636 }
1637 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
1638 requests.setProperty(location, getCurrentWorkspaceName(), property);
1639 return nextGraph;
1640 }
1641 };
1642 }
1643
1644 public SetValuesTo<Conjunction<Graph>> on( String path ) {
1645 return on(Location.create(createPath(path)));
1646 }
1647
1648 public SetValuesTo<Conjunction<Graph>> on( Path path ) {
1649 return on(Location.create(path));
1650 }
1651
1652 public SetValuesTo<Conjunction<Graph>> on( Property idProperty ) {
1653 return on(Location.create(idProperty));
1654 }
1655
1656 public SetValuesTo<Conjunction<Graph>> on( Property firstIdProperty,
1657 Property... additionalIdProperties ) {
1658 return on(Location.create(firstIdProperty, additionalIdProperties));
1659 }
1660
1661 public SetValuesTo<Conjunction<Graph>> on( Iterable<Property> idProperties ) {
1662 return on(Location.create(idProperties));
1663 }
1664
1665 public SetValuesTo<Conjunction<Graph>> on( UUID uuid ) {
1666 return on(Location.create(uuid));
1667 }
1668
1669 public On<Conjunction<Graph>> to( Node node ) {
1670 Reference value = (Reference)convertReferenceValue(node);
1671 return set(getContext().getPropertyFactory().create(propertyName, value));
1672 }
1673
1674 public On<Conjunction<Graph>> to( Location location ) {
1675 Reference value = (Reference)convertReferenceValue(location);
1676 return set(getContext().getPropertyFactory().create(propertyName, value));
1677 }
1678
1679 protected On<Conjunction<Graph>> toValue( Object value ) {
1680 return set(getContext().getPropertyFactory().create(propertyName, value));
1681 }
1682
1683 public On<Conjunction<Graph>> to( String value ) {
1684 return toValue(value);
1685 }
1686
1687 public On<Conjunction<Graph>> to( int value ) {
1688 return toValue(Integer.valueOf(value));
1689 }
1690
1691 public On<Conjunction<Graph>> to( long value ) {
1692 return toValue(Long.valueOf(value));
1693 }
1694
1695 public On<Conjunction<Graph>> to( boolean value ) {
1696 return toValue(Boolean.valueOf(value));
1697 }
1698
1699 public On<Conjunction<Graph>> to( float value ) {
1700 return toValue(Float.valueOf(value));
1701 }
1702
1703 public On<Conjunction<Graph>> to( double value ) {
1704 return toValue(Double.valueOf(value));
1705 }
1706
1707 public On<Conjunction<Graph>> to( BigDecimal value ) {
1708 return toValue(value);
1709 }
1710
1711 public On<Conjunction<Graph>> to( Calendar value ) {
1712 return toValue(value);
1713 }
1714
1715 public On<Conjunction<Graph>> to( Date value ) {
1716 return toValue(value);
1717 }
1718
1719 public On<Conjunction<Graph>> to( DateTime value ) {
1720 return toValue(value);
1721 }
1722
1723 public On<Conjunction<Graph>> to( Name value ) {
1724 return toValue(value);
1725 }
1726
1727 public On<Conjunction<Graph>> to( Path value ) {
1728 return toValue(value);
1729 }
1730
1731 public On<Conjunction<Graph>> to( Reference value ) {
1732 return toValue(value);
1733 }
1734
1735 public On<Conjunction<Graph>> to( URI value ) {
1736 return toValue(value);
1737 }
1738
1739 public On<Conjunction<Graph>> to( UUID value ) {
1740 return toValue(value);
1741 }
1742
1743 public On<Conjunction<Graph>> to( Binary value ) {
1744 return toValue(value);
1745 }
1746
1747 public On<Conjunction<Graph>> to( byte[] value ) {
1748 return toValue(value);
1749 }
1750
1751 public On<Conjunction<Graph>> to( InputStream stream,
1752 long approximateLength ) {
1753 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
1754 return toValue(value);
1755 }
1756
1757 public On<Conjunction<Graph>> to( Reader reader,
1758 long approximateLength ) {
1759 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
1760 return toValue(value);
1761 }
1762
1763 public On<Conjunction<Graph>> to( Object value ) {
1764 value = convertReferenceValue(value);
1765 return set(getContext().getPropertyFactory().create(propertyName, value));
1766 }
1767
1768 public On<Conjunction<Graph>> to( Object firstValue,
1769 Object... otherValues ) {
1770 firstValue = convertReferenceValue(firstValue);
1771 for (int i = 0, len = otherValues.length; i != len; ++i) {
1772 otherValues[i] = convertReferenceValue(otherValues[i]);
1773 }
1774 return set(getContext().getPropertyFactory().create(propertyName, firstValue, otherValues));
1775 }
1776
1777 public On<Conjunction<Graph>> to( Object[] values ) {
1778 for (int i = 0, len = values.length; i != len; ++i) {
1779 values[i] = convertReferenceValue(values[i]);
1780 }
1781 return set(getContext().getPropertyFactory().create(propertyName, values));
1782 }
1783
1784 public On<Conjunction<Graph>> to( Iterable<?> values ) {
1785 List<Object> valueList = new LinkedList<Object>();
1786 for (Object value : values) {
1787 value = convertReferenceValue(value);
1788 valueList.add(value);
1789 }
1790 return set(getContext().getPropertyFactory().create(propertyName, valueList));
1791 }
1792
1793 public On<Conjunction<Graph>> to( Iterator<?> values ) {
1794 List<Object> valueList = new LinkedList<Object>();
1795 while (values.hasNext()) {
1796 Object value = values.next();
1797 valueList.add(value);
1798 }
1799 return set(getContext().getPropertyFactory().create(propertyName, valueList));
1800 }
1801 };
1802 }
1803
1804 /**
1805 * Remove properties from the node at the given location.
1806 *
1807 * @param propertyNames the names of the properties to be removed
1808 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1809 */
1810 public On<Conjunction<Graph>> remove( final Name... propertyNames ) {
1811 return new On<Conjunction<Graph>>() {
1812 public Conjunction<Graph> on( Location location ) {
1813 requests.removeProperties(location, getCurrentWorkspaceName(), propertyNames);
1814 return nextGraph;
1815 }
1816
1817 public Conjunction<Graph> on( String path ) {
1818 return on(Location.create(createPath(path)));
1819 }
1820
1821 public Conjunction<Graph> on( Path path ) {
1822 return on(Location.create(path));
1823 }
1824
1825 public Conjunction<Graph> on( Property idProperty ) {
1826 return on(Location.create(idProperty));
1827 }
1828
1829 public Conjunction<Graph> on( Property firstIdProperty,
1830 Property... additionalIdProperties ) {
1831 return on(Location.create(firstIdProperty, additionalIdProperties));
1832 }
1833
1834 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1835 return on(Location.create(idProperties));
1836 }
1837
1838 public Conjunction<Graph> on( UUID uuid ) {
1839 return on(Location.create(uuid));
1840 }
1841 };
1842 }
1843
1844 /**
1845 * Remove properties from the node at the given location.
1846 *
1847 * @param propertyNames the names of the properties to be removed
1848 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1849 */
1850 public On<Conjunction<Graph>> remove( final String... propertyNames ) {
1851 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
1852 int number = propertyNames.length;
1853 final Name[] names = new Name[number];
1854 for (int i = 0; i != number; ++i) {
1855 names[i] = nameFactory.create(propertyNames[i]);
1856 }
1857 return new On<Conjunction<Graph>>() {
1858 public Conjunction<Graph> on( Location location ) {
1859 requests.removeProperties(location, getCurrentWorkspaceName(), names);
1860 return nextGraph;
1861 }
1862
1863 public Conjunction<Graph> on( String path ) {
1864 return on(Location.create(createPath(path)));
1865 }
1866
1867 public Conjunction<Graph> on( Path path ) {
1868 return on(Location.create(path));
1869 }
1870
1871 public Conjunction<Graph> on( Property idProperty ) {
1872 return on(Location.create(idProperty));
1873 }
1874
1875 public Conjunction<Graph> on( Property firstIdProperty,
1876 Property... additionalIdProperties ) {
1877 return on(Location.create(firstIdProperty, additionalIdProperties));
1878 }
1879
1880 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1881 return on(Location.create(idProperties));
1882 }
1883
1884 public Conjunction<Graph> on( UUID uuid ) {
1885 return on(Location.create(uuid));
1886 }
1887 };
1888 }
1889
1890 /**
1891 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
1892 * object. Once the location is specified, the {@link Collection collection of properties} are read and then returned.
1893 *
1894 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
1895 */
1896 public On<Collection<Property>> getProperties() {
1897 return new On<Collection<Property>>() {
1898 public Collection<Property> on( Location location ) {
1899 return requests.readAllProperties(location, getCurrentWorkspaceName()).getProperties();
1900 }
1901
1902 public Collection<Property> on( String path ) {
1903 return on(Location.create(createPath(path)));
1904 }
1905
1906 public Collection<Property> on( Path path ) {
1907 return on(Location.create(path));
1908 }
1909
1910 public Collection<Property> on( Property idProperty ) {
1911 return on(Location.create(idProperty));
1912 }
1913
1914 public Collection<Property> on( Property firstIdProperty,
1915 Property... additionalIdProperties ) {
1916 return on(Location.create(firstIdProperty, additionalIdProperties));
1917 }
1918
1919 public Collection<Property> on( Iterable<Property> idProperties ) {
1920 return on(Location.create(idProperties));
1921 }
1922
1923 public Collection<Property> on( UUID uuid ) {
1924 return on(Location.create(uuid));
1925 }
1926 };
1927 }
1928
1929 /**
1930 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
1931 * object. Once the location is specified, the {@link Map map of properties} are read and then returned.
1932 *
1933 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
1934 * as a map keyed by their name
1935 */
1936 public On<Map<Name, Property>> getPropertiesByName() {
1937 return new On<Map<Name, Property>>() {
1938 public Map<Name, Property> on( Location location ) {
1939 return requests.readAllProperties(location, getCurrentWorkspaceName()).getPropertiesByName();
1940 }
1941
1942 public Map<Name, Property> on( String path ) {
1943 return on(Location.create(createPath(path)));
1944 }
1945
1946 public Map<Name, Property> on( Path path ) {
1947 return on(Location.create(path));
1948 }
1949
1950 public Map<Name, Property> on( Property idProperty ) {
1951 return on(Location.create(idProperty));
1952 }
1953
1954 public Map<Name, Property> on( Property firstIdProperty,
1955 Property... additionalIdProperties ) {
1956 return on(Location.create(firstIdProperty, additionalIdProperties));
1957 }
1958
1959 public Map<Name, Property> on( Iterable<Property> idProperties ) {
1960 return on(Location.create(idProperties));
1961 }
1962
1963 public Map<Name, Property> on( UUID uuid ) {
1964 return on(Location.create(uuid));
1965 }
1966 };
1967 }
1968
1969 /**
1970 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
1971 * object. The returned object is used to supply the remaining information, including either the {@link Children#of(Location)
1972 * location of the parent}, or that a subset of the children should be retrieved {@link Children#inBlockOf(int) in a block}.
1973 *
1974 * @return the object that is used to specify the remaining inputs for the request, and which will return the children
1975 */
1976 public Children<List<Location>> getChildren() {
1977 return new Children<List<Location>>() {
1978 public List<Location> of( String path ) {
1979 return of(Location.create(createPath(path)));
1980 }
1981
1982 public List<Location> of( Path path ) {
1983 return of(Location.create(path));
1984 }
1985
1986 public List<Location> of( Property idProperty ) {
1987 return of(Location.create(idProperty));
1988 }
1989
1990 public List<Location> of( Property firstIdProperty,
1991 Property... additionalIdProperties ) {
1992 return of(Location.create(firstIdProperty, additionalIdProperties));
1993 }
1994
1995 public List<Location> of( Iterable<Property> idProperties ) {
1996 return of(Location.create(idProperties));
1997 }
1998
1999 public List<Location> of( UUID uuid ) {
2000 return of(Location.create(uuid));
2001 }
2002
2003 public List<Location> of( Location at ) {
2004 return requests.readAllChildren(at, getCurrentWorkspaceName()).getChildren();
2005 }
2006
2007 public BlockOfChildren<List<Location>> inBlockOf( final int blockSize ) {
2008 return new BlockOfChildren<List<Location>>() {
2009 public Under<List<Location>> startingAt( final int startingIndex ) {
2010 return new Under<List<Location>>() {
2011 public List<Location> under( String path ) {
2012 return under(Location.create(createPath(path)));
2013 }
2014
2015 public List<Location> under( Path path ) {
2016 return under(Location.create(path));
2017 }
2018
2019 public List<Location> under( Property idProperty ) {
2020 return under(Location.create(idProperty));
2021 }
2022
2023 public List<Location> under( Property firstIdProperty,
2024 Property... additionalIdProperties ) {
2025 return under(Location.create(firstIdProperty, additionalIdProperties));
2026 }
2027
2028 public List<Location> under( UUID uuid ) {
2029 return under(Location.create(uuid));
2030 }
2031
2032 public List<Location> under( Location at ) {
2033 return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize)
2034 .getChildren();
2035 }
2036 };
2037 }
2038
2039 public List<Location> startingAfter( final Location previousSibling ) {
2040 return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize)
2041 .getChildren();
2042 }
2043
2044 public List<Location> startingAfter( String pathOfPreviousSibling ) {
2045 return startingAfter(Location.create(createPath(pathOfPreviousSibling)));
2046 }
2047
2048 public List<Location> startingAfter( Path pathOfPreviousSibling ) {
2049 return startingAfter(Location.create(pathOfPreviousSibling));
2050 }
2051
2052 public List<Location> startingAfter( UUID uuidOfPreviousSibling ) {
2053 return startingAfter(Location.create(uuidOfPreviousSibling));
2054 }
2055
2056 public List<Location> startingAfter( Property idPropertyOfPreviousSibling ) {
2057 return startingAfter(Location.create(idPropertyOfPreviousSibling));
2058 }
2059
2060 public List<Location> startingAfter( Property firstIdProperyOfPreviousSibling,
2061 Property... additionalIdPropertiesOfPreviousSibling ) {
2062 return startingAfter(Location.create(firstIdProperyOfPreviousSibling,
2063 additionalIdPropertiesOfPreviousSibling));
2064 }
2065 };
2066 }
2067 };
2068 }
2069
2070 /**
2071 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
2072 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
2073 *
2074 * @param name the name of the property that is to be read
2075 * @return the object that is used to specified the node whose property is to be read, and which will return the property
2076 */
2077 public On<Property> getProperty( final String name ) {
2078 Name nameObj = context.getValueFactories().getNameFactory().create(name);
2079 return getProperty(nameObj);
2080 }
2081
2082 /**
2083 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
2084 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
2085 *
2086 * @param name the name of the property that is to be read
2087 * @return the object that is used to specified the node whose property is to be read, and which will return the property
2088 */
2089 public OnMultiple<Property> getProperty( final Name name ) {
2090 CheckArg.isNotNull(name, "name");
2091 return new OnMultiple<Property>() {
2092 public Property on( String path ) {
2093 return on(Location.create(createPath(path)));
2094 }
2095
2096 public Property on( Path path ) {
2097 return on(Location.create(path));
2098 }
2099
2100 public Property on( Property idProperty ) {
2101 return on(Location.create(idProperty));
2102 }
2103
2104 public Property on( Property firstIdProperty,
2105 Property... additionalIdProperties ) {
2106 return on(Location.create(firstIdProperty, additionalIdProperties));
2107 }
2108
2109 public Property on( Iterable<Property> idProperties ) {
2110 return on(Location.create(idProperties));
2111 }
2112
2113 public Property on( UUID uuid ) {
2114 return on(Location.create(uuid));
2115 }
2116
2117 public Property on( Location at ) {
2118 return requests.readProperty(at, getCurrentWorkspaceName(), name).getProperty();
2119 }
2120
2121 public Map<Location, Property> on( Collection<Location> locations ) {
2122 CheckArg.isNotNull(locations, "locations");
2123 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2124 String workspace = getCurrentWorkspaceName();
2125 for (Location location : locations) {
2126 requests.add(new ReadPropertyRequest(location, workspace, name));
2127 }
2128 return execute(requests);
2129 }
2130
2131 public Map<Location, Property> on( Location first,
2132 Location... additional ) {
2133 CheckArg.isNotNull(first, "first");
2134 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2135 String workspace = getCurrentWorkspaceName();
2136 requests.add(new ReadPropertyRequest(first, workspace, name));
2137 for (Location location : additional) {
2138 requests.add(new ReadPropertyRequest(location, workspace, name));
2139 }
2140 return execute(requests);
2141 }
2142
2143 public Map<Location, Property> on( String first,
2144 String... additional ) {
2145 CheckArg.isNotNull(first, "first");
2146 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2147 String workspace = getCurrentWorkspaceName();
2148 requests.add(new ReadPropertyRequest(Location.create(createPath(first)), workspace, name));
2149 for (String path : additional) {
2150 requests.add(new ReadPropertyRequest(Location.create(createPath(path)), workspace, name));
2151 }
2152 return execute(requests);
2153 }
2154
2155 public Map<Location, Property> on( Path first,
2156 Path... additional ) {
2157 CheckArg.isNotNull(first, "first");
2158 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2159 String workspace = getCurrentWorkspaceName();
2160 requests.add(new ReadPropertyRequest(Location.create(first), workspace, name));
2161 for (Path path : additional) {
2162 requests.add(new ReadPropertyRequest(Location.create(path), workspace, name));
2163 }
2164 return execute(requests);
2165 }
2166
2167 public Map<Location, Property> on( UUID first,
2168 UUID... additional ) {
2169 CheckArg.isNotNull(first, "first");
2170 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2171 String workspace = getCurrentWorkspaceName();
2172 requests.add(new ReadPropertyRequest(Location.create(first), workspace, name));
2173 for (UUID uuid : additional) {
2174 requests.add(new ReadPropertyRequest(Location.create(uuid), workspace, name));
2175 }
2176 return execute(requests);
2177 }
2178
2179 protected Map<Location, Property> execute( List<ReadPropertyRequest> requests ) {
2180 // Create a composite request ...
2181 Request composite = CompositeRequest.with(requests);
2182 Graph.this.execute(composite);
2183 Map<Location, Property> results = new HashMap<Location, Property>();
2184 for (ReadPropertyRequest request : requests) {
2185 Property property = request.getProperty();
2186 Location location = request.getActualLocationOfNode();
2187 results.put(location, property);
2188 }
2189 return results;
2190 }
2191 };
2192 }
2193
2194 /**
2195 * Request that the properties with the given names be read on the node defined via the <code>on(...)</code> method on the
2196 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
2197 *
2198 * @param names the name of the property that are to be read
2199 * @return the object that is used to specified the node whose properties are to be read, and which will return the map of
2200 * properties keyed by their name; never null
2201 */
2202 public OnMultiple<Map<Name, Property>> getProperties( final Name... names ) {
2203 return new OnMultiple<Map<Name, Property>>() {
2204 public Map<Name, Property> on( String path ) {
2205 return on(Location.create(createPath(path)));
2206 }
2207
2208 public Map<Name, Property> on( Path path ) {
2209 return on(Location.create(path));
2210 }
2211
2212 public Map<Name, Property> on( Property idProperty ) {
2213 return on(Location.create(idProperty));
2214 }
2215
2216 public Map<Name, Property> on( Property firstIdProperty,
2217 Property... additionalIdProperties ) {
2218 return on(Location.create(firstIdProperty, additionalIdProperties));
2219 }
2220
2221 public Map<Name, Property> on( Iterable<Property> idProperties ) {
2222 return on(Location.create(idProperties));
2223 }
2224
2225 public Map<Name, Property> on( UUID uuid ) {
2226 return on(Location.create(uuid));
2227 }
2228
2229 public Map<Name, Property> on( Location at ) {
2230 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2231 String workspace = getCurrentWorkspaceName();
2232 for (Name propertyName : names) {
2233 requests.add(new ReadPropertyRequest(at, workspace, propertyName));
2234 }
2235 // Create a composite request ...
2236 Request composite = CompositeRequest.with(requests);
2237 Graph.this.execute(composite);
2238 Map<Name, Property> results = new HashMap<Name, Property>();
2239 for (ReadPropertyRequest request : requests) {
2240 Property property = request.getProperty();
2241 results.put(property.getName(), property);
2242 }
2243 return results;
2244 }
2245
2246 public Map<Location, Map<Name, Property>> on( Collection<Location> locations ) {
2247 CheckArg.isNotNull(locations, "locations");
2248 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2249 String workspace = getCurrentWorkspaceName();
2250 for (Location location : locations) {
2251 if (location == null) continue;
2252 for (Name propertyName : names) {
2253 if (propertyName == null) continue;
2254 requests.add(new ReadPropertyRequest(location, workspace, propertyName));
2255 }
2256 }
2257 return execute(requests);
2258 }
2259
2260 /**
2261 * {@inheritDoc}
2262 *
2263 * @see org.modeshape.graph.Graph.OnMultiple#on(org.modeshape.graph.Location, org.modeshape.graph.Location[])
2264 */
2265 public Map<Location, Map<Name, Property>> on( Location first,
2266 Location... additional ) {
2267 CheckArg.isNotNull(first, "first");
2268 final List<ReadPropertyRequest> requests = new LinkedList<ReadPropertyRequest>();
2269 String workspace = getCurrentWorkspaceName();
2270 for (Location location : additional) {
2271 if (location == null) continue;
2272 for (Name propertyName : names) {
2273 if (propertyName == null) continue;
2274 requests.add(new ReadPropertyRequest(first, workspace, propertyName));
2275 requests.add(new ReadPropertyRequest(location, workspace, propertyName));
2276 }
2277 }
2278 return execute(requests);
2279 }
2280
2281 /**
2282 * {@inheritDoc}
2283 *
2284 * @see org.modeshape.graph.Graph.OnMultiple#on(org.modeshape.graph.property.Path,
2285 * org.modeshape.graph.property.Path[])
2286 */
2287 public Map<Location, Map<Name, Property>> on( Path first,
2288 Path... additional ) {
2289 CheckArg.isNotNull(first, "first");
2290 List<Location> locations = new LinkedList<Location>();
2291 locations.add(Location.create(first));
2292 for (Path path : additional) {
2293 if (path != null) locations.add(Location.create(path));
2294 }
2295 return on(locations);
2296 }
2297
2298 /**
2299 * {@inheritDoc}
2300 *
2301 * @see org.modeshape.graph.Graph.OnMultiple#on(java.lang.String, java.lang.String[])
2302 */
2303 public Map<Location, Map<Name, Property>> on( String first,
2304 String... additional ) {
2305 CheckArg.isNotNull(first, "first");
2306 List<Location> locations = new LinkedList<Location>();
2307 locations.add(Location.create(createPath(first)));
2308 for (String path : additional) {
2309 if (path != null) locations.add(Location.create(createPath(path)));
2310 }
2311 return on(locations);
2312 }
2313
2314 /**
2315 * {@inheritDoc}
2316 *
2317 * @see org.modeshape.graph.Graph.OnMultiple#on(java.util.UUID, java.util.UUID[])
2318 */
2319 public Map<Location, Map<Name, Property>> on( UUID first,
2320 UUID... additional ) {
2321 CheckArg.isNotNull(first, "first");
2322 List<Location> locations = new LinkedList<Location>();
2323 locations.add(Location.create(first));
2324 for (UUID uuid : additional) {
2325 if (uuid != null) locations.add(Location.create(uuid));
2326 }
2327 return on(locations);
2328 }
2329
2330 protected Map<Location, Map<Name, Property>> execute( List<ReadPropertyRequest> requests ) {
2331 // Create a composite request ...
2332 Request composite = CompositeRequest.with(requests);
2333 Graph.this.execute(composite);
2334 Map<Location, Map<Name, Property>> results = new HashMap<Location, Map<Name, Property>>();
2335 for (ReadPropertyRequest request : requests) {
2336 Property property = request.getProperty();
2337
2338 // property was requested but doesn't exist
2339 if (property == null) continue;
2340
2341 Location location = request.getActualLocationOfNode();
2342 Map<Name, Property> properties = results.get(location);
2343 if (properties == null) {
2344 properties = new HashMap<Name, Property>();
2345 results.put(location, properties);
2346 }
2347 properties.put(property.getName(), property);
2348 }
2349 return results;
2350 }
2351 };
2352 }
2353
2354 /**
2355 * Request to read the node with the supplied UUID.
2356 *
2357 * @param uuid the UUID of the node that is to be read
2358 * @return the node that is read from the repository
2359 */
2360 public Node getNodeAt( UUID uuid ) {
2361 return getNodeAt(Location.create(uuid));
2362 }
2363
2364 /**
2365 * Request to read the node at the supplied location.
2366 *
2367 * @param location the location of the node that is to be read
2368 * @return the node that is read from the repository
2369 */
2370 public Node getNodeAt( Location location ) {
2371 return new GraphNode(requests.readNode(location, getCurrentWorkspaceName()));
2372 }
2373
2374 /**
2375 * Request to read the node at the supplied path.
2376 *
2377 * @param path the path of the node that is to be read
2378 * @return the node that is read from the repository
2379 */
2380 public Node getNodeAt( String path ) {
2381 return getNodeAt(Location.create(createPath(path)));
2382 }
2383
2384 /**
2385 * Request to read the node at the supplied path.
2386 *
2387 * @param path the path of the node that is to be read
2388 * @return the node that is read from the repository
2389 */
2390 public Node getNodeAt( Path path ) {
2391 return getNodeAt(Location.create(path));
2392 }
2393
2394 /**
2395 * Request to read the node with the supplied unique identifier property.
2396 *
2397 * @param idProperty the identification property that is unique to the node that is to be read
2398 * @return the node that is read from the repository
2399 */
2400 public Node getNodeAt( Property idProperty ) {
2401 return getNodeAt(Location.create(idProperty));
2402 }
2403
2404 /**
2405 * Request to read the node with the supplied unique identifier properties.
2406 *
2407 * @param firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
2408 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be read
2409 * @return the node that is read from the repository
2410 */
2411 public Node getNodeAt( Property firstIdProperty,
2412 Property... additionalIdProperties ) {
2413 return getNodeAt(Location.create(firstIdProperty, additionalIdProperties));
2414 }
2415
2416 /**
2417 * Request to read the node with the supplied unique identifier properties.
2418 *
2419 * @param idProperties the identification properties that uniquely identify the node that is to be read
2420 * @return the node that is read from the repository
2421 */
2422 public Node getNodeAt( Iterable<Property> idProperties ) {
2423 return getNodeAt(Location.create(idProperties));
2424 }
2425
2426 /**
2427 * Request to read the node given by the supplied reference value.
2428 *
2429 * @param reference the reference property value that is to be resolved into a node
2430 * @return the node that is read from the repository
2431 * @throws ValueFormatException if the supplied reference could not be converted to an identifier property value
2432 */
2433 public Node resolve( Reference reference ) {
2434 CheckArg.isNotNull(reference, "reference");
2435 UUID uuid = context.getValueFactories().getUuidFactory().create(reference);
2436 return getNodeAt(uuid);
2437 }
2438
2439 /**
2440 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code> in
2441 * the resulting {@link At} object. All properties and children of every node in the subgraph will be read and returned in the
2442 * {@link Subgraph} object returned from the <code>at(...)</code> methods.
2443 *
2444 * @param depth the maximum depth of the subgraph that should be read
2445 * @return the component that should be used to specify the location of the node that is the top of the subgraph, and which
2446 * will return the {@link Subgraph} containing the results
2447 */
2448 public At<Subgraph> getSubgraphOfDepth( final int depth ) {
2449 return new At<Subgraph>() {
2450 public Subgraph at( Location location ) {
2451 return new SubgraphResults(requests.readBranch(location, getCurrentWorkspaceName(), depth));
2452 }
2453
2454 public Subgraph at( String path ) {
2455 return at(Location.create(createPath(path)));
2456 }
2457
2458 public Subgraph at( Path path ) {
2459 return at(Location.create(path));
2460 }
2461
2462 public Subgraph at( UUID uuid ) {
2463 return at(Location.create(uuid));
2464 }
2465
2466 public Subgraph at( Property idProperty ) {
2467 return at(Location.create(idProperty));
2468 }
2469
2470 public Subgraph at( Property firstIdProperty,
2471 Property... additionalIdProperties ) {
2472 return at(Location.create(firstIdProperty, additionalIdProperties));
2473 }
2474
2475 public Subgraph at( Iterable<Property> idProperties ) {
2476 return at(Location.create(idProperties));
2477 }
2478 };
2479 }
2480
2481 /**
2482 * Search the current workspace using the supplied full-text search expression.
2483 *
2484 * @param fullTextSearchExpression the full-text search expression
2485 * @param maxResults the maximum number of results that are to be returned; always positive
2486 * @param offset the number of initial results to skip, or 0 if the first results are to be returned
2487 * @return the results of the search; never null
2488 * @throws IllegalArgumentException if the expression is null
2489 */
2490 public QueryResults search( final String fullTextSearchExpression,
2491 int maxResults,
2492 int offset ) {
2493 FullTextSearchRequest request = requests.search(getCurrentWorkspaceName(), fullTextSearchExpression, maxResults, offset);
2494 QueryResults results = new org.modeshape.graph.query.process.QueryResults(request.getResultColumns(),
2495 request.getStatistics(), request.getTuples());
2496 return results;
2497 }
2498
2499 /**
2500 * Query the current workspace using the supplied {@link Schemata}.
2501 *
2502 * @param query the query that is to be executed against the current workspace
2503 * @param schemata the schemata defining the structure of the tables that are being queried
2504 * @return the interface used to continue specifying the options for the query and to obtain the results
2505 * @throws IllegalArgumentException if the query or schemata references are null
2506 */
2507 public BuildQuery query( final QueryCommand query,
2508 final Schemata schemata ) {
2509 CheckArg.isNotNull(query, "query");
2510 CheckArg.isNotNull(schemata, "schemata");
2511 return new BuildQuery() {
2512 private PlanHints hints;
2513 private Problems problems;
2514 private Map<String, Object> variables;
2515
2516 /**
2517 * {@inheritDoc}
2518 *
2519 * @see org.modeshape.graph.Graph.BuildQuery#using(java.util.Map)
2520 */
2521 public BuildQuery using( Map<String, Object> variables ) {
2522 CheckArg.isNotNull(variables, "variables");
2523 if (this.variables == null) this.variables = new HashMap<String, Object>();
2524 this.variables.putAll(variables);
2525 return this;
2526 }
2527
2528 /**
2529 * {@inheritDoc}
2530 *
2531 * @see org.modeshape.graph.Graph.BuildQuery#using(java.lang.String, java.lang.Object)
2532 */
2533 public BuildQuery using( String variableName,
2534 Object variableValue ) {
2535 CheckArg.isNotNull(variableName, "variableName");
2536 if (this.variables == null) this.variables = new HashMap<String, Object>();
2537 this.variables.put(variableName, variableValue);
2538 return this;
2539 }
2540
2541 /**
2542 * {@inheritDoc}
2543 *
2544 * @see org.modeshape.graph.Graph.BuildQuery#using(org.modeshape.graph.query.plan.PlanHints)
2545 */
2546 public BuildQuery using( PlanHints hints ) {
2547 this.hints = hints;
2548 return this;
2549 }
2550
2551 /**
2552 * {@inheritDoc}
2553 *
2554 * @see org.modeshape.graph.Graph.BuildQuery#execute()
2555 */
2556 public QueryResults execute() {
2557 Batch batch = batch();
2558 TypeSystem typeSystem = getContext().getValueFactories().getTypeSystem();
2559 QueryContext context = new GraphQueryContext(schemata, typeSystem, hints, problems, variables, batch);
2560 QueryEngine engine = getQueryEngine();
2561 return engine.execute(context, query);
2562 }
2563 };
2564 }
2565
2566 protected QueryEngine getQueryEngine() {
2567 if (queryEngine == null) {
2568 queryEngine = getQueryEngine(new RuleBasedOptimizer());
2569 }
2570 return queryEngine;
2571 }
2572
2573 protected QueryEngine getQueryEngine( Optimizer optimizer ) {
2574 Planner planner = new CanonicalPlanner();
2575 Processor processor = new QueryProcessor() {
2576 /**
2577 * {@inheritDoc}
2578 *
2579 * @see org.modeshape.graph.query.process.QueryProcessor#createAccessComponent(org.modeshape.graph.query.model.QueryCommand,
2580 * org.modeshape.graph.query.QueryContext, org.modeshape.graph.query.plan.PlanNode,
2581 * org.modeshape.graph.query.QueryResults.Columns, org.modeshape.graph.query.process.SelectComponent.Analyzer)
2582 */
2583 @Override
2584 protected ProcessingComponent createAccessComponent( QueryCommand originalQuery,
2585 QueryContext context,
2586 PlanNode accessNode,
2587 Columns resultColumns,
2588 Analyzer analyzer ) {
2589 return new AccessQueryProcessor(getSourceName(), getCurrentWorkspaceName(), context, resultColumns, accessNode);
2590 }
2591
2592 /**
2593 * {@inheritDoc}
2594 *
2595 * @see org.modeshape.graph.query.process.QueryProcessor#preExecute(QueryContext)
2596 */
2597 @Override
2598 protected void preExecute( QueryContext context ) {
2599 // Submit the batch before the processing the query. No need to hold onto the batch results,
2600 // because each ProcessingComponent holds onto its AccessQueryRequest ...
2601 ((GraphQueryContext)context).getBatch().execute();
2602 }
2603 };
2604 return new QueryEngine(planner, optimizer, processor);
2605 }
2606
2607 protected class GraphQueryContext extends QueryContext {
2608 private final Batch batch;
2609
2610 protected GraphQueryContext( Schemata schemata,
2611 TypeSystem typeSystem,
2612 PlanHints hints,
2613 Problems problems,
2614 Map<String, Object> variables,
2615 Batch batch ) {
2616 super(schemata, typeSystem, hints, problems, variables);
2617 this.batch = batch;
2618 assert this.batch != null;
2619 }
2620
2621 /**
2622 * Get the {@link Batch} that is being used to execute these queries
2623 *
2624 * @return the batch; never null
2625 */
2626 public Batch getBatch() {
2627 return batch;
2628 }
2629 }
2630
2631 protected static class AccessQueryProcessor extends AbstractAccessComponent {
2632 private final AccessQueryRequest accessRequest;
2633 private final String graphSourceName;
2634
2635 protected AccessQueryProcessor( String graphSourceName,
2636 String workspaceName,
2637 QueryContext context,
2638 Columns columns,
2639 PlanNode accessNode ) {
2640 super(context, columns, accessNode);
2641 this.graphSourceName = graphSourceName;
2642 accessRequest = new AccessQueryRequest(workspaceName, sourceName, getColumns(), andedConstraints, limit,
2643 context.getSchemata(), context.getVariables());
2644 ((GraphQueryContext)context).getBatch().requestQueue.submit(accessRequest);
2645 }
2646
2647 /**
2648 * Get the access query request.
2649 *
2650 * @return the access query request; never null
2651 */
2652 public AccessQueryRequest getAccessRequest() {
2653 return accessRequest;
2654 }
2655
2656 /**
2657 * {@inheritDoc}
2658 *
2659 * @see org.modeshape.graph.query.process.ProcessingComponent#execute()
2660 */
2661 @Override
2662 public List<Object[]> execute() {
2663 if (accessRequest.getError() != null) {
2664 I18n msg = GraphI18n.errorWhilePerformingQuery;
2665 getContext().getProblems().addError(accessRequest.getError(),
2666 msg,
2667 accessNode.getString(),
2668 accessRequest.workspace(),
2669 graphSourceName,
2670 accessRequest.getError().getLocalizedMessage());
2671 return emptyTuples();
2672 }
2673 return accessRequest.getTuples();
2674 }
2675
2676 }
2677
2678 /**
2679 * Import the content from the provided stream of XML data, specifying via the returned {@link ImportInto object} where the
2680 * content is to be imported.
2681 *
2682 * @param stream the open stream of XML data that the importer can read the content that is to be imported
2683 * @return the object that should be used to specify into which the content is to be imported
2684 * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
2685 */
2686 public ImportInto<Conjunction<Graph>> importXmlFrom( final InputStream stream ) {
2687 CheckArg.isNotNull(stream, "stream");
2688
2689 return new ImportInto<Conjunction<Graph>>() {
2690 private boolean skipRootElement = false;
2691
2692 public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
2693 this.skipRootElement = skipRootElement;
2694 return this;
2695 }
2696
2697 public Conjunction<Graph> into( String path ) throws IOException, SAXException {
2698 return into(Location.create(createPath(path)));
2699 }
2700
2701 public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
2702 return into(Location.create(path));
2703 }
2704
2705 public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
2706 return into(Location.create(idProperty));
2707 }
2708
2709 public Conjunction<Graph> into( Property firstIdProperty,
2710 Property... additionalIdProperties ) throws IOException, SAXException {
2711 return into(Location.create(firstIdProperty, additionalIdProperties));
2712 }
2713
2714 public Conjunction<Graph> into( Iterable<Property> idProperties ) throws IOException, SAXException {
2715 return into(Location.create(idProperties));
2716 }
2717
2718 public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
2719 return into(Location.create(uuid));
2720 }
2721
2722 public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
2723 GraphImporter importer = new GraphImporter(Graph.this);
2724 importer.importXml(stream, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
2725 return Graph.this.nextGraph;
2726 }
2727 };
2728 }
2729
2730 /**
2731 * Import the content from the XML file at the supplied URI, specifying via the returned {@link ImportInto object} where the
2732 * content is to be imported.
2733 *
2734 * @param uri the URI where the importer can read the content that is to be imported
2735 * @return the object that should be used to specify into which the content is to be imported
2736 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2737 */
2738 public ImportInto<Conjunction<Graph>> importXmlFrom( final URI uri ) {
2739 return new ImportInto<Conjunction<Graph>>() {
2740 private boolean skipRootElement = false;
2741
2742 public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
2743 this.skipRootElement = skipRootElement;
2744 return this;
2745 }
2746
2747 public Conjunction<Graph> into( String path ) throws IOException, SAXException {
2748 return into(Location.create(createPath(path)));
2749 }
2750
2751 public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
2752 return into(Location.create(path));
2753 }
2754
2755 public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
2756 return into(Location.create(idProperty));
2757 }
2758
2759 public Conjunction<Graph> into( Property firstIdProperty,
2760 Property... additionalIdProperties ) throws IOException, SAXException {
2761 return into(Location.create(firstIdProperty, additionalIdProperties));
2762 }
2763
2764 public Conjunction<Graph> into( Iterable<Property> idProperties ) throws IOException, SAXException {
2765 return into(Location.create(idProperties));
2766 }
2767
2768 public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
2769 return into(Location.create(uuid));
2770 }
2771
2772 public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
2773 GraphImporter importer = new GraphImporter(Graph.this);
2774 importer.importXml(uri, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
2775 return Graph.this.nextGraph;
2776 }
2777 };
2778 }
2779
2780 /**
2781 * Import the content from the XML file at the supplied file location, specifying via the returned {@link ImportInto object}
2782 * where the content is to be imported.
2783 *
2784 * @param pathToFile the path to the XML file that should be imported.
2785 * @return the object that should be used to specify into which the content is to be imported
2786 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2787 */
2788 public ImportInto<Conjunction<Graph>> importXmlFrom( String pathToFile ) {
2789 CheckArg.isNotNull(pathToFile, "pathToFile");
2790 return importXmlFrom(new File(pathToFile).toURI());
2791 }
2792
2793 /**
2794 * Import the content from the XML file at the supplied file, specifying via the returned {@link ImportInto object} where the
2795 * content is to be imported.
2796 *
2797 * @param file the XML file that should be imported.
2798 * @return the object that should be used to specify into which the content is to be imported
2799 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2800 */
2801 public ImportInto<Conjunction<Graph>> importXmlFrom( File file ) {
2802 CheckArg.isNotNull(file, "file");
2803 return importXmlFrom(file.toURI());
2804 }
2805
2806 protected Path createPath( String path ) {
2807 return getContext().getValueFactories().getPathFactory().create(path);
2808 }
2809
2810 protected List<Segment> getSegments( List<Location> locations ) {
2811 List<Segment> segments = new ArrayList<Segment>(locations.size());
2812 for (Location location : locations) {
2813 segments.add(location.getPath().getLastSegment());
2814 }
2815 return segments;
2816 }
2817
2818 /**
2819 * Begin a batch of requests to perform various operations. Use this approach when multiple operations are to be built and
2820 * then executed with one submission to the underlying {@link #getSourceName() repository source}. The {@link Results results}
2821 * are not available until the {@link Batch#execute()} method is invoked.
2822 *
2823 * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
2824 * @see Batch#execute()
2825 * @see Results
2826 */
2827 public Batch batch() {
2828 return new Batch(new BatchRequestBuilder());
2829 }
2830
2831 /**
2832 * Begin a batch of requests to perform various operations, but specify the queue where all accumulated requests should be
2833 * placed. Use this approach when multiple operations are to be built and then executed with one submission to the underlying
2834 * {@link #getSourceName() repository source}. The {@link Results results} are not available until the {@link Batch#execute()}
2835 * method is invoked.
2836 *
2837 * @param builder the request builder that should be used; may not be null
2838 * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
2839 * @see Batch#execute()
2840 * @see Results
2841 */
2842 public Batch batch( BatchRequestBuilder builder ) {
2843 CheckArg.isNotNull(builder, "builder");
2844 return new Batch(builder);
2845 }
2846
2847 /**
2848 * Interface for creating multiple requests to perform various operations. Note that all the requests are accumulated until
2849 * the {@link #execute()} method is called. The results of all the operations are then available in the {@link Results} object
2850 * returned by the {@link #execute()}.
2851 */
2852 @Immutable
2853 public final class Batch implements Executable<Node> {
2854 protected final BatchRequestBuilder requestQueue;
2855 protected final BatchConjunction nextRequests;
2856 protected final String workspaceName;
2857 protected boolean executed = false;
2858
2859 /*package*/Batch( BatchRequestBuilder builder ) {
2860 assert builder != null;
2861 this.requestQueue = builder;
2862 this.workspaceName = Graph.this.getCurrentWorkspaceName();
2863 this.nextRequests = new BatchConjunction() {
2864 public Batch and() {
2865 return Batch.this;
2866 }
2867
2868 public Results execute() {
2869 return Batch.this.execute();
2870 }
2871 };
2872 }
2873
2874 /**
2875 * Return whether this batch has been {@link #execute() executed}.
2876 *
2877 * @return true if this batch has already been executed, or false otherwise
2878 */
2879 public boolean hasExecuted() {
2880 return executed;
2881 }
2882
2883 /**
2884 * Determine whether this batch needs to be executed (there are requests and the batch has not been executed yet).
2885 *
2886 * @return true if there are some requests in this batch that need to be executed, or false execution is not required
2887 */
2888 public boolean isExecuteRequired() {
2889 return !executed && requestQueue.hasRequests();
2890 }
2891
2892 /**
2893 * Obtain the graph that this batch uses.
2894 *
2895 * @return the graph; never null
2896 */
2897 public Graph getGraph() {
2898 return Graph.this;
2899 }
2900
2901 /**
2902 * Get the name of the workspace that this batch is using. This is always constant throughout the lifetime of the batch.
2903 *
2904 * @return the name of the workspace; never null
2905 */
2906 public String getCurrentWorkspaceName() {
2907 return this.workspaceName;
2908 }
2909
2910 protected final void assertNotExecuted() {
2911 if (executed) {
2912 throw new IllegalStateException(GraphI18n.unableToAddMoreRequestsToAlreadyExecutedBatch.text());
2913 }
2914 }
2915
2916 /**
2917 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
2918 * <code>into(...)</code> method on the returned {@link Move} object.
2919 * <p>
2920 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2921 * called.
2922 * </p>
2923 *
2924 * @param from the node that is to be moved.
2925 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2926 * to be moved
2927 */
2928 public Move<BatchConjunction> move( Node from ) {
2929 return move(from.getLocation());
2930 }
2931
2932 /**
2933 * Begin the request to move a node at the specified location into a parent node at a different location, which is
2934 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2935 * <p>
2936 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2937 * called.
2938 * </p>
2939 *
2940 * @param from the location of the node that is to be moved.
2941 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2942 * to be moved
2943 */
2944 public final Move<BatchConjunction> move( Location from ) {
2945 assertNotExecuted();
2946 return new MoveAction<BatchConjunction>(this.nextRequests, from) {
2947 @Override
2948 protected BatchConjunction submit( Locations from,
2949 Location into,
2950 Location before,
2951 Name newName ) {
2952 String workspaceName = getCurrentWorkspaceName();
2953 do {
2954 requestQueue.moveBranch(from.getLocation(), into, before, workspaceName, newName);
2955 } while ((from = from.next()) != null);
2956 return and();
2957 }
2958 };
2959 }
2960
2961 /**
2962 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
2963 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2964 * <p>
2965 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2966 * called.
2967 * </p>
2968 *
2969 * @param fromPath the path to the node that is to be moved.
2970 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2971 * to be moved
2972 */
2973 public Move<BatchConjunction> move( String fromPath ) {
2974 return move(Location.create(createPath(fromPath)));
2975 }
2976
2977 /**
2978 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
2979 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2980 * <p>
2981 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2982 * called.
2983 * </p>
2984 *
2985 * @param from the path to the node that is to be moved.
2986 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2987 * to be moved
2988 */
2989 public Move<BatchConjunction> move( Path from ) {
2990 return move(Location.create(from));
2991 }
2992
2993 /**
2994 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which
2995 * is specified via the <code>into(...)</code> method on the returned {@link Move} object.
2996 * <p>
2997 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2998 * called.
2999 * </p>
3000 *
3001 * @param from the UUID of the node that is to be moved.
3002 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
3003 * to be moved
3004 */
3005 public Move<BatchConjunction> move( UUID from ) {
3006 return move(Location.create(from));
3007 }
3008
3009 /**
3010 * Begin the request to move a node with the specified unique identification property into a parent node at a different
3011 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
3012 * identification property should uniquely identify a single node.
3013 * <p>
3014 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3015 * called.
3016 * </p>
3017 *
3018 * @param idProperty the unique identification property of the node that is to be moved.
3019 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
3020 * to be moved
3021 */
3022 public Move<BatchConjunction> move( Property idProperty ) {
3023 return move(Location.create(idProperty));
3024 }
3025
3026 /**
3027 * Begin the request to move a node with the specified identification properties into a parent node at a different
3028 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
3029 * identification properties should uniquely identify a single node.
3030 * <p>
3031 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3032 * called.
3033 * </p>
3034 *
3035 * @param firstIdProperty the first identification property of the node that is to be moved
3036 * @param additionalIdProperties the remaining identification properties of the node that is to be moved
3037 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
3038 * to be moved
3039 */
3040 public Move<BatchConjunction> move( Property firstIdProperty,
3041 Property... additionalIdProperties ) {
3042 return move(Location.create(firstIdProperty, additionalIdProperties));
3043 }
3044
3045 /**
3046 * Begin the request to move a node with the specified identification properties into a parent node at a different
3047 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
3048 * identification properties should uniquely identify a single node.
3049 * <p>
3050 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3051 * called.
3052 * </p>
3053 *
3054 * @param idProperties the identification properties of the node that is to be moved
3055 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
3056 * to be moved
3057 */
3058 public Move<BatchConjunction> move( Iterable<Property> idProperties ) {
3059 return move(Location.create(idProperties));
3060 }
3061
3062 /**
3063 * Request to lock the specified node. This request is submitted to the repository immediately.
3064 *
3065 * @param at the node that is to be locked
3066 * @return an object that allows the scope of the lock to be defined
3067 */
3068 public LockScope<LockTimeout<BatchConjunction>> lock( Node at ) {
3069 return lock(at.getLocation());
3070 }
3071
3072 /**
3073 * Request to lock the node at the given path. This request is submitted to the repository immediately.
3074 *
3075 * @param atPath the path of the node that is to be locked
3076 * @return an object that allows the scope of the lock to be defined
3077 */
3078 public LockScope<LockTimeout<BatchConjunction>> lock( String atPath ) {
3079 return lock(Location.create(createPath(atPath)));
3080 }
3081
3082 /**
3083 * Request to lock the node at the given path. This request is submitted to the repository immediately.
3084 *
3085 * @param at the path of the node that is to be locked
3086 * @return an object that allows the scope of the lock to be defined
3087 */
3088 public LockScope<LockTimeout<BatchConjunction>> lock( Path at ) {
3089 return lock(Location.create(at));
3090 }
3091
3092 /**
3093 * Request to lock the node with the given UUID. This request is submitted to the repository immediately.
3094 *
3095 * @param at the UUID of the node that is to be locked
3096 * @return an object that allows the scope of the lock to be defined
3097 */
3098 public LockScope<LockTimeout<BatchConjunction>> lock( UUID at ) {
3099 return lock(Location.create(at));
3100 }
3101
3102 /**
3103 * Request to lock the node with the given unique identification property. This request is submitted to the repository
3104 * immediately.
3105 *
3106 * @param idProperty the unique identifying property of the node that is to be locked
3107 * @return an object that allows the scope of the lock to be defined
3108 */
3109 public LockScope<LockTimeout<BatchConjunction>> lock( Property idProperty ) {
3110 return lock(Location.create(idProperty));
3111 }
3112
3113 /**
3114 * Request to lock the node with the given identification properties. The identification properties should uniquely
3115 * identify a single node. This request is submitted to the repository immediately.
3116 *
3117 * @param firstIdProperty the first identification property of the node that is to be copied
3118 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
3119 * @return an object that allows the scope of the lock to be defined
3120 */
3121 public LockScope<LockTimeout<BatchConjunction>> lock( Property firstIdProperty,
3122 Property... additionalIdProperties ) {
3123 return lock(Location.create(firstIdProperty, additionalIdProperties));
3124 }
3125
3126 /**
3127 * Request to lock the node at the given location. This request is submitted to the repository immediately.
3128 *
3129 * @param at the location of the node that is to be locked
3130 * @return an object that allows the scope of the lock to be defined
3131 */
3132 public LockScope<LockTimeout<BatchConjunction>> lock( Location at ) {
3133 return new LockAction<BatchConjunction>(this.nextRequests, at) {
3134 @Override
3135 protected BatchConjunction submit( Location target,
3136 org.modeshape.graph.request.LockBranchRequest.LockScope lockScope,
3137 long lockTimeoutInMillis ) {
3138 String workspaceName = getCurrentWorkspaceName();
3139 requests.lockBranch(workspaceName, target, lockScope, lockTimeoutInMillis);
3140 return and();
3141 }
3142 };
3143 }
3144
3145 /**
3146 * Request to unlock the specified node. This request is submitted to the repository immediately.
3147 *
3148 * @param at the node that is to be unlocked
3149 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3150 */
3151 public BatchConjunction unlock( Node at ) {
3152 return unlock(at.getLocation());
3153 }
3154
3155 /**
3156 * Request to unlock the node at the given path. This request is submitted to the repository immediately.
3157 *
3158 * @param atPath the path of the node that is to be unlocked
3159 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3160 */
3161 public BatchConjunction unlock( String atPath ) {
3162 return unlock(Location.create(createPath(atPath)));
3163 }
3164
3165 /**
3166 * Request to unlock the node at the given path. This request is submitted to the repository immediately.
3167 *
3168 * @param at the path of the node that is to be unlocked
3169 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3170 */
3171 public BatchConjunction unlock( Path at ) {
3172 return unlock(Location.create(at));
3173 }
3174
3175 /**
3176 * Request to unlock the node with the given UUID. This request is submitted to the repository immediately.
3177 *
3178 * @param at the UUID of the node that is to be unlocked
3179 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3180 */
3181 public BatchConjunction unlock( UUID at ) {
3182 return unlock(Location.create(at));
3183 }
3184
3185 /**
3186 * Request to unlock the node with the given unique identification property. This request is submitted to the repository
3187 * immediately.
3188 *
3189 * @param idProperty the unique identifying property of the node that is to be unlocked
3190 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3191 */
3192 public BatchConjunction unlock( Property idProperty ) {
3193 return unlock(Location.create(idProperty));
3194 }
3195
3196 /**
3197 * Request to unlock the node with the given identification properties. The identification properties should uniquely
3198 * identify a single node. This request is submitted to the repository immediately.
3199 *
3200 * @param firstIdProperty the first identification property of the node that is to be copied
3201 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
3202 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3203 */
3204 public BatchConjunction unlock( Property firstIdProperty,
3205 Property... additionalIdProperties ) {
3206 return unlock(Location.create(firstIdProperty, additionalIdProperties));
3207 }
3208
3209 /**
3210 * Request to unlock the node at the given location. This request is submitted to the repository immediately.
3211 *
3212 * @param at the location of the node that is to be unlocked
3213 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3214 */
3215 public BatchConjunction unlock( Location at ) {
3216 requests.unlockBranch(workspaceName, at);
3217 return this.nextRequests;
3218 }
3219
3220 /**
3221 * Begin the request to clone the specified node into a parent node at a different location, which is specified via the
3222 * <code>into(...)</code> method on the returned {@link Clone} object.
3223 * <p>
3224 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3225 * called.
3226 * </p>
3227 *
3228 * @param from the node that is to be copied.
3229 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3230 * is to be copied
3231 */
3232 public Clone<BatchConjunction> clone( Node from ) {
3233 return clone(from.getLocation());
3234 }
3235
3236 /**
3237 * Begin the request to clone a node at the specified location into a parent node at a different location, which is
3238 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
3239 * <p>
3240 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3241 * called.
3242 * </p>
3243 *
3244 * @param from the location of the node that is to be copied.
3245 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3246 * is to be copied
3247 */
3248 public Clone<BatchConjunction> clone( Location from ) {
3249 assertNotExecuted();
3250 return new CloneAction<BatchConjunction>(this.nextRequests, from) {
3251 @Override
3252 protected BatchConjunction submit( String fromWorkspaceName,
3253 Location from,
3254 String intoWorkspaceName,
3255 Location into,
3256 Name desiredName,
3257 Segment desiredSegment,
3258 boolean removeExisting ) {
3259 requestQueue.cloneBranch(from,
3260 fromWorkspaceName,
3261 into,
3262 intoWorkspaceName,
3263 desiredName,
3264 desiredSegment,
3265 removeExisting);
3266 return and();
3267 }
3268 };
3269 }
3270
3271 /**
3272 * Begin the request to clone a node located at the supplied path into a parent node at a different location, which is
3273 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
3274 * <p>
3275 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3276 * called.
3277 * </p>
3278 *
3279 * @param fromPath the path to the node that is to be copied.
3280 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3281 * is to be copied
3282 */
3283 public Clone<BatchConjunction> clone( String fromPath ) {
3284 return clone(Location.create(createPath(fromPath)));
3285 }
3286
3287 /**
3288 * Begin the request to clone a node located at the supplied path into a parent node at a different location, which is
3289 * specified via the <code>into(...)</code> method on the returned {@link Clone} object.
3290 * <p>
3291 * Like all other methods on the {@link Graph}, the clone request will be performed immediately when the
3292 * <code>into(...)</code> method is called.
3293 * </p>
3294 *
3295 * @param from the path to the node that is to be copied.
3296 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3297 * is to be copied
3298 */
3299 public Clone<BatchConjunction> clone( Path from ) {
3300 return clone(Location.create(from));
3301 }
3302
3303 /**
3304 * Begin the request to clone a node with the specified unique identifier into a parent node at a different location,
3305 * which is specified via the <code>into(...)</code> method on the returned {@link Clone} object.
3306 * <p>
3307 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3308 * called.
3309 * </p>
3310 *
3311 * @param from the UUID of the node that is to be copied.
3312 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3313 * is to be copied
3314 */
3315 public Clone<BatchConjunction> clone( UUID from ) {
3316 return clone(Location.create(from));
3317 }
3318
3319 /**
3320 * Begin the request to clone a node with the specified unique identification property into a parent node at a different
3321 * location, which is specified via the <code>into(...)</code> method on the returned {@link Clone} object. The
3322 * identification property should uniquely identify a single node.
3323 * <p>
3324 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3325 * called.
3326 * </p>
3327 *
3328 * @param idProperty the unique identification property of the node that is to be copied.
3329 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3330 * is to be copied
3331 */
3332 public Clone<BatchConjunction> clone( Property idProperty ) {
3333 return clone(Location.create(idProperty));
3334 }
3335
3336 /**
3337 * Begin the request to clone a node with the specified identification properties into a parent node at a different
3338 * location, which is specified via the <code>into(...)</code> method on the returned {@link Clone} object. The
3339 * identification properties should uniquely identify a single node.
3340 * <p>
3341 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3342 * called.
3343 * </p>
3344 *
3345 * @param firstIdProperty the first identification property of the node that is to be copied
3346 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
3347 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3348 * is to be copied
3349 */
3350 public Clone<BatchConjunction> clone( Property firstIdProperty,
3351 Property... additionalIdProperties ) {
3352 return clone(Location.create(firstIdProperty, additionalIdProperties));
3353 }
3354
3355 /**
3356 * Begin the request to clone a node with the specified identification properties into a parent node at a different
3357 * location, which is specified via the <code>into(...)</code> method on the returned {@link Clone} object. The
3358 * identification properties should uniquely identify a single node.
3359 * <p>
3360 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3361 * called.
3362 * </p>
3363 *
3364 * @param idProperties the identification properties of the node that is to be copied
3365 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3366 * is to be copied
3367 */
3368 public Clone<BatchConjunction> clone( Iterable<Property> idProperties ) {
3369 return clone(Location.create(idProperties));
3370 }
3371
3372 /**
3373 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
3374 * <code>into(...)</code> method on the returned {@link Copy} object.
3375 * <p>
3376 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3377 * called.
3378 * </p>
3379 *
3380 * @param from the node that is to be copied.
3381 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3382 * is to be copied
3383 */
3384 public Copy<BatchConjunction> copy( Node from ) {
3385 return copy(from.getLocation());
3386 }
3387
3388 /**
3389 * Begin the request to copy a node at the specified location into a parent node at a different location, which is
3390 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
3391 * <p>
3392 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3393 * called.
3394 * </p>
3395 *
3396 * @param from the location of the node that is to be copied.
3397 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3398 * is to be copied
3399 */
3400 public Copy<BatchConjunction> copy( Location from ) {
3401 assertNotExecuted();
3402 return new CopyAction<BatchConjunction>(this.nextRequests, from) {
3403 @Override
3404 protected BatchConjunction submit( String fromWorkspaceName,
3405 Locations from,
3406 Location into,
3407 Name copyName ) {
3408
3409 String intoWorkspaceName = getCurrentWorkspaceName();
3410 if (fromWorkspaceName == null) fromWorkspaceName = intoWorkspaceName;
3411 do {
3412 requestQueue.copyBranch(from.getLocation(), fromWorkspaceName, into, intoWorkspaceName, copyName, null);
3413 } while ((from = from.next()) != null);
3414 return and();
3415 }
3416 };
3417 }
3418
3419 /**
3420 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
3421 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
3422 * <p>
3423 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3424 * called.
3425 * </p>
3426 *
3427 * @param fromPath the path to the node that is to be copied.
3428 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3429 * is to be copied
3430 */
3431 public Copy<BatchConjunction> copy( String fromPath ) {
3432 return copy(Location.create(createPath(fromPath)));
3433 }
3434
3435 /**
3436 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
3437 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
3438 * <p>
3439 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the
3440 * <code>into(...)</code> method is called.
3441 * </p>
3442 *
3443 * @param from the path to the node that is to be copied.
3444 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3445 * is to be copied
3446 */
3447 public Copy<BatchConjunction> copy( Path from ) {
3448 return copy(Location.create(from));
3449 }
3450
3451 /**
3452 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which
3453 * is specified via the <code>into(...)</code> method on the returned {@link Copy} object.
3454 * <p>
3455 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3456 * called.
3457 * </p>
3458 *
3459 * @param from the UUID of the node that is to be copied.
3460 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3461 * is to be copied
3462 */
3463 public Copy<BatchConjunction> copy( UUID from ) {
3464 return copy(Location.create(from));
3465 }
3466
3467 /**
3468 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
3469 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
3470 * identification property should uniquely identify a single node.
3471 * <p>
3472 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3473 * called.
3474 * </p>
3475 *
3476 * @param idProperty the unique identification property of the node that is to be copied.
3477 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3478 * is to be copied
3479 */
3480 public Copy<BatchConjunction> copy( Property idProperty ) {
3481 return copy(Location.create(idProperty));
3482 }
3483
3484 /**
3485 * Begin the request to copy a node with the specified identification properties into a parent node at a different
3486 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
3487 * identification properties should uniquely identify a single node.
3488 * <p>
3489 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3490 * called.
3491 * </p>
3492 *
3493 * @param firstIdProperty the first identification property of the node that is to be copied
3494 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
3495 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3496 * is to be copied
3497 */
3498 public Copy<BatchConjunction> copy( Property firstIdProperty,
3499 Property... additionalIdProperties ) {
3500 return copy(Location.create(firstIdProperty, additionalIdProperties));
3501 }
3502
3503 /**
3504 * Begin the request to copy a node with the specified identification properties into a parent node at a different
3505 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
3506 * identification properties should uniquely identify a single node.
3507 * <p>
3508 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3509 * called.
3510 * </p>
3511 *
3512 * @param idProperties the identification properties of the node that is to be copied
3513 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
3514 * is to be copied
3515 */
3516 public Copy<BatchConjunction> copy( Iterable<Property> idProperties ) {
3517 return copy(Location.create(idProperties));
3518 }
3519
3520 /**
3521 * Request to delete the specified node.
3522 * <p>
3523 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3524 * called.
3525 * </p>
3526 *
3527 * @param at the node that is to be deleted
3528 * @return an object that may be used to start another request
3529 */
3530 public BatchConjunction delete( Node at ) {
3531 return delete(at.getLocation());
3532 }
3533
3534 /**
3535 * Request to delete the node at the given location.
3536 * <p>
3537 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3538 * called.
3539 * </p>
3540 *
3541 * @param at the location of the node that is to be deleted
3542 * @return an object that may be used to start another request
3543 */
3544 public BatchConjunction delete( Location at ) {
3545 assertNotExecuted();
3546 this.requestQueue.deleteBranch(at, getCurrentWorkspaceName());
3547 return nextRequests;
3548 }
3549
3550 /**
3551 * Request to delete the node at the given path.
3552 * <p>
3553 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3554 * called.
3555 * </p>
3556 *
3557 * @param atPath the path of the node that is to be deleted
3558 * @return an object that may be used to start another request
3559 */
3560 public BatchConjunction delete( String atPath ) {
3561 return delete(Location.create(createPath(atPath)));
3562 }
3563
3564 /**
3565 * Request to delete the node at the given path.
3566 * <p>
3567 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3568 * called.
3569 * </p>
3570 *
3571 * @param at the path of the node that is to be deleted
3572 * @return an object that may be used to start another request
3573 */
3574 public BatchConjunction delete( Path at ) {
3575 return delete(Location.create(at));
3576 }
3577
3578 /**
3579 * Request to delete the node with the given UUID.
3580 * <p>
3581 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3582 * called.
3583 * </p>
3584 *
3585 * @param at the UUID of the node that is to be deleted
3586 * @return an object that may be used to start another request
3587 */
3588 public BatchConjunction delete( UUID at ) {
3589 return delete(Location.create(at));
3590 }
3591
3592 /**
3593 * Request to delete the node with the given unique identification property.
3594 * <p>
3595 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3596 * called.
3597 * </p>
3598 *
3599 * @param idProperty the unique identifying property of the node that is to be deleted
3600 * @return an object that may be used to start another request
3601 */
3602 public BatchConjunction delete( Property idProperty ) {
3603 return delete(Location.create(idProperty));
3604 }
3605
3606 /**
3607 * Request to delete the node with the given identification properties. The identification properties should uniquely
3608 * identify a single node.
3609 * <p>
3610 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3611 * called.
3612 * </p>
3613 *
3614 * @param firstIdProperty the first identification property of the node that is to be copied
3615 * @param additionalIdProperties the remaining identification properties of the node that is to be copied
3616 * @return an object that may be used to start another request
3617 */
3618 public BatchConjunction delete( Property firstIdProperty,
3619 Property... additionalIdProperties ) {
3620 return delete(Location.create(firstIdProperty, additionalIdProperties));
3621 }
3622
3623 /**
3624 * Request to delete the node with the given identification properties. The identification properties should uniquely
3625 * identify a single node.
3626 * <p>
3627 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3628 * called.
3629 * </p>
3630 *
3631 * @param idProperties the identification property of the node that is to be copied
3632 * @return an object that may be used to start another request
3633 */
3634 public BatchConjunction delete( Iterable<Property> idProperties ) {
3635 return delete(Location.create(idProperties));
3636 }
3637
3638 /**
3639 * Begin the request to create a node located at the supplied path.
3640 * <p>
3641 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3642 * called.
3643 * </p>
3644 *
3645 * @param atPath the path to the node that is to be created.
3646 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3647 * node where the node is to be created
3648 */
3649 public Create<Batch> create( String atPath ) {
3650 return create(createPath(atPath));
3651 }
3652
3653 /**
3654 * Begin the request to create a node located at the supplied path.
3655 * <p>
3656 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3657 * called.
3658 * </p>
3659 *
3660 * @param atPath the path to the node that is to be created.
3661 * @param property a property for the new node
3662 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3663 * node where the node is to be created
3664 */
3665 public Create<Batch> create( String atPath,
3666 Property property ) {
3667 return create(createPath(atPath)).with(property);
3668 }
3669
3670 /**
3671 * Begin the request to create a node located at the supplied path.
3672 * <p>
3673 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3674 * called.
3675 * </p>
3676 *
3677 * @param atPath the path to the node that is to be created.
3678 * @param firstProperty a property for the new node
3679 * @param additionalProperties additional properties for the new node
3680 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3681 * node where the node is to be created
3682 */
3683 public Create<Batch> create( String atPath,
3684 Property firstProperty,
3685 Property... additionalProperties ) {
3686 return create(createPath(atPath)).with(firstProperty, additionalProperties);
3687 }
3688
3689 /**
3690 * Begin the request to create a node located at the supplied path.
3691 * <p>
3692 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3693 * called.
3694 * </p>
3695 *
3696 * @param at the path to the node that is to be created.
3697 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3698 * node where the node is to be created
3699 */
3700 public final Create<Batch> create( Path at ) {
3701 assertNotExecuted();
3702 CheckArg.isNotNull(at, "at");
3703 Path parent = at.getParent();
3704 Name name = at.getLastSegment().getName();
3705 return create(Location.create(parent), name);
3706 }
3707
3708 protected final CreateAction<Batch> create( Location parent,
3709 Name child ) {
3710 return new CreateAction<Batch>(this, parent, getCurrentWorkspaceName(), child) {
3711 @Override
3712 protected Batch submit( Location parent,
3713 String workspaceName,
3714 Name childName,
3715 Collection<Property> properties,
3716 NodeConflictBehavior behavior ) {
3717 requestQueue.createNode(parent, workspaceName, childName, properties.iterator(), behavior);
3718 return Batch.this;
3719 }
3720 };
3721 }
3722
3723 /**
3724 * Begin the request to create a node located at the supplied path.
3725 * <p>
3726 * Like all other methods on the {@link Batch}, the request will be performed when the {@link Batch#execute()} method is
3727 * called.
3728 * </p>
3729 *
3730 * @param at the path to the node that is to be created.
3731 * @param properties the iterator over the properties for the new node
3732 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3733 * node where the node is to be created
3734 */
3735 public Create<Batch> create( Path at,
3736 Iterable<Property> properties ) {
3737 Create<Batch> action = create(at);
3738 for (Property property : properties) {
3739 action.and(property);
3740 }
3741 return action;
3742 }
3743
3744 /**
3745 * Begin the request to create a node located at the supplied path.
3746 * <p>
3747 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3748 * called.
3749 * </p>
3750 *
3751 * @param at the path to the node that is to be created.
3752 * @param property a property for the new node
3753 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3754 * node where the node is to be created
3755 */
3756 public Create<Batch> create( Path at,
3757 Property property ) {
3758 return create(at).with(property);
3759 }
3760
3761 /**
3762 * Begin the request to create a node located at the supplied path.
3763 * <p>
3764 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3765 * called.
3766 * </p>
3767 *
3768 * @param at the path to the node that is to be created.
3769 * @param firstProperty a property for the new node
3770 * @param additionalProperties additional properties for the new node
3771 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
3772 * node where the node is to be created
3773 */
3774 public Create<Batch> create( Path at,
3775 Property firstProperty,
3776 Property... additionalProperties ) {
3777 return create(at).with(firstProperty, additionalProperties);
3778 }
3779
3780 /**
3781 * Begin the request to create a node under the existing parent node at the supplied location. This request is submitted
3782 * to the repository after the returned components are completed.
3783 *
3784 * @param parent the location of the parent
3785 * @return the object used to start creating a node
3786 */
3787 public CreateNodeNamed<Batch> createUnder( Location parent ) {
3788 CheckArg.isNotNull(parent, "parent");
3789 return new CreateNodeNamedAction<Batch>(this, parent) {
3790 @Override
3791 protected CreateAction<Batch> createWith( Batch batch,
3792 Location parent,
3793 Name childName ) {
3794 return Batch.this.create(parent, childName);
3795 }
3796 };
3797 }
3798
3799 public AddValue<Batch> addValue( Object value ) {
3800 return new AddValueAction<Batch>(this, this.getCurrentWorkspaceName(), value) {
3801
3802 @Override
3803 protected Batch submit( String workspaceName,
3804 Location on,
3805 Name property,
3806 List<Object> values ) {
3807 requests.addValues(workspaceName, on, property, values);
3808 return nextRequests.and();
3809 }
3810 };
3811 }
3812
3813 public RemoveValue<Batch> removeValue( Object value ) {
3814 return new RemoveValueAction<Batch>(this, this.getCurrentWorkspaceName(), value) {
3815
3816 @Override
3817 protected Batch submit( String workspaceName,
3818 Location on,
3819 Name property,
3820 List<Object> values ) {
3821 requests.removeValues(workspaceName, on, property, values);
3822 return nextRequests.and();
3823 }
3824 };
3825 }
3826
3827 /**
3828 * Set the properties on a node.
3829 *
3830 * @param properties the properties to set
3831 * @return the interface that should be used to specify the node on which the properties are to be set.
3832 */
3833 public On<BatchConjunction> set( final Property... properties ) {
3834 return new On<BatchConjunction>() {
3835 public BatchConjunction on( Location location ) {
3836 requestQueue.setProperties(location, getCurrentWorkspaceName(), properties);
3837 return nextRequests;
3838 }
3839
3840 public BatchConjunction on( String path ) {
3841 return on(Location.create(createPath(path)));
3842 }
3843
3844 public BatchConjunction on( Path path ) {
3845 return on(Location.create(path));
3846 }
3847
3848 public BatchConjunction on( Property idProperty ) {
3849 return on(Location.create(idProperty));
3850 }
3851
3852 public BatchConjunction on( Property firstIdProperty,
3853 Property... additionalIdProperties ) {
3854 return on(Location.create(firstIdProperty, additionalIdProperties));
3855 }
3856
3857 public BatchConjunction on( Iterable<Property> idProperties ) {
3858 return on(Location.create(idProperties));
3859 }
3860
3861 public BatchConjunction on( UUID uuid ) {
3862 return on(Location.create(uuid));
3863 }
3864 };
3865 }
3866
3867 /**
3868 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
3869 * value(s) and the location of the node onto which the property should be set.
3870 *
3871 * @param propertyName the property name
3872 * @return the interface used to specify the values
3873 */
3874 public SetValues<BatchConjunction> set( String propertyName ) {
3875 Name name = getContext().getValueFactories().getNameFactory().create(propertyName);
3876 return set(name);
3877 }
3878
3879 /**
3880 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
3881 * value(s) and the location of the node onto which the property should be set.
3882 *
3883 * @param propertyName the property name
3884 * @return the interface used to specify the values
3885 */
3886 public SetValues<BatchConjunction> set( final Name propertyName ) {
3887 return new SetValues<BatchConjunction>() {
3888 public SetValuesTo<BatchConjunction> on( final Location location ) {
3889 return new SetValuesTo<BatchConjunction>() {
3890 public BatchConjunction to( Node value ) {
3891 return to(value.getLocation());
3892 }
3893
3894 public BatchConjunction to( Location value ) {
3895 Reference ref = (Reference)convertReferenceValue(value);
3896 Property property = getContext().getPropertyFactory().create(propertyName, ref);
3897 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
3898 return nextRequests;
3899 }
3900
3901 protected BatchConjunction toValue( Object value ) {
3902 Property property = getContext().getPropertyFactory().create(propertyName, value);
3903 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
3904 return nextRequests;
3905 }
3906
3907 public BatchConjunction to( String value ) {
3908 return toValue(value);
3909 }
3910
3911 public BatchConjunction to( int value ) {
3912 return toValue(Integer.valueOf(value));
3913 }
3914
3915 public BatchConjunction to( long value ) {
3916 return toValue(Long.valueOf(value));
3917 }
3918
3919 public BatchConjunction to( boolean value ) {
3920 return toValue(Boolean.valueOf(value));
3921 }
3922
3923 public BatchConjunction to( float value ) {
3924 return toValue(Float.valueOf(value));
3925 }
3926
3927 public BatchConjunction to( double value ) {
3928 return toValue(Double.valueOf(value));
3929 }
3930
3931 public BatchConjunction to( BigDecimal value ) {
3932 return toValue(value);
3933 }
3934
3935 public BatchConjunction to( Calendar value ) {
3936 return toValue(value);
3937 }
3938
3939 public BatchConjunction to( Date value ) {
3940 return toValue(value);
3941 }
3942
3943 public BatchConjunction to( DateTime value ) {
3944 return toValue(value);
3945 }
3946
3947 public BatchConjunction to( Name value ) {
3948 return toValue(value);
3949 }
3950
3951 public BatchConjunction to( Path value ) {
3952 return toValue(value);
3953 }
3954
3955 public BatchConjunction to( Reference value ) {
3956 return toValue(value);
3957 }
3958
3959 public BatchConjunction to( URI value ) {
3960 return toValue(value);
3961 }
3962
3963 public BatchConjunction to( UUID value ) {
3964 return toValue(value);
3965 }
3966
3967 public BatchConjunction to( Binary value ) {
3968 return toValue(value);
3969 }
3970
3971 public BatchConjunction to( byte[] value ) {
3972 return toValue(value);
3973 }
3974
3975 public BatchConjunction to( InputStream stream,
3976 long approximateLength ) {
3977 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
3978 return toValue(value);
3979 }
3980
3981 public BatchConjunction to( Reader reader,
3982 long approximateLength ) {
3983 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
3984 return toValue(value);
3985 }
3986
3987 public BatchConjunction to( Object value ) {
3988 value = convertReferenceValue(value);
3989 Property property = getContext().getPropertyFactory().create(propertyName, value);
3990 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
3991 return nextRequests;
3992 }
3993
3994 public BatchConjunction to( Object firstValue,
3995 Object... otherValues ) {
3996 firstValue = convertReferenceValue(firstValue);
3997 for (int i = 0, len = otherValues.length; i != len; ++i) {
3998 otherValues[i] = convertReferenceValue(otherValues[i]);
3999 }
4000 Property property = getContext().getPropertyFactory().create(propertyName, firstValue, otherValues);
4001 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
4002 return nextRequests;
4003 }
4004
4005 public BatchConjunction to( Object[] values ) {
4006 for (int i = 0; i != values.length; ++i) {
4007 values[i] = convertReferenceValue(values[i]);
4008 }
4009 Property property = getContext().getPropertyFactory().create(propertyName, values);
4010 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
4011 return nextRequests;
4012 }
4013
4014 public BatchConjunction to( Iterable<?> values ) {
4015 List<Object> valueList = new LinkedList<Object>();
4016 for (Object value : values) {
4017 value = convertReferenceValue(value);
4018 valueList.add(value);
4019 }
4020 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
4021 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
4022 return nextRequests;
4023 }
4024
4025 public BatchConjunction to( Iterator<?> values ) {
4026 List<Object> valueList = new LinkedList<Object>();
4027 while (values.hasNext()) {
4028 Object value = values.next();
4029 valueList.add(value);
4030 }
4031 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
4032 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
4033 return nextRequests;
4034 }
4035
4036 };
4037 }
4038
4039 public SetValuesTo<BatchConjunction> on( String path ) {
4040 return on(Location.create(createPath(path)));
4041 }
4042
4043 public SetValuesTo<BatchConjunction> on( Path path ) {
4044 return on(Location.create(path));
4045 }
4046
4047 public SetValuesTo<BatchConjunction> on( Property idProperty ) {
4048 return on(Location.create(idProperty));
4049 }
4050
4051 public SetValuesTo<BatchConjunction> on( Property firstIdProperty,
4052 Property... additionalIdProperties ) {
4053 return on(Location.create(firstIdProperty, additionalIdProperties));
4054 }
4055
4056 public SetValuesTo<BatchConjunction> on( Iterable<Property> idProperties ) {
4057 return on(Location.create(idProperties));
4058 }
4059
4060 public SetValuesTo<BatchConjunction> on( UUID uuid ) {
4061 return on(Location.create(uuid));
4062 }
4063
4064 public On<BatchConjunction> to( Node value ) {
4065 Object reference = convertReferenceValue(value);
4066 return set(getContext().getPropertyFactory().create(propertyName, reference));
4067 }
4068
4069 public On<BatchConjunction> to( Location value ) {
4070 Object reference = convertReferenceValue(value);
4071 return set(getContext().getPropertyFactory().create(propertyName, reference));
4072 }
4073
4074 protected On<BatchConjunction> toValue( Object value ) {
4075 return set(getContext().getPropertyFactory().create(propertyName, value));
4076 }
4077
4078 public On<BatchConjunction> to( String value ) {
4079 return toValue(value);
4080 }
4081
4082 public On<BatchConjunction> to( int value ) {
4083 return toValue(Integer.valueOf(value));
4084 }
4085
4086 public On<BatchConjunction> to( long value ) {
4087 return toValue(Long.valueOf(value));
4088 }
4089
4090 public On<BatchConjunction> to( boolean value ) {
4091 return toValue(Boolean.valueOf(value));
4092 }
4093
4094 public On<BatchConjunction> to( float value ) {
4095 return toValue(Float.valueOf(value));
4096 }
4097
4098 public On<BatchConjunction> to( double value ) {
4099 return toValue(Double.valueOf(value));
4100 }
4101
4102 public On<BatchConjunction> to( BigDecimal value ) {
4103 return toValue(value);
4104 }
4105
4106 public On<BatchConjunction> to( Calendar value ) {
4107 return toValue(value);
4108 }
4109
4110 public On<BatchConjunction> to( Date value ) {
4111 return toValue(value);
4112 }
4113
4114 public On<BatchConjunction> to( DateTime value ) {
4115 return toValue(value);
4116 }
4117
4118 public On<BatchConjunction> to( Name value ) {
4119 return toValue(value);
4120 }
4121
4122 public On<BatchConjunction> to( Path value ) {
4123 return toValue(value);
4124 }
4125
4126 public On<BatchConjunction> to( Reference value ) {
4127 return toValue(value);
4128 }
4129
4130 public On<BatchConjunction> to( URI value ) {
4131 return toValue(value);
4132 }
4133
4134 public On<BatchConjunction> to( UUID value ) {
4135 return toValue(value);
4136 }
4137
4138 public On<BatchConjunction> to( Binary value ) {
4139 return toValue(value);
4140 }
4141
4142 public On<BatchConjunction> to( byte[] value ) {
4143 return toValue(value);
4144 }
4145
4146 public On<BatchConjunction> to( InputStream stream,
4147 long approximateLength ) {
4148 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
4149 return toValue(value);
4150 }
4151
4152 public On<BatchConjunction> to( Reader reader,
4153 long approximateLength ) {
4154 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
4155 return toValue(value);
4156 }
4157
4158 public On<BatchConjunction> to( Object value ) {
4159 value = convertReferenceValue(value);
4160 return set(getContext().getPropertyFactory().create(propertyName, value));
4161 }
4162
4163 public On<BatchConjunction> to( Object firstValue,
4164 Object... otherValues ) {
4165 Object[] values = new Object[otherValues.length + 1];
4166 values[0] = convertReferenceValue(firstValue);
4167 for (int i = 0, len = otherValues.length; i != len; ++i) {
4168 values[i + 1] = convertReferenceValue(otherValues[i]);
4169 }
4170 return set(getContext().getPropertyFactory().create(propertyName, values));
4171 }
4172
4173 public On<BatchConjunction> to( Object[] values ) {
4174 for (int i = 0, len = values.length; i != len; ++i) {
4175 values[i] = convertReferenceValue(values[i]);
4176 }
4177 return set(getContext().getPropertyFactory().create(propertyName, values));
4178 }
4179
4180 public On<BatchConjunction> to( Iterable<?> values ) {
4181 List<Object> valueList = new LinkedList<Object>();
4182 for (Object value : values) {
4183 value = convertReferenceValue(value);
4184 valueList.add(value);
4185 }
4186 return set(getContext().getPropertyFactory().create(propertyName, valueList));
4187 }
4188
4189 public On<BatchConjunction> to( Iterator<?> values ) {
4190 List<Object> valueList = new LinkedList<Object>();
4191 while (values.hasNext()) {
4192 Object value = values.next();
4193 valueList.add(value);
4194 }
4195 return set(getContext().getPropertyFactory().create(propertyName, valueList));
4196 }
4197 };
4198 }
4199
4200 /**
4201 * Remove properties from the node at the given location.
4202 *
4203 * @param propertyNames the names of the properties to be removed
4204 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
4205 */
4206 public On<BatchConjunction> remove( final Name... propertyNames ) {
4207 return new On<BatchConjunction>() {
4208 public BatchConjunction on( Location location ) {
4209 requestQueue.removeProperties(location, getCurrentWorkspaceName(), propertyNames);
4210 return nextRequests;
4211 }
4212
4213 public BatchConjunction on( String path ) {
4214 return on(Location.create(createPath(path)));
4215 }
4216
4217 public BatchConjunction on( Path path ) {
4218 return on(Location.create(path));
4219 }
4220
4221 public BatchConjunction on( Property idProperty ) {
4222 return on(Location.create(idProperty));
4223 }
4224
4225 public BatchConjunction on( Property firstIdProperty,
4226 Property... additionalIdProperties ) {
4227 return on(Location.create(firstIdProperty, additionalIdProperties));
4228 }
4229
4230 public BatchConjunction on( Iterable<Property> idProperties ) {
4231 return on(Location.create(idProperties));
4232 }
4233
4234 public BatchConjunction on( UUID uuid ) {
4235 return on(Location.create(uuid));
4236 }
4237 };
4238 }
4239
4240 /**
4241 * Remove properties from the node at the given location.
4242 *
4243 * @param propertyNames the names of the properties to be removed
4244 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
4245 */
4246 public On<BatchConjunction> remove( String... propertyNames ) {
4247 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
4248 int number = propertyNames.length;
4249 final Name[] names = new Name[number];
4250 for (int i = 0; i != number; ++i) {
4251 names[i] = nameFactory.create(propertyNames[i]);
4252 }
4253 return new On<BatchConjunction>() {
4254 public BatchConjunction on( Location location ) {
4255 requestQueue.removeProperties(location, getCurrentWorkspaceName(), names);
4256 return nextRequests;
4257 }
4258
4259 public BatchConjunction on( String path ) {
4260 return on(Location.create(createPath(path)));
4261 }
4262
4263 public BatchConjunction on( Path path ) {
4264 return on(Location.create(path));
4265 }
4266
4267 public BatchConjunction on( Property idProperty ) {
4268 return on(Location.create(idProperty));
4269 }
4270
4271 public BatchConjunction on( Property firstIdProperty,
4272 Property... additionalIdProperties ) {
4273 return on(Location.create(firstIdProperty, additionalIdProperties));
4274 }
4275
4276 public BatchConjunction on( Iterable<Property> idProperties ) {
4277 return on(Location.create(idProperties));
4278 }
4279
4280 public BatchConjunction on( UUID uuid ) {
4281 return on(Location.create(uuid));
4282 }
4283 };
4284 }
4285
4286 /**
4287 * Request to read the node with the supplied UUID.
4288 * <p>
4289 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4290 * called.
4291 * </p>
4292 *
4293 * @param uuid the UUID of the node that is to be read
4294 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4295 */
4296 public BatchConjunction read( UUID uuid ) {
4297 return read(Location.create(uuid));
4298 }
4299
4300 /**
4301 * Request to read the node at the supplied location.
4302 * <p>
4303 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4304 * called.
4305 * </p>
4306 *
4307 * @param location the location of the node that is to be read
4308 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4309 */
4310 public BatchConjunction read( Location location ) {
4311 assertNotExecuted();
4312 requestQueue.readNode(location, getCurrentWorkspaceName());
4313 return nextRequests;
4314 }
4315
4316 /**
4317 * Request to read the node at the supplied path.
4318 * <p>
4319 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4320 * called.
4321 * </p>
4322 *
4323 * @param path the path of the node that is to be read
4324 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4325 */
4326 public BatchConjunction read( String path ) {
4327 return read(Location.create(createPath(path)));
4328 }
4329
4330 /**
4331 * Request to read the node at the supplied path.
4332 * <p>
4333 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4334 * called.
4335 * </p>
4336 *
4337 * @param path the path of the node that is to be read
4338 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4339 */
4340 public BatchConjunction read( Path path ) {
4341 return read(Location.create(path));
4342 }
4343
4344 /**
4345 * Request to read the node with the supplied unique identifier property.
4346 * <p>
4347 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4348 * called.
4349 * </p>
4350 *
4351 * @param idProperty the identification property that is unique to the node that is to be read
4352 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4353 */
4354 public BatchConjunction read( Property idProperty ) {
4355 return read(Location.create(idProperty));
4356 }
4357
4358 /**
4359 * Request to read the node with the supplied unique identifier properties.
4360 * <p>
4361 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4362 * called.
4363 * </p>
4364 *
4365 * @param firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
4366 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be
4367 * read
4368 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4369 */
4370 public BatchConjunction read( Property firstIdProperty,
4371 Property... additionalIdProperties ) {
4372 return read(Location.create(firstIdProperty, additionalIdProperties));
4373 }
4374
4375 /**
4376 * Request to read the node with the supplied unique identifier properties.
4377 * <p>
4378 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4379 * called.
4380 * </p>
4381 *
4382 * @param idProperties the identification properties that uniquely identify the node that is to be read
4383 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
4384 */
4385 public BatchConjunction read( Iterable<Property> idProperties ) {
4386 return read(Location.create(idProperties));
4387 }
4388
4389 /**
4390 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
4391 * returned {@link On} object.
4392 * <p>
4393 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4394 * called.
4395 * </p>
4396 *
4397 * @param propertyName the name of the property that is to be read
4398 * @return the object that is used to specified the node whose property is to be read
4399 */
4400 public On<BatchConjunction> readProperty( String propertyName ) {
4401 assertNotExecuted();
4402 Name name = Graph.this.getContext().getValueFactories().getNameFactory().create(propertyName);
4403 return readProperty(name);
4404 }
4405
4406 /**
4407 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
4408 * returned {@link On} object.
4409 * <p>
4410 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4411 * called.
4412 * </p>
4413 *
4414 * @param name the name of the property that is to be read
4415 * @return the object that is used to specified the node whose property is to be read
4416 */
4417 public On<BatchConjunction> readProperty( final Name name ) {
4418 assertNotExecuted();
4419 return new On<BatchConjunction>() {
4420 public BatchConjunction on( String path ) {
4421 return on(Location.create(createPath(path)));
4422 }
4423
4424 public BatchConjunction on( Path path ) {
4425 return on(Location.create(path));
4426 }
4427
4428 public BatchConjunction on( Property idProperty ) {
4429 return on(Location.create(idProperty));
4430 }
4431
4432 public BatchConjunction on( Property firstIdProperty,
4433 Property... additionalIdProperties ) {
4434 return on(Location.create(firstIdProperty, additionalIdProperties));
4435 }
4436
4437 public BatchConjunction on( Iterable<Property> idProperties ) {
4438 return on(Location.create(idProperties));
4439 }
4440
4441 public BatchConjunction on( UUID uuid ) {
4442 return on(Location.create(uuid));
4443 }
4444
4445 public BatchConjunction on( Location at ) {
4446 requestQueue.readProperty(at, getCurrentWorkspaceName(), name);
4447 return Batch.this.nextRequests;
4448 }
4449 };
4450 }
4451
4452 /**
4453 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
4454 * object.
4455 * <p>
4456 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4457 * called.
4458 * </p>
4459 *
4460 * @return the object that is used to specified the node whose properties are to be read,
4461 */
4462 public On<BatchConjunction> readProperties() {
4463 assertNotExecuted();
4464 return new On<BatchConjunction>() {
4465 public BatchConjunction on( Location location ) {
4466 requestQueue.readAllProperties(location, getCurrentWorkspaceName());
4467 return Batch.this.nextRequests;
4468 }
4469
4470 public BatchConjunction on( String path ) {
4471 return on(Location.create(createPath(path)));
4472 }
4473
4474 public BatchConjunction on( Path path ) {
4475 return on(Location.create(path));
4476 }
4477
4478 public BatchConjunction on( Property idProperty ) {
4479 return on(Location.create(idProperty));
4480 }
4481
4482 public BatchConjunction on( Property firstIdProperty,
4483 Property... additionalIdProperties ) {
4484 return on(Location.create(firstIdProperty, additionalIdProperties));
4485 }
4486
4487 public BatchConjunction on( Iterable<Property> idProperties ) {
4488 return on(Location.create(idProperties));
4489 }
4490
4491 public BatchConjunction on( UUID uuid ) {
4492 return on(Location.create(uuid));
4493 }
4494 };
4495 }
4496
4497 /**
4498 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
4499 * object.
4500 * <p>
4501 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4502 * called.
4503 * </p>
4504 *
4505 * @return the object that is used to specified the node whose children are to be read
4506 */
4507 public Of<BatchConjunction> readChildren() {
4508 assertNotExecuted();
4509 return new Of<BatchConjunction>() {
4510 public BatchConjunction of( String path ) {
4511 return of(Location.create(createPath(path)));
4512 }
4513
4514 public BatchConjunction of( Path path ) {
4515 return of(Location.create(path));
4516 }
4517
4518 public BatchConjunction of( Property idProperty ) {
4519 return of(Location.create(idProperty));
4520 }
4521
4522 public BatchConjunction of( Property firstIdProperty,
4523 Property... additionalIdProperties ) {
4524 return of(Location.create(firstIdProperty, additionalIdProperties));
4525 }
4526
4527 public BatchConjunction of( Iterable<Property> idProperties ) {
4528 return of(Location.create(idProperties));
4529 }
4530
4531 public BatchConjunction of( UUID uuid ) {
4532 return of(Location.create(uuid));
4533 }
4534
4535 public BatchConjunction of( Location at ) {
4536 requestQueue.readAllChildren(at, getCurrentWorkspaceName());
4537 return Batch.this.nextRequests;
4538 }
4539 };
4540 }
4541
4542 /**
4543 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code>
4544 * in the resulting {@link At} object.
4545 * <p>
4546 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
4547 * called.
4548 * </p>
4549 *
4550 * @param depth the maximum depth of the subgraph that should be read
4551 * @return the component that should be used to specify the location of the node that is the top of the subgraph
4552 */
4553 public At<BatchConjunction> readSubgraphOfDepth( final int depth ) {
4554 assertNotExecuted();
4555 return new At<BatchConjunction>() {
4556 public BatchConjunction at( Location location ) {
4557 requestQueue.readBranch(location, getCurrentWorkspaceName(), depth);
4558 return Batch.this.nextRequests;
4559 }
4560
4561 public BatchConjunction at( String path ) {
4562 return at(Location.create(createPath(path)));
4563 }
4564
4565 public BatchConjunction at( Path path ) {
4566 return at(Location.create(path));
4567 }
4568
4569 public BatchConjunction at( UUID uuid ) {
4570 return at(Location.create(uuid));
4571 }
4572
4573 public BatchConjunction at( Property idProperty ) {
4574 return at(Location.create(idProperty));
4575 }
4576
4577 public BatchConjunction at( Property firstIdProperty,
4578 Property... additionalIdProperties ) {
4579 return at(Location.create(firstIdProperty, additionalIdProperties));
4580 }
4581
4582 public BatchConjunction at( Iterable<Property> idProperties ) {
4583 return at(Location.create(idProperties));
4584 }
4585 };
4586 }
4587
4588 /**
4589 * {@inheritDoc}
4590 *
4591 * @see org.modeshape.graph.Graph.Executable#execute()
4592 */
4593 public Results execute() {
4594 executed = true;
4595 Request request = requestQueue.pop();
4596 if (request == null) {
4597 return new BatchResults();
4598 }
4599 Graph.this.execute(request);
4600 if (RequestType.COMPOSITE == request.getType()) {
4601 CompositeRequest composite = (CompositeRequest)request;
4602 return new BatchResults(composite.getRequests());
4603 }
4604 return new BatchResults(request);
4605 }
4606
4607 /**
4608 * {@inheritDoc}
4609 *
4610 * @see java.lang.Object#toString()
4611 */
4612 @Override
4613 public String toString() {
4614 StringBuilder sb = new StringBuilder();
4615 sb.append("Pending requests:\n");
4616 sb.append(requestQueue.toString());
4617 return sb.toString();
4618 }
4619 }
4620
4621 /**
4622 * Utility method for checking a property value. If the value is a {@link Node} or {@link Location}, a {@link Reference} value
4623 * is created (if the node/location has a UUID); otherwise, the value is returned as is.
4624 *
4625 * @param value the property value
4626 * @return the property value, which may be a {@link Reference} if the input value is a Node or Location
4627 */
4628 protected Object convertReferenceValue( Object value ) {
4629 if (value instanceof Node) {
4630 Node node = (Node)value;
4631 UUID uuid = node.getLocation().getUuid();
4632 if (uuid == null) {
4633 // Look for a property ...
4634 Property uuidProperty = node.getProperty(ModeShapeLexicon.UUID);
4635 if (uuidProperty != null) {
4636 uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
4637 } else {
4638 uuidProperty = node.getProperty(JcrLexicon.UUID);
4639 if (uuidProperty != null) {
4640 uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
4641 }
4642 }
4643 }
4644 if (uuid == null) {
4645 String nodeString = node.getLocation().getString(getContext().getNamespaceRegistry());
4646 String msg = GraphI18n.unableToCreateReferenceToNodeWithoutUuid.text(nodeString);
4647 throw new IllegalArgumentException(msg);
4648 }
4649 return getContext().getValueFactories().getReferenceFactory().create(uuid);
4650 }
4651 if (value instanceof Location) {
4652 Location location = (Location)value;
4653 UUID uuid = location.getUuid();
4654 if (uuid == null) {
4655 String nodeString = location.getString(getContext().getNamespaceRegistry());
4656 String msg = GraphI18n.unableToCreateReferenceToNodeWithoutUuid.text(nodeString);
4657 throw new IllegalArgumentException(msg);
4658 }
4659 return getContext().getValueFactories().getReferenceFactory().create(uuid);
4660 }
4661 return value;
4662 }
4663
4664 protected static DateTime computeExpirationTime( CacheableRequest request ) {
4665 CachePolicy policy = request.getCachePolicy();
4666 return policy == null ? null : request.getTimeLoaded().plus(policy.getTimeToLive(), TimeUnit.MILLISECONDS);
4667 }
4668
4669 /**
4670 * The interface used to complete a query submission.
4671 */
4672 public interface BuildQuery {
4673 /**
4674 * Use the supplied hints when executing the query.
4675 *
4676 * @param hints the hints
4677 * @return this same interface for method chaining purposes; never null
4678 * @throws IllegalArgumentException if the hints reference is null
4679 */
4680 BuildQuery using( PlanHints hints );
4681
4682 /**
4683 * Use the supplied variables when executing the query.
4684 *
4685 * @param variables the variables
4686 * @return this same interface for method chaining purposes; never null
4687 * @throws IllegalArgumentException if the variables reference is null
4688 */
4689 BuildQuery using( Map<String, Object> variables );
4690
4691 /**
4692 * Use the supplied value for the given variable name when executing the query.
4693 *
4694 * @param variableName the variable value
4695 * @param value the value to replace the variable during execution
4696 * @return this same interface for method chaining purposes; never null
4697 * @throws IllegalArgumentException if the variable name is null
4698 */
4699 BuildQuery using( String variableName,
4700 Object value );
4701
4702 /**
4703 * Execute the query and get the results.
4704 *
4705 * @return the query results
4706 */
4707 QueryResults execute();
4708 }
4709
4710 /**
4711 * The interface used to specify the name of a new workspace.
4712 */
4713 public interface NameWorkspace {
4714
4715 /**
4716 * Specify the name of the new workspace that is to be created.
4717 *
4718 * @param workspaceName the name of the existing workspace that will be cloned to create the new workspace;
4719 * @return the workspace; never null
4720 * @throws IllegalArgumentException if the name of the new workspace is null
4721 * @throws InvalidWorkspaceException if there is already an existing workspace with the supplied name
4722 */
4723 Workspace named( String workspaceName );
4724
4725 /**
4726 * Specify the name of the new workspace that is to be created. If a workspace with the supplied name already exists, the
4727 * new workspace name will be adjusted so that it is unique.
4728 *
4729 * @param workspaceName the name of the existing workspace that will be cloned to create the new workspace;
4730 * @return the workspace; never null
4731 * @throws IllegalArgumentException if the name of the new workspace is null
4732 */
4733 Workspace namedSomethingLike( String workspaceName );
4734 }
4735
4736 /**
4737 * The interface used to create a new workspace.
4738 */
4739 public interface CreateWorkspace extends NameWorkspace {
4740 /**
4741 * Specify that the new workspace should be initialized as a clone of another existing workspace.
4742 *
4743 * @param originalWorkspaceName the name of the existing workspace that will be cloned to create the new workspace;
4744 * @return the interface that should be used to set the name of the new workspace; never null
4745 * @throws IllegalArgumentException if the name of the original workspace is null
4746 * @throws InvalidWorkspaceException if there is no such workspace with the supplied name
4747 */
4748 NameWorkspace clonedFrom( String originalWorkspaceName );
4749 }
4750
4751 /**
4752 * A interface used to execute the accumulated {@link Batch requests}.
4753 *
4754 * @param <NodeType> the type of node that is returned
4755 */
4756 public interface Executable<NodeType extends Node> {
4757 /**
4758 * Stop accumulating the requests, submit them to the repository source, and return the results.
4759 *
4760 * @return the results containing the requested information from the repository.
4761 * @throws PathNotFoundException if a request used a node that did not exist
4762 * @throws InvalidRequestException if a request was not valid
4763 * @throws InvalidWorkspaceException if the workspace used in a request was not valid
4764 * @throws UnsupportedRequestException if a request was not supported by the source
4765 * @throws RepositorySourceException if an error occurs during execution
4766 * @throws RuntimeException if a runtime error occurs during execution
4767 */
4768 Results execute();
4769 }
4770
4771 /**
4772 * A interface that can be used to finish the current request and start another.
4773 *
4774 * @param <Next> the interface that will be used to start another request
4775 */
4776 public interface Conjunction<Next> {
4777 /**
4778 * Finish the request and prepare to start another.
4779 *
4780 * @return the interface that can be used to start another request; never null
4781 */
4782 Next and();
4783 }
4784
4785 /**
4786 * A component that defines the location into which a node should be copied or moved.
4787 *
4788 * @param <Next> The interface that is to be returned when this request is completed
4789 */
4790 public interface Into<Next> {
4791 /**
4792 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4793 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4794 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4795 * {@link To#to(Location)} instead.
4796 *
4797 * @param parentLocation the location of the new parent
4798 * @return the interface for additional requests or actions
4799 * @see To#to(Location)
4800 */
4801 Next into( Location parentLocation );
4802
4803 /**
4804 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4805 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4806 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4807 * {@link To#to(String)} instead.
4808 *
4809 * @param parentPath the path of the new parent
4810 * @return the interface for additional requests or actions
4811 * @see To#to(String)
4812 */
4813 Next into( String parentPath );
4814
4815 /**
4816 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4817 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4818 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4819 * {@link To#to(Path)} instead.
4820 *
4821 * @param parentPath the path of the new parent
4822 * @return the interface for additional requests or actions
4823 * @see To#to(Path)
4824 */
4825 Next into( Path parentPath );
4826
4827 /**
4828 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4829 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4830 * same-name-sibling index).
4831 *
4832 * @param parentUuid the UUID of the new parent
4833 * @return the interface for additional requests or actions
4834 */
4835 Next into( UUID parentUuid );
4836
4837 /**
4838 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4839 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4840 * same-name-sibling index).
4841 *
4842 * @param parentIdProperty the property that uniquely identifies the new parent
4843 * @return the interface for additional requests or actions
4844 */
4845 Next into( Property parentIdProperty );
4846
4847 /**
4848 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
4849 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4850 * same-name-sibling index).
4851 *
4852 * @param firstParentIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies
4853 * the new parent
4854 * @param additionalParentIdProperties the additional properties that, with the <code>additionalIdProperties</code>,
4855 * uniquely identifies the new parent
4856 * @return the interface for additional requests or actions
4857 */
4858 Next into( Property firstParentIdProperty,
4859 Property... additionalParentIdProperties );
4860 }
4861
4862 /**
4863 * A component that defines the location before which a node should be copied or moved. This is similar to an {@link Into},
4864 * but it allows for placing a node at a particular location within the new destination, rather than always placing the moved
4865 * or copied node as the last child of the new parent.
4866 *
4867 * @param <Next> The interface that is to be returned when this request is completed
4868 */
4869 public interface Before<Next> {
4870 /**
4871 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4872 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4873 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4874 * {@link To#to(Location)} instead.
4875 *
4876 * @param parentLocation the location of the new parent
4877 * @return the interface for additional requests or actions
4878 * @see To#to(Location)
4879 */
4880 Next before( Location parentLocation );
4881
4882 /**
4883 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4884 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4885 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4886 * {@link To#to(String)} instead.
4887 *
4888 * @param parentPath the path of the new parent
4889 * @return the interface for additional requests or actions
4890 * @see To#to(String)
4891 */
4892 Next before( String parentPath );
4893
4894 /**
4895 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4896 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4897 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
4898 * {@link To#to(Path)} instead.
4899 *
4900 * @param parentPath the path of the new parent
4901 * @return the interface for additional requests or actions
4902 * @see To#to(Path)
4903 */
4904 Next before( Path parentPath );
4905
4906 /**
4907 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4908 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4909 * same-name-sibling index).
4910 *
4911 * @param parentUuid the UUID of the new parent
4912 * @return the interface for additional requests or actions
4913 */
4914 Next before( UUID parentUuid );
4915
4916 /**
4917 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4918 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4919 * same-name-sibling index).
4920 *
4921 * @param parentIdProperty the property that uniquely identifies the new parent
4922 * @return the interface for additional requests or actions
4923 */
4924 Next before( Property parentIdProperty );
4925
4926 /**
4927 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
4928 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
4929 * same-name-sibling index).
4930 *
4931 * @param firstParentIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies
4932 * the new parent
4933 * @param additionalParentIdProperties the additional properties that, with the <code>additionalIdProperties</code>,
4934 * uniquely identifies the new parent
4935 * @return the interface for additional requests or actions
4936 */
4937 Next before( Property firstParentIdProperty,
4938 Property... additionalParentIdProperties );
4939 }
4940
4941 /**
4942 * A component that defines the name of a property to which a value should be added.
4943 *
4944 * @param <Next> The interface that is to be returned when this request is completed
4945 */
4946 public interface ToName<Next> {
4947
4948 public Next to( String name );
4949
4950 public Next to( Name name );
4951
4952 }
4953
4954 /**
4955 * A component that defines the name of a property from which a value should be removed.
4956 *
4957 * @param <Next> The interface that is to be returned when this request is completed
4958 */
4959 public interface FromName<Next> {
4960
4961 public Next from( String name );
4962
4963 public Next from( Name name );
4964
4965 }
4966
4967 /**
4968 * A component that defines the location to which a node should be copied or moved.
4969 *
4970 * @param <Next> The interface that is to be returned when this request is completed
4971 */
4972 public interface To<Next> {
4973 /**
4974 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
4975 * {@link Into#into(Location)}, which specifies the location of the parent and which assumes the new node should have the
4976 * same name as the original, this method allows the caller to specify a new name for the new node.
4977 *
4978 * @param desiredLocation the desired location for the new node, which must have a {@link Location#getPath() path}
4979 * @return the interface for additional requests or actions
4980 * @see Into#into(Location)
4981 */
4982 Next to( Location desiredLocation );
4983
4984 /**
4985 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
4986 * {@link Into#into(String)}, which specifies the location of the parent and which assumes the new node should have the
4987 * same name as the original, this method allows the caller to specify a new name for the new node.
4988 *
4989 * @param desiredPath the path for the new node
4990 * @return the interface for additional requests or actions
4991 * @see Into#into(String)
4992 */
4993 Next to( String desiredPath );
4994
4995 /**
4996 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
4997 * {@link Into#into(Path)} , which specifies the location of the parent and which assumes the new node should have the
4998 * same name as the original, this method allows the caller to specify a new name for the new node.
4999 *
5000 * @param desiredPath the path for the new node
5001 * @return the interface for additional requests or actions
5002 * @see Into#into(Path)
5003 */
5004 Next to( Path desiredPath );
5005 }
5006
5007 /**
5008 * A component that defines a new child name for a node.
5009 *
5010 * @param <Next> The interface that is to be returned when this request is completed
5011 */
5012 public interface AsChild<Next> {
5013 /**
5014 * Finish the request by specifying the exact segment for the new child node. If no segment already exists, this request
5015 * should fail.
5016 *
5017 * @param newSegment the new name
5018 * @return the interface for additional requests or actions
5019 */
5020 Next as( Path.Segment newSegment );
5021
5022 /**
5023 * Finish the request by specifying the name of the new child node. This method indicates that the child should be added
5024 * as a new node with the given name at the end of the parents children
5025 *
5026 * @param newName the new name
5027 * @return the interface for additional requests or actions
5028 */
5029 Next as( Name newName );
5030
5031 /**
5032 * Finish the request by specifying the name of the new child node. This method indicates that the child should be added
5033 * as a new node with the given name at the end of the parents children
5034 *
5035 * @param newName the new name
5036 * @return the interface for additional requests or actions
5037 */
5038 Next as( String newName );
5039 }
5040
5041 /**
5042 * A component that defines a new name for a node.
5043 *
5044 * @param <Next> The interface that is to be returned when this request is completed
5045 */
5046 public interface AsName<Next> {
5047 /**
5048 * Finish the request by specifying the new name.
5049 *
5050 * @param newName the new name
5051 * @return the interface for additional requests or actions
5052 */
5053 Next as( String newName );
5054
5055 /**
5056 * Finish the request by specifying the new name.
5057 *
5058 * @param newName the new name
5059 * @return the interface for additional requests or actions
5060 */
5061 Next as( Name newName );
5062 }
5063
5064 /**
5065 * A interface that is used to add more locations that are to be copied/moved.
5066 *
5067 * @param <Next> The interface that is to be returned when this request is completed
5068 */
5069 public interface And<Next> {
5070 /**
5071 * Specify that another node should also be copied or moved.
5072 *
5073 * @param from the location of the node to be copied or moved
5074 * @return the interface for finishing the request
5075 */
5076 Next and( Location from );
5077
5078 /**
5079 * Specify that another node should also be copied or moved.
5080 *
5081 * @param fromPath the path of the node to be copied or moved
5082 * @return the interface for finishing the request
5083 */
5084 Next and( String fromPath );
5085
5086 /**
5087 * Specify that another node should also be copied or moved.
5088 *
5089 * @param from the path of the node to be copied or moved
5090 * @return the interface for finishing the request
5091 */
5092 Next and( Path from );
5093
5094 /**
5095 * Specify that another node should also be copied or moved.
5096 *
5097 * @param from the UUID of the node to be copied or moved
5098 * @return the interface for finishing the request
5099 */
5100 Next and( UUID from );
5101
5102 /**
5103 * Specify that another node should also be copied or moved.
5104 *
5105 * @param idProperty the property that uniquely identifies the node to be copied or moved
5106 * @return the interface for finishing the request
5107 */
5108 Next and( Property idProperty );
5109
5110 /**
5111 * Specify that another node should also be copied or moved.
5112 *
5113 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5114 * node to be copied or moved
5115 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5116 * identifies the node to be copied or moved
5117 * @return the interface for finishing the request
5118 */
5119 Next and( Property firstIdProperty,
5120 Property... additionalIdProperties );
5121
5122 /**
5123 * Specify that another node should also be copied or moved.
5124 *
5125 * @param idProperties the properties that uniquely identifies the node to be copied or moved
5126 * @return the interface for finishing the request
5127 */
5128 Next and( Iterable<Property> idProperties );
5129 }
5130
5131 /**
5132 * The interface for defining additional nodes to be moved and the parent into which the node(s) are to be moved.
5133 *
5134 * @param <Next> The interface that is to be returned when this request is completed
5135 */
5136 public interface Move<Next> extends AsName<Into<Next>>, Into<Next>, Before<Next>, And<Move<Next>> {
5137 }
5138
5139 /**
5140 * The interface for defining additional nodes to be copied and the locations where the copy is to be placed. The
5141 * <code>to(...)</code> methods allow you to specify the location of the copy, including the name for the node that results
5142 * from the copy. Alternatively, you can use the <code>into(...)</code> methods to specify the parent location where the copy
5143 * is to be placed, which will assume the new copy will have the same name as the original.
5144 *
5145 * @param <Next> The interface that is to be returned when this request is completed
5146 */
5147 public interface Copy<Next> extends FromWorkspace<CopyTarget<Next>>, CopyTarget<Next>, And<Copy<Next>> {
5148 }
5149
5150 public interface CopyTarget<Next> extends To<Next>, Into<Next> {
5151 }
5152
5153 /**
5154 * The interface for defining a branch of nodes to be cloned and the location where the clone is to be placed. Cloning a
5155 * branch differs from copying a branch in that:
5156 * <ol>
5157 * <li>Nodes can be copied within the same workspace or to another workspace; cloned nodes must be copied from one workspace
5158 * into another.</li>
5159 * <li>Copied nodes always get new UUIDs; cloned nodes always maintain their UUIDs and hence must define the behavior that
5160 * occurs if a node with the same UUID already exists in the new workspace.</li>
5161 * <li>Nodes can be copied to a specific name under a specific parent, but can only be added as a new child node at the end of
5162 * the new parent's children; nodes can be cloned to an exact location among the parent's children, replacing the existing
5163 * node at that location.</li>
5164 * </ol>
5165 *
5166 * @param <Next>
5167 */
5168 public interface Clone<Next> extends FromWorkspace<AsChild<Into<WithUuids<Next>>>> {
5169
5170 }
5171
5172 /**
5173 * The interface for specifying that a node should come from a workspace other than the current workspace.
5174 *
5175 * @param <Next> The interface that is to be returned when this request is completed
5176 */
5177 public interface FromWorkspace<Next> {
5178 Next fromWorkspace( String workspaceName );
5179 }
5180
5181 /**
5182 * The interface for specifying how UUID conflicts should be handled.
5183 *
5184 * @param <Next> The interface that is to be returned when this request is completed
5185 */
5186 public interface WithUuids<Next> {
5187 Next failingIfAnyUuidsMatch();
5188
5189 Next replacingExistingNodesWithSameUuids();
5190 }
5191
5192 /**
5193 * Interface for specifying whether a lock should be deep in scope
5194 *
5195 * @param <Next> The interface that is to be returned when this create request is completed
5196 */
5197 public interface LockScope<Next> {
5198 Next andItsDescendants();
5199
5200 Next only();
5201 }
5202
5203 /**
5204 * Interface for specifying whether the maximum length of the lock
5205 *
5206 * @param <Next> The interface that is to be returned when this create request is completed
5207 */
5208 public interface LockTimeout<Next> {
5209 Next withDefaultTimeout();
5210
5211 Next withTimeoutOf( long milliseconds );
5212 }
5213
5214 @NotThreadSafe
5215 protected abstract class LockAction<T> extends AbstractAction<T> implements LockScope<LockTimeout<T>> {
5216 private final Location target;
5217
5218 /*package*/LockAction( T afterConjunction,
5219 Location target ) {
5220 super(afterConjunction);
5221 this.target = target;
5222 }
5223
5224 protected abstract T submit( Location lock,
5225 org.modeshape.graph.request.LockBranchRequest.LockScope lockScope,
5226 long lockTimeoutInMillis );
5227
5228 @SuppressWarnings( "synthetic-access" )
5229 public LockTimeout<T> andItsDescendants() {
5230 return new LockTimeout<T>() {
5231
5232 public T withDefaultTimeout() {
5233 return submit(target, org.modeshape.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS, 0);
5234 }
5235
5236 public T withTimeoutOf( long milliseconds ) {
5237 return submit(target,
5238 org.modeshape.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS,
5239 milliseconds);
5240 }
5241
5242 };
5243 }
5244
5245 @SuppressWarnings( "synthetic-access" )
5246 public LockTimeout<T> only() {
5247 return new LockTimeout<T>() {
5248
5249 public T withDefaultTimeout() {
5250 return submit(target, org.modeshape.graph.request.LockBranchRequest.LockScope.SELF_ONLY, 0);
5251 }
5252
5253 public T withTimeoutOf( long milliseconds ) {
5254 return submit(target, org.modeshape.graph.request.LockBranchRequest.LockScope.SELF_ONLY, milliseconds);
5255 }
5256
5257 };
5258 }
5259
5260 }
5261
5262 /**
5263 * The interface for defining additional properties on a new node.
5264 *
5265 * @param <Next> The interface that is to be returned when this create request is completed
5266 */
5267 public interface Create<Next> extends Conjunction<Next> {
5268 /**
5269 * Create the node only if there is no existing node with the same {@link Path.Segment#getName() name} (ignoring
5270 * {@link Path.Segment#getIndex() same-name-sibling indexes}).
5271 *
5272 * @return this interface for continued specification of the request
5273 */
5274 Create<Next> ifAbsent();
5275
5276 /**
5277 * Create the node if it does not exist, or update any existing node that has the same {@link Path.Segment#getName() name}
5278 * (ignoring {@link Path.Segment#getIndex() same-name-sibling indexes}).
5279 *
5280 * @return this interface for continued specification of the request
5281 */
5282 Create<Next> orUpdate();
5283
5284 /**
5285 * Create the node if it does not exist, or replace any existing node that has the same {@link Path.Segment#getName()
5286 * name} (ignoring {@link Path.Segment#getIndex() same-name-sibling indexes}).
5287 *
5288 * @return this interface for continued specification of the request
5289 */
5290 Create<Next> orReplace();
5291
5292 /**
5293 * Create the node if it does not exist by appending or adjusting the {@link Path.Segment#getIndex() same-name-sibling
5294 * index}). This is the default behavior.
5295 *
5296 * @return this interface for continued specification of the request
5297 */
5298 Create<Next> byAppending();
5299
5300 /**
5301 * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
5302 *
5303 * @param uuid the UUID
5304 * @return this same interface so additional properties may be added
5305 */
5306 Create<Next> with( UUID uuid );
5307
5308 /**
5309 * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
5310 *
5311 * @param property the property
5312 * @return this same interface so additional properties may be added
5313 */
5314 Create<Next> with( Property property );
5315
5316 /**
5317 * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
5318 *
5319 * @param properties the properties that should be added
5320 * @return this same interface so additional properties may be added
5321 */
5322 Create<Next> with( Iterable<Property> properties );
5323
5324 /**
5325 * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
5326 *
5327 * @param propertyName the name of the property
5328 * @param values the property values
5329 * @return this same interface so additional properties may be added
5330 */
5331 Create<Next> with( String propertyName,
5332 Object... values );
5333
5334 /**
5335 * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
5336 *
5337 * @param propertyName the name of the property
5338 * @param values the property values
5339 * @return this same interface so additional properties may be added
5340 */
5341 Create<Next> with( Name propertyName,
5342 Object... values );
5343
5344 /**
5345 * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
5346 *
5347 * @param firstProperty the first property
5348 * @param additionalProperties the additional property
5349 * @return this same interface so additional properties may be added
5350 */
5351 Create<Next> with( Property firstProperty,
5352 Property... additionalProperties );
5353
5354 /**
5355 * Specify the UUID that should the new node should have.
5356 *
5357 * @param uuid the UUID
5358 * @return this same interface so additional properties may be added
5359 */
5360 Create<Next> and( UUID uuid );
5361
5362 /**
5363 * Specify a property that should the new node should have.
5364 *
5365 * @param property the property
5366 * @return this same interface so additional properties may be added
5367 */
5368 Create<Next> and( Property property );
5369
5370 /**
5371 * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
5372 * the properties in the supplied {@link Iterable}.
5373 *
5374 * @param properties the properties that should be added
5375 * @return this same interface so additional properties may be added
5376 */
5377 Create<Next> and( Iterable<Property> properties );
5378
5379 /**
5380 * Specify a property that should the new node should have.
5381 *
5382 * @param propertyName the name of the property
5383 * @param values the property values
5384 * @return this same interface so additional properties may be added
5385 */
5386 Create<Next> and( String propertyName,
5387 Object... values );
5388
5389 /**
5390 * Specify a property that should the new node should have.
5391 *
5392 * @param propertyName the name of the property
5393 * @param values the property values
5394 * @return this same interface so additional properties may be added
5395 */
5396 Create<Next> and( Name propertyName,
5397 Object... values );
5398
5399 /**
5400 * Specify properties that should the new node should have.
5401 *
5402 * @param firstProperty the first property
5403 * @param additionalProperties the additional property
5404 * @return this same interface so additional properties may be added
5405 */
5406 Create<Next> and( Property firstProperty,
5407 Property... additionalProperties );
5408 }
5409
5410 /**
5411 * The interface for defining additional properties on a new node.
5412 *
5413 * @param <Next> The interface that is to be returned when this create request is completed
5414 */
5415 public interface CreateAt<Next> extends Conjunction<Next> {
5416 /**
5417 * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
5418 *
5419 * @param uuid the UUID
5420 * @return this same interface so additional properties may be added
5421 */
5422 CreateAt<Next> with( UUID uuid );
5423
5424 /**
5425 * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
5426 *
5427 * @param property the property
5428 * @return this same interface so additional properties may be added
5429 */
5430 CreateAt<Next> with( Property property );
5431
5432 /**
5433 * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
5434 *
5435 * @param properties the properties that should be added
5436 * @return this same interface so additional properties may be added
5437 */
5438 CreateAt<Next> with( Iterable<Property> properties );
5439
5440 /**
5441 * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
5442 *
5443 * @param propertyName the name of the property
5444 * @param values the property values
5445 * @return this same interface so additional properties may be added
5446 */
5447 CreateAt<Next> with( String propertyName,
5448 Object... values );
5449
5450 /**
5451 * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
5452 *
5453 * @param propertyName the name of the property
5454 * @param values the property values
5455 * @return this same interface so additional properties may be added
5456 */
5457 CreateAt<Next> with( Name propertyName,
5458 Object... values );
5459
5460 /**
5461 * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
5462 *
5463 * @param firstProperty the first property
5464 * @param additionalProperties the additional property
5465 * @return this same interface so additional properties may be added
5466 */
5467 CreateAt<Next> with( Property firstProperty,
5468 Property... additionalProperties );
5469
5470 /**
5471 * Specify the UUID that should the new node should have.
5472 *
5473 * @param uuid the UUID
5474 * @return this same interface so additional properties may be added
5475 */
5476 CreateAt<Next> and( UUID uuid );
5477
5478 /**
5479 * Specify a property that should the new node should have.
5480 *
5481 * @param property the property
5482 * @return this same interface so additional properties may be added
5483 */
5484 CreateAt<Next> and( Property property );
5485
5486 /**
5487 * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
5488 * the properties in the supplied {@link Iterable}.
5489 *
5490 * @param properties the properties that should be added
5491 * @return this same interface so additional properties may be added
5492 */
5493 CreateAt<Next> and( Iterable<Property> properties );
5494
5495 /**
5496 * Specify a property that should the new node should have.
5497 *
5498 * @param propertyName the name of the property
5499 * @param values the property values
5500 * @return this same interface so additional properties may be added
5501 */
5502 CreateAt<Next> and( String propertyName,
5503 Object... values );
5504
5505 /**
5506 * Specify a property that should the new node should have.
5507 *
5508 * @param propertyName the name of the property
5509 * @param values the property values
5510 * @return this same interface so additional properties may be added
5511 */
5512 CreateAt<Next> and( Name propertyName,
5513 Object... values );
5514
5515 /**
5516 * Specify properties that should the new node should have.
5517 *
5518 * @param firstProperty the first property
5519 * @param additionalProperties the additional property
5520 * @return this same interface so additional properties may be added
5521 */
5522 CreateAt<Next> and( Property firstProperty,
5523 Property... additionalProperties );
5524
5525 /**
5526 * Complete this request, submit it, and return the actual location of the created node.
5527 *
5528 * @return the actual location of the just-created node; never null
5529 */
5530 Location getLocation();
5531
5532 /**
5533 * Complete this request, submit it, and return the actual node that was created.
5534 *
5535 * @return the actual node that was just created; never null
5536 */
5537 Node getNode();
5538 }
5539
5540 /**
5541 * The interface for defining the node upon which a request operates.
5542 *
5543 * @param <Next> The interface that is to be returned when the request is completed
5544 */
5545 public interface On<Next> {
5546 /**
5547 * Specify the location of the node upon which the request is to operate.
5548 *
5549 * @param to the location of the new parent
5550 * @return the interface for additional requests or actions
5551 */
5552 Next on( Location to );
5553
5554 /**
5555 * Specify the path of the node upon which the request is to operate.
5556 *
5557 * @param toPath the path of the new parent
5558 * @return the interface for additional requests or actions
5559 */
5560 Next on( String toPath );
5561
5562 /**
5563 * Specify the path of the node upon which the request is to operate.
5564 *
5565 * @param to the path of the new parent
5566 * @return the interface for additional requests or actions
5567 */
5568 Next on( Path to );
5569
5570 /**
5571 * Specify the UUID of the node upon which the request is to operate.
5572 *
5573 * @param to the UUID of the new parent
5574 * @return the interface for additional requests or actions
5575 */
5576 Next on( UUID to );
5577
5578 /**
5579 * Specify the unique identification property that identifies the node upon which the request is to operate.
5580 *
5581 * @param idProperty the property that uniquely identifies the new parent
5582 * @return the interface for additional requests or actions
5583 */
5584 Next on( Property idProperty );
5585
5586 /**
5587 * Specify the unique identification properties that identify the node upon which the request is to operate.
5588 *
5589 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5590 * new parent
5591 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5592 * identifies the new parent
5593 * @return the interface for additional requests or actions
5594 */
5595 Next on( Property firstIdProperty,
5596 Property... additionalIdProperties );
5597
5598 /**
5599 * Specify the unique identification properties that identify the node upon which the request is to operate.
5600 *
5601 * @param idProperties the properties that uniquely identifies the new parent
5602 * @return the interface for additional requests or actions
5603 */
5604 Next on( Iterable<Property> idProperties );
5605 }
5606
5607 /**
5608 * The interface for defining the node upon which a request operates, including a method that accepts multiple locations.
5609 *
5610 * @param <Next> The interface that is to be returned when the request is completed
5611 */
5612 public interface OnMultiple<Next> extends On<Next> {
5613 /**
5614 * Specify the location of each node upon which the requests are to operate.
5615 *
5616 * @param to the locations
5617 * @return the interface for additional requests or actions
5618 */
5619 Map<Location, Next> on( Collection<Location> to );
5620
5621 /**
5622 * Specify the location of each node upon which the requests are to operate.
5623 *
5624 * @param firstTo the first location
5625 * @param additional the additional location
5626 * @return the interface for additional requests or actions
5627 */
5628 Map<Location, Next> on( Location firstTo,
5629 Location... additional );
5630
5631 /**
5632 * Specify the path of each node upon which the requests are to operate.
5633 *
5634 * @param firstPath the first path
5635 * @param additional the additional path
5636 * @return the interface for additional requests or actions
5637 */
5638 Map<Location, Next> on( String firstPath,
5639 String... additional );
5640
5641 /**
5642 * Specify the path of each node upon which the requests are to operate.
5643 *
5644 * @param firstPath the first path
5645 * @param additional the additional path
5646 * @return the interface for additional requests or actions
5647 */
5648 Map<Location, Next> on( Path firstPath,
5649 Path... additional );
5650
5651 /**
5652 * Specify the UUID of each node upon which the requests are to operate.
5653 *
5654 * @param firstPath the first UUID of the node
5655 * @param additional the additional UUIDs
5656 * @return the interface for additional requests or actions
5657 */
5658 Map<Location, Next> on( UUID firstPath,
5659 UUID... additional );
5660 }
5661
5662 /**
5663 * The interface for defining the node upon which a request operates.
5664 *
5665 * @param <Next> The interface that is to be returned when the request is completed
5666 */
5667 public interface Of<Next> {
5668 /**
5669 * Specify the location of the node upon which the request is to operate.
5670 *
5671 * @param to the location of the new parent
5672 * @return the interface for additional requests or actions
5673 */
5674 Next of( Location to );
5675
5676 /**
5677 * Specify the path of the node upon which the request is to operate.
5678 *
5679 * @param toPath the path of the new parent
5680 * @return the interface for additional requests or actions
5681 */
5682 Next of( String toPath );
5683
5684 /**
5685 * Specify the path of the node upon which the request is to operate.
5686 *
5687 * @param to the path of the new parent
5688 * @return the interface for additional requests or actions
5689 */
5690 Next of( Path to );
5691
5692 /**
5693 * Specify the UUID of the node upon which the request is to operate.
5694 *
5695 * @param to the UUID of the new parent
5696 * @return the interface for additional requests or actions
5697 */
5698 Next of( UUID to );
5699
5700 /**
5701 * Specify the unique identification property that identifies the node upon which the request is to operate.
5702 *
5703 * @param idProperty the property that uniquely identifies the new parent
5704 * @return the interface for additional requests or actions
5705 */
5706 Next of( Property idProperty );
5707
5708 /**
5709 * Specify the unique identification properties that identify the node upon which the request is to operate.
5710 *
5711 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5712 * new parent
5713 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5714 * identifies the new parent
5715 * @return the interface for additional requests or actions
5716 */
5717 Next of( Property firstIdProperty,
5718 Property... additionalIdProperties );
5719
5720 /**
5721 * Specify the unique identification properties that identify the node upon which the request is to operate.
5722 *
5723 * @param idProperties the properties that uniquely identifies the new parent
5724 * @return the interface for additional requests or actions
5725 */
5726 Next of( Iterable<Property> idProperties );
5727 }
5728
5729 /**
5730 * The interface for defining the node upon which which a request operates.
5731 *
5732 * @param <Next> The interface that is to be returned when the request is completed
5733 */
5734 public interface At<Next> {
5735 /**
5736 * Specify the location of the node upon which the request is to operate.
5737 *
5738 * @param to the location of the new parent
5739 * @return the interface for additional requests or actions
5740 */
5741 Next at( Location to );
5742
5743 /**
5744 * Specify the path of the node upon which the request is to operate.
5745 *
5746 * @param toPath the path of the new parent
5747 * @return the interface for additional requests or actions
5748 */
5749 Next at( String toPath );
5750
5751 /**
5752 * Specify the path of the node upon which the request is to operate.
5753 *
5754 * @param to the path of the new parent
5755 * @return the interface for additional requests or actions
5756 */
5757 Next at( Path to );
5758
5759 /**
5760 * Specify the UUID of the node upon which the request is to operate.
5761 *
5762 * @param to the UUID of the new parent
5763 * @return the interface for additional requests or actions
5764 */
5765 Next at( UUID to );
5766
5767 /**
5768 * Specify the unique identification property that identifies the node upon which the request is to operate.
5769 *
5770 * @param idProperty the property that uniquely identifies the new parent
5771 * @return the interface for additional requests or actions
5772 */
5773 Next at( Property idProperty );
5774
5775 /**
5776 * Specify the unique identification properties that identify the node upon which the request is to operate.
5777 *
5778 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5779 * new parent
5780 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5781 * identifies the new parent
5782 * @return the interface for additional requests or actions
5783 */
5784 Next at( Property firstIdProperty,
5785 Property... additionalIdProperties );
5786
5787 /**
5788 * Specify the unique identification properties that identify the node upon which the request is to operate.
5789 *
5790 * @param idProperties the properties that uniquely identifies the new parent
5791 * @return the interface for additional requests or actions
5792 */
5793 Next at( Iterable<Property> idProperties );
5794 }
5795
5796 /**
5797 * A component used to supply the details for getting children of another node. If all of the children are to be obtained,
5798 * then the parent can be specified using one of the <code>of(...)</code> methods on this component. If, however, only some of
5799 * the nodes are to be returned (e.g., a "block" of children), then specify the {@link #inBlockOf(int) block size} followed by
5800 * the {@link BlockOfChildren block size and parent}.
5801 *
5802 * @param <Next>
5803 */
5804 public interface Children<Next> extends Of<Next> {
5805 /**
5806 * Specify that a block of children are to be retreived, and in particular the number of children that are to be returned.
5807 *
5808 * @param blockSize the number of children that are to be retrieved in the block; must be positive
5809 * @return the interface used to specify the starting point for the block and the parent
5810 */
5811 BlockOfChildren<Next> inBlockOf( int blockSize );
5812 }
5813
5814 /**
5815 * A component used to specify a block of children starting either {@link #startingAt(int) at a particular index} or
5816 * {@link #startingAfter(Location) after a previous sibling}.
5817 *
5818 * @param <Next>
5819 */
5820 public interface BlockOfChildren<Next> {
5821 /**
5822 * Specify the block of children is to start at the supplied index.
5823 *
5824 * @param startingIndex the zero-based index of the first child to be returned in the block
5825 * @return interface used to specify the parent of the children; never null
5826 */
5827 Under<Next> startingAt( int startingIndex );
5828
5829 /**
5830 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5831 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5832 * block.
5833 *
5834 * @param previousSibling the location of the sibling node that is before the first node in the block
5835 * @return the children; never null
5836 */
5837 Next startingAfter( Location previousSibling );
5838
5839 /**
5840 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5841 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5842 * block.
5843 *
5844 * @param pathToPreviousSiblingName the path of the sibling node that is before the first node in the block
5845 * @return the children; never null
5846 */
5847 Next startingAfter( String pathToPreviousSiblingName );
5848
5849 /**
5850 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5851 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5852 * block.
5853 *
5854 * @param previousSibling the path of the sibling node that is before the first node in the block
5855 * @return the children; never null
5856 */
5857 Next startingAfter( Path previousSibling );
5858
5859 /**
5860 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5861 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5862 * block.
5863 *
5864 * @param previousSiblingUuid the UUID of the sibling node that is before the first node in the block
5865 * @return the children; never null
5866 */
5867 Next startingAfter( UUID previousSiblingUuid );
5868
5869 /**
5870 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5871 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5872 * block.
5873 *
5874 * @param idPropertyOfPreviousSibling the property that uniquely identifies the previous sibling
5875 * @return the children; never null
5876 */
5877 Next startingAfter( Property idPropertyOfPreviousSibling );
5878
5879 /**
5880 * Specify the block of children is to start with the child immediately following the supplied node. This method is
5881 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
5882 * block.
5883 *
5884 * @param firstIdPropertyOfPreviousSibling the first property that, with the <code>additionalIdProperties</code>, uniquely
5885 * identifies the previous sibling
5886 * @param additionalIdPropertiesOfPreviousSibling the additional properties that, with the
5887 * <code>additionalIdProperties</code>, uniquely identifies the previous sibling
5888 * @return the children; never null
5889 */
5890 Next startingAfter( Property firstIdPropertyOfPreviousSibling,
5891 Property... additionalIdPropertiesOfPreviousSibling );
5892 }
5893
5894 /**
5895 * The interface for defining the node under which which a request operates.
5896 *
5897 * @param <Next> The interface that is to be returned when the request is completed
5898 */
5899 public interface Under<Next> {
5900 /**
5901 * Specify the location of the node under which the request is to operate.
5902 *
5903 * @param to the location of the new parent
5904 * @return the interface for additional requests or actions
5905 */
5906 Next under( Location to );
5907
5908 /**
5909 * Specify the path of the node under which the request is to operate.
5910 *
5911 * @param toPath the path of the new parent
5912 * @return the interface for additional requests or actions
5913 */
5914 Next under( String toPath );
5915
5916 /**
5917 * Specify the path of the node under which the request is to operate.
5918 *
5919 * @param to the path of the new parent
5920 * @return the interface for additional requests or actions
5921 */
5922 Next under( Path to );
5923
5924 /**
5925 * Specify the UUID of the node under which the request is to operate.
5926 *
5927 * @param to the UUID of the new parent
5928 * @return the interface for additional requests or actions
5929 */
5930 Next under( UUID to );
5931
5932 /**
5933 * Specify the unique identification property that identifies the node under which the request is to operate.
5934 *
5935 * @param idProperty the property that uniquely identifies the new parent
5936 * @return the interface for additional requests or actions
5937 */
5938 Next under( Property idProperty );
5939
5940 /**
5941 * Specify the unique identification properties that identify the node under which the request is to operate.
5942 *
5943 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5944 * new parent
5945 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5946 * identifies the new parent
5947 * @return the interface for additional requests or actions
5948 */
5949 Next under( Property firstIdProperty,
5950 Property... additionalIdProperties );
5951 }
5952
5953 /**
5954 * The interface for defining the node on which an {@link Graph#addValue(Object)} operation applies and what additional values
5955 * (if any) should be added.
5956 *
5957 * @param <Next> The interface that is to be returned when the request is completed
5958 */
5959 public interface AddValue<Next> extends ToName<On<Next>> {
5960 /**
5961 * Specifies an additional value to be added
5962 *
5963 * @param value the value to be added
5964 * @return an object that allows additional values to be specified for removal or for their location to be specified
5965 */
5966 AddValue<Next> andValue( Object value );
5967
5968 }
5969
5970 /**
5971 * The interface for defining the node on which an {@link Graph#removeValue(Object)} operation applies and what additional
5972 * values (if any) should be removed.
5973 *
5974 * @param <Next> The interface that is to be returned when the request is completed
5975 */
5976 public interface RemoveValue<Next> extends FromName<On<Next>> {
5977
5978 /**
5979 * Specifies an additional value to be removed
5980 *
5981 * @param value the value to be removed
5982 * @return an object that allows additional values to be specified for removal or for their location to be specified
5983 */
5984 RemoveValue<Next> andValue( Object value );
5985
5986 }
5987
5988 public abstract class AddValueAction<T> extends AbstractAction<T> implements AddValue<T> {
5989
5990 protected final String workspaceName;
5991 protected final List<Object> values = new LinkedList<Object>();
5992
5993 protected AddValueAction( T afterConjunction,
5994 String workspaceName,
5995 Object firstValue ) {
5996 super(afterConjunction);
5997
5998 this.workspaceName = workspaceName;
5999 this.values.add(firstValue);
6000 }
6001
6002 public AddValue<T> andValue( Object nextValue ) {
6003 this.values.add(nextValue);
6004 return this;
6005 }
6006
6007 public On<T> to( String name ) {
6008 return to(createName(name));
6009 }
6010
6011 public On<T> to( final Name name ) {
6012 return new On<T>() {
6013
6014 public T on( Iterable<Property> idProperties ) {
6015 return on(Location.create(idProperties));
6016 }
6017
6018 public T on( Location to ) {
6019 return submit(workspaceName, to, name, values);
6020 }
6021
6022 public T on( Path to ) {
6023 return on(Location.create(to));
6024 }
6025
6026 public T on( Property firstIdProperty,
6027 Property... additionalIdProperties ) {
6028 return on(Location.create(firstIdProperty, additionalIdProperties));
6029 }
6030
6031 public T on( Property idProperty ) {
6032 return on(Location.create(idProperty));
6033 }
6034
6035 public T on( String toPath ) {
6036 return on(Location.create(createPath(toPath)));
6037 }
6038
6039 public T on( UUID to ) {
6040 return on(Location.create(to));
6041 }
6042 };
6043 }
6044
6045 protected abstract T submit( String workspaceName,
6046 Location on,
6047 Name property,
6048 List<Object> values );
6049
6050 }
6051
6052 public abstract class RemoveValueAction<T> extends AbstractAction<T> implements RemoveValue<T> {
6053
6054 protected final String workspaceName;
6055 protected final List<Object> values = new LinkedList<Object>();
6056
6057 protected RemoveValueAction( T afterConjunction,
6058 String workspaceName,
6059 Object firstValue ) {
6060 super(afterConjunction);
6061
6062 this.workspaceName = workspaceName;
6063 this.values.add(firstValue);
6064 }
6065
6066 public RemoveValue<T> andValue( Object nextValue ) {
6067 this.values.add(nextValue);
6068 return this;
6069 }
6070
6071 public On<T> from( String name ) {
6072 return from(createName(name));
6073 }
6074
6075 public On<T> from( final Name name ) {
6076 return new On<T>() {
6077
6078 public T on( Iterable<Property> idProperties ) {
6079 return on(Location.create(idProperties));
6080 }
6081
6082 public T on( Location to ) {
6083 return submit(workspaceName, to, name, values);
6084 }
6085
6086 public T on( Path to ) {
6087 return on(Location.create(to));
6088 }
6089
6090 public T on( Property firstIdProperty,
6091 Property... additionalIdProperties ) {
6092 return on(Location.create(firstIdProperty, additionalIdProperties));
6093 }
6094
6095 public T on( Property idProperty ) {
6096 return on(Location.create(idProperty));
6097 }
6098
6099 public T on( String toPath ) {
6100 return on(Location.create(createPath(toPath)));
6101 }
6102
6103 public T on( UUID to ) {
6104 return on(Location.create(to));
6105 }
6106 };
6107 }
6108
6109 protected abstract T submit( String workspaceName,
6110 Location on,
6111 Name property,
6112 List<Object> values );
6113
6114 }
6115
6116 /**
6117 * A component used to set the values on a property.
6118 *
6119 * @param <Next> the next command
6120 */
6121 public interface SetValues<Next> extends On<SetValuesTo<Next>>, SetValuesTo<On<Next>> {
6122 }
6123
6124 /**
6125 * A component used to set the values on a property.
6126 *
6127 * @param <Next>
6128 */
6129 public interface SetValuesTo<Next> {
6130
6131 /**
6132 * Set the property value to be a reference to the given node. Note that it is an error if the Node does not have a
6133 * {@link Location#getUuid() UUID}.
6134 *
6135 * @param node the node to which a reference should be set
6136 * @return the interface for additional requests or actions
6137 * @throws IllegalArgumentException if the value is a Node that has no {@link Location#getUuid() UUID}
6138 */
6139 Next to( Node node );
6140
6141 /**
6142 * Set the property value to be a reference to the given location. Note that it is an error if the Location does not have
6143 * a {@link Location#getUuid() UUID}.
6144 *
6145 * @param location the location to which a reference should be set
6146 * @return the interface for additional requests or actions
6147 * @throws IllegalArgumentException if the value is a Location that has no {@link Location#getUuid() UUID}
6148 */
6149 Next to( Location location );
6150
6151 /**
6152 * Set the property value to the given string.
6153 *
6154 * @param value the property value
6155 * @return the interface for additional requests or actions
6156 */
6157 Next to( String value );
6158
6159 /**
6160 * Set the property value to the given integer value.
6161 *
6162 * @param value the property value
6163 * @return the interface for additional requests or actions
6164 */
6165 Next to( int value );
6166
6167 /**
6168 * Set the property value to the given long value.
6169 *
6170 * @param value the property value
6171 * @return the interface for additional requests or actions
6172 */
6173 Next to( long value );
6174
6175 /**
6176 * Set the property value to the given boolean value.
6177 *
6178 * @param value the property value
6179 * @return the interface for additional requests or actions
6180 */
6181 Next to( boolean value );
6182
6183 /**
6184 * Set the property value to the given float value.
6185 *
6186 * @param value the property value
6187 * @return the interface for additional requests or actions
6188 */
6189 Next to( float value );
6190
6191 /**
6192 * Set the property value to the given double value.
6193 *
6194 * @param value the property value
6195 * @return the interface for additional requests or actions
6196 */
6197 Next to( double value );
6198
6199 /**
6200 * Set the property value to the given decimal value.
6201 *
6202 * @param value the property value
6203 * @return the interface for additional requests or actions
6204 */
6205 Next to( BigDecimal value );
6206
6207 /**
6208 * Set the property value to the date given by the supplied calendar.
6209 *
6210 * @param value the property value
6211 * @return the interface for additional requests or actions
6212 */
6213 Next to( Calendar value );
6214
6215 /**
6216 * Set the property value to the given date.
6217 *
6218 * @param value the property value
6219 * @return the interface for additional requests or actions
6220 */
6221 Next to( Date value );
6222
6223 /**
6224 * Set the property value to the given date-time instant.
6225 *
6226 * @param value the property value
6227 * @return the interface for additional requests or actions
6228 */
6229 Next to( DateTime value );
6230
6231 /**
6232 * Set the property value to the given Name.
6233 *
6234 * @param value the property value
6235 * @return the interface for additional requests or actions
6236 */
6237 Next to( Name value );
6238
6239 /**
6240 * Set the property value to the given Path.
6241 *
6242 * @param value the property value
6243 * @return the interface for additional requests or actions
6244 */
6245 Next to( Path value );
6246
6247 /**
6248 * Set the property value to the given Reference. See also {@link #to(Node)}.
6249 *
6250 * @param value the property value
6251 * @return the interface for additional requests or actions
6252 */
6253 Next to( Reference value );
6254
6255 /**
6256 * Set the property value to the given URI.
6257 *
6258 * @param value the property value
6259 * @return the interface for additional requests or actions
6260 */
6261 Next to( URI value );
6262
6263 /**
6264 * Set the property value to the given UUID.
6265 *
6266 * @param value the property value
6267 * @return the interface for additional requests or actions
6268 */
6269 Next to( UUID value );
6270
6271 /**
6272 * Set the property value to the given binary value.
6273 *
6274 * @param value the property value
6275 * @return the interface for additional requests or actions
6276 */
6277 Next to( Binary value );
6278
6279 /**
6280 * Set the property value to the given byte array.
6281 *
6282 * @param value the property value
6283 * @return the interface for additional requests or actions
6284 */
6285 Next to( byte[] value );
6286
6287 /**
6288 * Set the property value to the given string.
6289 *
6290 * @param stream the stream containing the content to be used for the property value
6291 * @param approximateLength the approximate length of the content (in bytes)
6292 * @return the interface for additional requests or actions
6293 */
6294 Next to( InputStream stream,
6295 long approximateLength );
6296
6297 /**
6298 * Set the property value to the given string.
6299 *
6300 * @param reader the reader containing the content to be used for the property value
6301 * @param approximateLength the approximate length of the content (in bytes)
6302 * @return the interface for additional requests or actions
6303 */
6304 Next to( Reader reader,
6305 long approximateLength );
6306
6307 /**
6308 * Set the property value to the given object. The supplied <code>value</code> should be a valid property value, or a
6309 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
6310 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
6311 *
6312 * @param value the property value
6313 * @return the interface for additional requests or actions
6314 * @throws IllegalArgumentException if the value is a Node or Location that has no {@link Location#getUuid() UUID}
6315 */
6316 Next to( Object value );
6317
6318 /**
6319 * Set the property values to the given object. Each of the supplied <code>values</code> should be a valid property value,
6320 * or a {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note
6321 * that it is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
6322 *
6323 * @param values the property values
6324 * @return the interface for additional requests or actions
6325 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
6326 * UUID}
6327 */
6328 Next to( Object[] values );
6329
6330 /**
6331 * Set the property value to the given objects. Each of the supplied values should be a valid property value, or a
6332 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
6333 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
6334 *
6335 * @param firstValue the first property value
6336 * @param otherValues the remaining property values
6337 * @return the interface for additional requests or actions
6338 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
6339 * UUID}
6340 */
6341 Next to( Object firstValue,
6342 Object... otherValues );
6343
6344 /**
6345 * Set the property value to the given object. Each of the supplied values should be a valid property value, or a
6346 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
6347 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
6348 *
6349 * @param values the container for the property values
6350 * @return the interface for additional requests or actions
6351 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
6352 * UUID}
6353 */
6354 Next to( Iterable<?> values );
6355
6356 /**
6357 * Set the property value to the given object. Each of the supplied values should be a valid property value, or a
6358 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
6359 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
6360 *
6361 * @param values the iterator over the property values
6362 * @return the interface for additional requests or actions
6363 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
6364 * UUID}
6365 */
6366 Next to( Iterator<?> values );
6367 }
6368
6369 /**
6370 * A component that defines a node that is to be created.
6371 *
6372 * @param <Next> The interface that is to be returned to complete the create request
6373 */
6374 public interface CreateNode<Next> {
6375 /**
6376 * Specify the name of the node that is to be created.
6377 *
6378 * @param nodeName the name of the new node
6379 * @param properties the properties for the new node
6380 * @return the next component for making additional requests.
6381 */
6382 Next node( String nodeName,
6383 Property... properties );
6384
6385 /**
6386 * Specify the name of the node that is to be created.
6387 *
6388 * @param nodeName the name of the new node
6389 * @param properties the properties for the new node
6390 * @return the next component for making additional requests.
6391 */
6392 Next node( String nodeName,
6393 Iterator<Property> properties );
6394
6395 /**
6396 * Specify the name of the node that is to be created.
6397 *
6398 * @param nodeName the name of the new node
6399 * @param properties the properties for the new node
6400 * @return the next component for making additional requests.
6401 */
6402 Next node( String nodeName,
6403 Iterable<Property> properties );
6404 }
6405
6406 /**
6407 * A component that defines a node that is to be created.
6408 *
6409 * @param <Next> The interface that is to be returned to complete the create request
6410 */
6411 public interface CreateNodeNamed<Next> {
6412 /**
6413 * Specify the name of the node that is to be created.
6414 *
6415 * @param nodeName the name of the new node
6416 * @return the interface used to complete the request
6417 */
6418 Create<Next> nodeNamed( String nodeName );
6419
6420 /**
6421 * Specify the name of the node that is to be created.
6422 *
6423 * @param nodeName the name of the new node
6424 * @return the interface used to complete the request
6425 */
6426 Create<Next> nodeNamed( Name nodeName );
6427 }
6428
6429 /**
6430 * A component that defines the location into which a node should be copied or moved.
6431 *
6432 * @param <Next> The interface that is to be returned when this request is completed
6433 */
6434 public interface ImportInto<Next> {
6435 /**
6436 * Specify whether the root element in the XML document should be skipped (that is, not be represented by a node). By
6437 * default, the root element is not skipped.
6438 *
6439 * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
6440 * @return the interface used to specify the location where the content should be placed
6441 */
6442 ImportInto<Next> skippingRootElement( boolean skip );
6443
6444 /**
6445 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6446 *
6447 * @param to the location of the new parent
6448 * @return the interface for additional requests or actions
6449 * @throws IOException if there is a problem reading the content being imported
6450 * @throws SAXException if there is a problem with the SAX Parser
6451 */
6452 Next into( Location to ) throws IOException, SAXException;
6453
6454 /**
6455 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6456 *
6457 * @param toPath the path of the new parent
6458 * @return the interface for additional requests or actions
6459 * @throws IOException if there is a problem reading the content being imported
6460 * @throws SAXException if there is a problem with the SAX Parser
6461 */
6462 Next into( String toPath ) throws IOException, SAXException;
6463
6464 /**
6465 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6466 *
6467 * @param to the path of the new parent
6468 * @return the interface for additional requests or actions
6469 * @throws IOException if there is a problem reading the content being imported
6470 * @throws SAXException if there is a problem with the SAX Parser
6471 */
6472 Next into( Path to ) throws IOException, SAXException;
6473
6474 /**
6475 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6476 *
6477 * @param to the UUID of the new parent
6478 * @return the interface for additional requests or actions
6479 * @throws IOException if there is a problem reading the content being imported
6480 * @throws SAXException if there is a problem with the SAX Parser
6481 */
6482 Next into( UUID to ) throws IOException, SAXException;
6483
6484 /**
6485 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6486 *
6487 * @param idProperty the property that uniquely identifies the new parent
6488 * @return the interface for additional requests or actions
6489 * @throws IOException if there is a problem reading the content being imported
6490 * @throws SAXException if there is a problem with the SAX Parser
6491 */
6492 Next into( Property idProperty ) throws IOException, SAXException;
6493
6494 /**
6495 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6496 *
6497 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
6498 * new parent
6499 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
6500 * identifies the new parent
6501 * @return the interface for additional requests or actions
6502 * @throws IOException if there is a problem reading the content being imported
6503 * @throws SAXException if there is a problem with the SAX Parser
6504 */
6505 Next into( Property firstIdProperty,
6506 Property... additionalIdProperties ) throws IOException, SAXException;
6507
6508 /**
6509 * Finish the import by specifying the Location.create into which the node should be copied/moved.
6510 *
6511 * @param idProperties the properties that uniquely identifies the new parent
6512 * @return the interface for additional requests or actions
6513 * @throws IOException if there is a problem reading the content being imported
6514 * @throws SAXException if there is a problem with the SAX Parser
6515 */
6516 Next into( Iterable<Property> idProperties ) throws IOException, SAXException;
6517 }
6518
6519 public interface BatchConjunction extends Conjunction<Batch>, Executable<Node> {
6520 }
6521
6522 public interface GetNodeConjunction<Next> extends Conjunction<Next> {
6523 Node andReturn();
6524 }
6525
6526 // ----------------------------------------------------------------------------------------------------------------
6527 // Node Implementation
6528 // ----------------------------------------------------------------------------------------------------------------
6529 @Immutable
6530 protected class GraphNode implements Node {
6531 private final ReadNodeRequest request;
6532
6533 /*package*/GraphNode( ReadNodeRequest request ) {
6534 this.request = request;
6535 }
6536
6537 public Location getLocation() {
6538 return request.getActualLocationOfNode();
6539 }
6540
6541 public DateTime getExpirationTime() {
6542 CachePolicy policy = request.getCachePolicy();
6543 return policy == null ? null : request.getTimeLoaded().plus(policy.getTimeToLive(), TimeUnit.MILLISECONDS);
6544 }
6545
6546 public Graph getGraph() {
6547 return Graph.this;
6548 }
6549
6550 public Collection<Property> getProperties() {
6551 return request.getProperties();
6552 }
6553
6554 public Property getProperty( Name name ) {
6555 return getPropertiesByName().get(name);
6556 }
6557
6558 public Property getProperty( String nameStr ) {
6559 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
6560 return getPropertiesByName().get(name);
6561 }
6562
6563 public Map<Name, Property> getPropertiesByName() {
6564 return request.getPropertiesByName();
6565 }
6566
6567 public List<Location> getChildren() {
6568 return request.getChildren();
6569 }
6570
6571 public boolean hasChildren() {
6572 return request.getChildren().size() > 0;
6573 }
6574
6575 public List<Segment> getChildrenSegments() {
6576 return getSegments(getChildren());
6577 }
6578
6579 public Iterator<Location> iterator() {
6580 return request.getChildren().iterator();
6581 }
6582
6583 @Override
6584 public int hashCode() {
6585 return getLocation().hashCode();
6586 }
6587
6588 @Override
6589 public boolean equals( Object obj ) {
6590 if (obj instanceof Node) {
6591 Node that = (Node)obj;
6592 return this.getLocation().isSame(that.getLocation());
6593 }
6594 return false;
6595 }
6596
6597 @Override
6598 public String toString() {
6599 return "Node " + getLocation().toString();
6600 }
6601 }
6602
6603 // ----------------------------------------------------------------------------------------------------------------
6604 // Results implementation for the batched requests
6605 // ----------------------------------------------------------------------------------------------------------------
6606 @Immutable
6607 class BatchResults implements Results {
6608 private final Map<Path, BatchResultsNode> nodes = new HashMap<Path, BatchResultsNode>();
6609 private final List<Request> requests;
6610
6611 /*package*/BatchResults( List<Request> requests ) {
6612 this.requests = Collections.unmodifiableList(requests);
6613 // Now create the results ...
6614 for (Request request : requests) {
6615 DateTime expires;
6616 BatchResultsNode node;
6617
6618 switch (request.getType()) {
6619 case READ_ALL_PROPERTIES:
6620 ReadAllPropertiesRequest readAll = (ReadAllPropertiesRequest)request;
6621 expires = computeExpirationTime(readAll);
6622 getOrCreateNode(readAll.getActualLocationOfNode(), expires).setProperties(readAll.getPropertiesByName());
6623 break;
6624 case READ_PROPERTY:
6625 ReadPropertyRequest read = (ReadPropertyRequest)request;
6626 expires = computeExpirationTime(read);
6627 getOrCreateNode(read.getActualLocationOfNode(), expires).addProperty(read.getProperty());
6628 break;
6629 case READ_NODE:
6630 ReadNodeRequest readNode = (ReadNodeRequest)request;
6631 expires = computeExpirationTime(readNode);
6632 node = getOrCreateNode(readNode.getActualLocationOfNode(), expires);
6633 node.setProperties(readNode.getPropertiesByName());
6634 node.setChildren(readNode.getChildren());
6635 break;
6636 case READ_BLOCK_OF_CHILDREN:
6637 throw new IllegalStateException();
6638 case READ_ALL_CHILDREN:
6639 ReadAllChildrenRequest readAllChildren = (ReadAllChildrenRequest)request;
6640 expires = computeExpirationTime(readAllChildren);
6641 getOrCreateNode(readAllChildren.getActualLocationOfNode(), expires).setChildren(readAllChildren.getChildren());
6642 break;
6643 case READ_BRANCH:
6644 ReadBranchRequest readBranch = (ReadBranchRequest)request;
6645 expires = computeExpirationTime(readBranch);
6646 for (Location location : readBranch) {
6647 node = getOrCreateNode(location, expires);
6648 node.setProperties(readBranch.getPropertiesFor(location));
6649 node.setChildren(readBranch.getChildren(location));
6650 }
6651 break;
6652 default:
6653 // Do nothing with other request types ...
6654 break;
6655 }
6656 }
6657 for (Map.Entry<Path, BatchResultsNode> entry : nodes.entrySet()) {
6658 entry.getValue().freeze();
6659 }
6660 }
6661
6662 /*package*/BatchResults( Request request ) {
6663 this.requests = Collections.singletonList(request);
6664 // Now create the results ...
6665 DateTime expires;
6666 BatchResultsNode node;
6667
6668 switch (request.getType()) {
6669 case READ_ALL_PROPERTIES:
6670 ReadAllPropertiesRequest readAll = (ReadAllPropertiesRequest)request;
6671 expires = computeExpirationTime(readAll);
6672 getOrCreateNode(readAll.getActualLocationOfNode(), expires).setProperties(readAll.getPropertiesByName());
6673 break;
6674 case READ_PROPERTY:
6675 ReadPropertyRequest read = (ReadPropertyRequest)request;
6676 expires = computeExpirationTime(read);
6677 getOrCreateNode(read.getActualLocationOfNode(), expires).addProperty(read.getProperty());
6678 break;
6679 case READ_NODE:
6680 ReadNodeRequest readNode = (ReadNodeRequest)request;
6681 expires = computeExpirationTime(readNode);
6682 node = getOrCreateNode(readNode.getActualLocationOfNode(), expires);
6683 node.setProperties(readNode.getPropertiesByName());
6684 node.setChildren(readNode.getChildren());
6685 break;
6686 case READ_BLOCK_OF_CHILDREN:
6687 throw new IllegalStateException();
6688 case READ_ALL_CHILDREN:
6689 ReadAllChildrenRequest readAllChildren = (ReadAllChildrenRequest)request;
6690 expires = computeExpirationTime(readAllChildren);
6691 getOrCreateNode(readAllChildren.getActualLocationOfNode(), expires).setChildren(readAllChildren.getChildren());
6692 break;
6693 case READ_BRANCH:
6694 ReadBranchRequest readBranch = (ReadBranchRequest)request;
6695 expires = computeExpirationTime(readBranch);
6696 for (Location location : readBranch) {
6697 node = getOrCreateNode(location, expires);
6698 node.setProperties(readBranch.getPropertiesFor(location));
6699 node.setChildren(readBranch.getChildren(location));
6700 }
6701 break;
6702 default:
6703 // Do nothing with other request types ...
6704 break;
6705 }
6706 for (Map.Entry<Path, BatchResultsNode> entry : nodes.entrySet()) {
6707 entry.getValue().freeze();
6708 }
6709 }
6710
6711 BatchResults() {
6712 this.requests = Collections.emptyList();
6713 }
6714
6715 /**
6716 * {@inheritDoc}
6717 *
6718 * @see org.modeshape.graph.Results#getRequests()
6719 */
6720 public List<Request> getRequests() {
6721 return requests;
6722 }
6723
6724 private BatchResultsNode getOrCreateNode( Location location,
6725 DateTime expirationTime ) {
6726 BatchResultsNode node = nodes.get(location);
6727 if (node == null) {
6728 node = new BatchResultsNode(location, expirationTime);
6729 assert location != null;
6730 assert location.getPath() != null;
6731 nodes.put(location.getPath(), node);
6732 }
6733 return node;
6734 }
6735
6736 public Graph getGraph() {
6737 return Graph.this;
6738 }
6739
6740 protected void checkIsAbsolute( Path path ) {
6741 if (!path.isAbsolute()) {
6742 throw new IllegalArgumentException(GraphI18n.pathIsNotAbsolute.text(path));
6743 }
6744 }
6745
6746 public Node getNode( String pathStr ) {
6747 Path path = createPath(pathStr);
6748 checkIsAbsolute(path);
6749 return nodes.get(path);
6750 }
6751
6752 public Node getNode( Path path ) {
6753 CheckArg.isNotNull(path, "path");
6754 checkIsAbsolute(path);
6755 return nodes.get(path);
6756 }
6757
6758 public Node getNode( Location location ) {
6759 CheckArg.isNotNull(location, "location");
6760 CheckArg.isNotNull(location.getPath(), "location.getPath()");
6761 return nodes.get(location.getPath());
6762 }
6763
6764 public boolean includes( String path ) {
6765 return getNode(path) != null;
6766 }
6767
6768 public boolean includes( Path path ) {
6769 return getNode(path) != null;
6770 }
6771
6772 public boolean includes( Location location ) {
6773 return getNode(location) != null;
6774 }
6775
6776 public Iterator<Node> iterator() {
6777 List<Path> paths = new ArrayList<Path>(nodes.keySet());
6778 Collections.sort(paths);
6779 final Iterator<Path> pathIter = paths.iterator();
6780 return new Iterator<Node>() {
6781 public boolean hasNext() {
6782 return pathIter.hasNext();
6783 }
6784
6785 public Node next() {
6786 Path nextPath = pathIter.next();
6787 return getNode(nextPath);
6788 }
6789
6790 public void remove() {
6791 throw new UnsupportedOperationException();
6792 }
6793 };
6794 }
6795 }
6796
6797 @Immutable
6798 class BatchResultsNode implements Node {
6799 private final Location location;
6800 private final DateTime expirationTime;
6801 private Map<Name, Property> properties;
6802 private List<Location> children;
6803
6804 BatchResultsNode( Location location,
6805 DateTime expirationTime ) {
6806 this.location = location;
6807 this.expirationTime = expirationTime;
6808 }
6809
6810 public DateTime getExpirationTime() {
6811 return expirationTime;
6812 }
6813
6814 void addProperty( Property property ) {
6815 if (this.properties == null) this.properties = new HashMap<Name, Property>();
6816 this.properties.put(property.getName(), property);
6817 }
6818
6819 void setProperties( Map<Name, Property> properties ) {
6820 this.properties = properties;
6821 }
6822
6823 void setChildren( List<Location> children ) {
6824 this.children = children;
6825 }
6826
6827 void freeze() {
6828 if (properties != null) properties = Collections.unmodifiableMap(properties);
6829 else properties = Collections.emptyMap();
6830 if (children != null) children = Collections.unmodifiableList(children);
6831 else children = Collections.emptyList();
6832 }
6833
6834 public List<Segment> getChildrenSegments() {
6835 return getSegments(getChildren());
6836 }
6837
6838 public Graph getGraph() {
6839 return Graph.this;
6840 }
6841
6842 public Location getLocation() {
6843 return location;
6844 }
6845
6846 public Collection<Property> getProperties() {
6847 return properties.values();
6848 }
6849
6850 public Map<Name, Property> getPropertiesByName() {
6851 return properties;
6852 }
6853
6854 public Property getProperty( Name name ) {
6855 return properties.get(name);
6856 }
6857
6858 public Property getProperty( String nameStr ) {
6859 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
6860 return properties.get(name);
6861 }
6862
6863 public List<Location> getChildren() {
6864 return children;
6865 }
6866
6867 public boolean hasChildren() {
6868 return children.size() != 0;
6869 }
6870
6871 public Iterator<Location> iterator() {
6872 return children.iterator();
6873 }
6874
6875 @Override
6876 public int hashCode() {
6877 return location.hashCode();
6878 }
6879
6880 @Override
6881 public boolean equals( Object obj ) {
6882 if (obj instanceof Node) {
6883 Node that = (Node)obj;
6884 return this.location.isSame(that.getLocation());
6885 }
6886 return false;
6887 }
6888
6889 @Override
6890 public String toString() {
6891 return "Node " + getLocation().toString();
6892 }
6893
6894 }
6895
6896 // ----------------------------------------------------------------------------------------------------------------
6897 // Subgraph and SubgraphNode implementations
6898 // ----------------------------------------------------------------------------------------------------------------
6899 @Immutable
6900 class SubgraphResults implements Subgraph {
6901 private final ReadBranchRequest request;
6902
6903 SubgraphResults( ReadBranchRequest request ) {
6904 this.request = request;
6905 }
6906
6907 public Graph getGraph() {
6908 return Graph.this;
6909 }
6910
6911 public Location getLocation() {
6912 return request.getActualLocationOfNode();
6913 }
6914
6915 public SubgraphNode getRoot() {
6916 return getNode(getLocation());
6917 }
6918
6919 public int getMaximumDepth() {
6920 return request.maximumDepth();
6921 }
6922
6923 public Iterator<SubgraphNode> iterator() {
6924 final Iterator<Location> iter = request.iterator();
6925 return new Iterator<SubgraphNode>() {
6926 public boolean hasNext() {
6927 return iter.hasNext();
6928 }
6929
6930 public SubgraphNode next() {
6931 return getNode(iter.next());
6932 }
6933
6934 public void remove() {
6935 throw new UnsupportedOperationException();
6936 }
6937 };
6938 }
6939
6940 public boolean includes( Path path ) {
6941 CheckArg.isNotNull(path, "path");
6942 path = getAbsolutePath(path);
6943 return request.includes(path);
6944 }
6945
6946 public boolean includes( Location location ) {
6947 CheckArg.isNotNull(location, "location");
6948 return request.includes(location);
6949 }
6950
6951 public boolean includes( String pathStr ) {
6952 Path path = createPath(pathStr);
6953 path = getAbsolutePath(path);
6954 return includes(path);
6955 }
6956
6957 public SubgraphNode getNode( Location location ) {
6958 if (!location.hasPath()) return null;
6959 Location actualLocation = request.getLocationFor(location.getPath());
6960 if (actualLocation == null) return null;
6961 return new SubgraphNodeImpl(actualLocation, request);
6962 }
6963
6964 public SubgraphNode getNode( Path path ) {
6965 path = getAbsolutePath(path);
6966 if (!includes(path)) return null;
6967 Location location = request.getLocationFor(path);
6968 if (location == null) return null;
6969 return new SubgraphNodeImpl(location, request);
6970 }
6971
6972 public SubgraphNode getNode( String pathStr ) {
6973 CheckArg.isNotEmpty(pathStr, "path");
6974 Path path = createPath(pathStr);
6975 path = getAbsolutePath(path);
6976 return getNode(path);
6977 }
6978
6979 public SubgraphNode getNode( Name relativePath ) {
6980 Path path = getGraph().getContext()
6981 .getValueFactories()
6982 .getPathFactory()
6983 .create(getLocation().getPath(), relativePath);
6984 path = path.getNormalizedPath();
6985 return getNode(path);
6986 }
6987
6988 protected Path getAbsolutePath( Path absoluteOrRelative ) {
6989 Path result = absoluteOrRelative;
6990 if (!result.isAbsolute()) {
6991 result = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), result);
6992 result = result.getNormalizedPath();
6993 }
6994 return result;
6995 }
6996
6997 @Override
6998 public int hashCode() {
6999 return getLocation().hashCode();
7000 }
7001
7002 @Override
7003 public String toString() {
7004 return "Subgraph\n" + getToString(context); // ExecutionContext.DEFAULT_CONTEXT);//getLocation().toString();
7005 }
7006
7007 /**
7008 * Get the string representation of this subgraph tree.
7009 *
7010 * @param context the execution context in which the conversion is to take place
7011 * @return the string representation; never null
7012 */
7013 public String getToString( ExecutionContext context ) {
7014 StringBuilder sb = new StringBuilder();
7015 getRecursiveString(context, getRoot(), sb, 0);
7016 return sb.toString();
7017 }
7018
7019 private void getRecursiveString( ExecutionContext context,
7020 SubgraphNode node,
7021 StringBuilder str,
7022 int indentLevel ) {
7023 for (int i = 0; i < indentLevel; ++i) {
7024 str.append(" ");
7025 }
7026 str.append(node.toString());
7027
7028 // Recursively add children at one greater tab level
7029 for (Location nextLoc : node.getChildren()) {
7030 SubgraphNode childNode = getNode(nextLoc);
7031 // child node location may exist, but the subgraph may not have
7032 // been constructed deep enough to instantiate the subnode, so
7033 // check for null
7034 if (childNode != null) {
7035 getRecursiveString(context, childNode, str, indentLevel + 1);
7036 }
7037 }
7038 }
7039
7040 }
7041
7042 protected static final List<Location> NO_CHILDREN = Collections.emptyList();
7043
7044 @Immutable
7045 class SubgraphNodeImpl implements SubgraphNode {
7046 private final Location location;
7047 private final ReadBranchRequest request;
7048
7049 SubgraphNodeImpl( Location location,
7050 ReadBranchRequest request ) {
7051 this.location = location;
7052 this.request = request;
7053 }
7054
7055 public DateTime getExpirationTime() {
7056 return computeExpirationTime(request);
7057 }
7058
7059 public List<Location> getChildren() {
7060 List<Location> children = request.getChildren(location);
7061 if (children == null) children = NO_CHILDREN;
7062 return children;
7063 }
7064
7065 public Graph getGraph() {
7066 return Graph.this;
7067 }
7068
7069 public Location getLocation() {
7070 return location;
7071 }
7072
7073 public Collection<Property> getProperties() {
7074 return getPropertiesByName().values();
7075 }
7076
7077 public Map<Name, Property> getPropertiesByName() {
7078 return request.getPropertiesFor(location);
7079 }
7080
7081 public Property getProperty( Name name ) {
7082 return getPropertiesByName().get(name);
7083 }
7084
7085 public Property getProperty( String nameStr ) {
7086 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
7087 return getPropertiesByName().get(name);
7088 }
7089
7090 public boolean hasChildren() {
7091 return getChildren().size() != 0;
7092 }
7093
7094 public List<Segment> getChildrenSegments() {
7095 return getSegments(getChildren());
7096 }
7097
7098 public Iterator<Location> iterator() {
7099 return getChildren().iterator();
7100 }
7101
7102 public SubgraphNode getNode( Name childName ) {
7103 Path path = getContext().getValueFactories().getPathFactory().create(location.getPath(), childName);
7104 Location location = request.getLocationFor(path);
7105 if (location == null) return null;
7106 return new SubgraphNodeImpl(location, request);
7107 }
7108
7109 public SubgraphNode getNode( Path relativePath ) {
7110 Path path = getContext().getValueFactories().getPathFactory().create(location.getPath(), relativePath);
7111 path = path.getNormalizedPath();
7112 Location location = request.getLocationFor(path);
7113 if (location == null) return null;
7114 return new SubgraphNodeImpl(location, request);
7115 }
7116
7117 @Override
7118 public int hashCode() {
7119 return location.hashCode();
7120 }
7121
7122 @Override
7123 public boolean equals( Object obj ) {
7124 if (obj instanceof Node) {
7125 Node that = (Node)obj;
7126 return this.location.isSame(that.getLocation());
7127 }
7128 return false;
7129 }
7130
7131 @Override
7132 public String toString() {
7133 return getNodeString(context, location);
7134 }
7135
7136 private String getNodeString( ExecutionContext context,
7137 Location location ) {
7138 StringBuilder sb = new StringBuilder();
7139 sb.append('<'); // Bracket the node
7140 ValueFactory<String> strings = context.getValueFactories().getStringFactory();
7141
7142 String name = "";
7143 if (location.getPath().getLastSegment() != null) {
7144 name = strings.create(location.getPath().getLastSegment());
7145 } else {
7146 name = strings.create(location.getPath());
7147 }
7148
7149 if (name.startsWith("{")) {
7150 // Remove {xxxx} namespace prefix
7151 int end = name.indexOf('}');
7152 name = name.substring(end + 1, name.length());
7153 }
7154
7155 // Surround name in double quotes
7156 sb.append("name = ").append('\"').append(name).append('\"').append(" ");
7157 boolean first = true;
7158 if (getProperties() != null) {
7159 for (Property entry : getProperties()) {
7160
7161 if (first) {
7162 first = false;
7163 } else sb.append(" ");
7164 sb.append(getPropertyString(entry));
7165 }
7166 }
7167 sb.append(">\n");
7168
7169 return sb.toString();
7170 }
7171
7172 private String getPropertyString( Property property ) {
7173 // Surround property value in double quotes so final property looks like:
7174 // color = "blue" (single valued property)
7175 // colors = ["blue", "red", "green"] (multi-valued property)
7176
7177 StringBuilder sb = new StringBuilder();
7178 sb.append(property.getName().getLocalName());
7179 sb.append(" = ");
7180 if (property.isEmpty()) {
7181 sb.append("null");
7182 } else if (property.isSingle()) {
7183 String valueStr = getContext().getValueFactories().getStringFactory().create(property.getValues().next());
7184 sb.append('\"').append(valueStr).append('\"');
7185 } else {
7186 sb.append('[');
7187 boolean first = true;
7188 for (Object value : property.getValuesAsArray()) {
7189 if (first) first = false;
7190 else sb.append(",");
7191 String valueStr = getContext().getValueFactories().getStringFactory().create(value);
7192 sb.append('\"').append(valueStr).append('\"');
7193 }
7194 if (property.isMultiple()) sb.append(']');
7195 }
7196 return sb.toString();
7197 }
7198 }
7199
7200 // ----------------------------------------------------------------------------------------------------------------
7201 // Action Implementations
7202 // ----------------------------------------------------------------------------------------------------------------
7203 @Immutable
7204 protected abstract class AbstractAction<T> implements Conjunction<T> {
7205 private final T afterConjunction;
7206
7207 /*package*/AbstractAction( T afterConjunction ) {
7208 this.afterConjunction = afterConjunction;
7209 }
7210
7211 /*package*/T afterConjunction() {
7212 return this.afterConjunction;
7213 }
7214
7215 public T and() {
7216 return this.afterConjunction;
7217 }
7218
7219 /*package*/Path createPath( String path ) {
7220 return Graph.this.getContext().getValueFactories().getPathFactory().create(path);
7221 }
7222
7223 /*package*/Name createName( String name ) {
7224 return Graph.this.getContext().getValueFactories().getNameFactory().create(name);
7225 }
7226 }
7227
7228 @NotThreadSafe
7229 protected abstract class MoveAction<T> extends AbstractAction<T> implements Move<T> {
7230 private final Locations from;
7231 private Name newName;
7232
7233 /*package*/MoveAction( T afterConjunction,
7234 Location from ) {
7235 super(afterConjunction);
7236 this.from = new Locations(from);
7237 }
7238
7239 public Move<T> and( Location from ) {
7240 this.from.add(from);
7241 return this;
7242 }
7243
7244 public Move<T> and( String from ) {
7245 this.from.add(Location.create(createPath(from)));
7246 return this;
7247 }
7248
7249 public Move<T> and( Path from ) {
7250 this.from.add(Location.create(from));
7251 return this;
7252 }
7253
7254 public Move<T> and( Property firstFrom,
7255 Property... additionalFroms ) {
7256 this.from.add(Location.create(firstFrom, additionalFroms));
7257 return this;
7258 }
7259
7260 public Move<T> and( Iterable<Property> idPropertiesFrom ) {
7261 this.from.add(Location.create(idPropertiesFrom));
7262 return this;
7263 }
7264
7265 public Move<T> and( Property from ) {
7266 this.from.add(Location.create(from));
7267 return this;
7268 }
7269
7270 public Move<T> and( UUID from ) {
7271 this.from.add(Location.create(from));
7272 return this;
7273 }
7274
7275 public Into<T> as( Name newName ) {
7276 this.newName = newName;
7277 return this;
7278 }
7279
7280 /**
7281 * {@inheritDoc}
7282 *
7283 * @see org.modeshape.graph.Graph.AsName#as(java.lang.String)
7284 */
7285 public Into<T> as( String newName ) {
7286 return as(createName(newName));
7287 }
7288
7289 /**
7290 * Submit any requests to move the targets into the supplied parent location
7291 *
7292 * @param from the location(s) that are being moved; never null
7293 * @param into the parent location
7294 * @param before the location of the child of the parent before which this node should be placed
7295 * @param newName the new name for the node being moved; may be null
7296 * @return this object, for method chaining
7297 */
7298 protected abstract T submit( Locations from,
7299 Location into,
7300 Location before,
7301 Name newName );
7302
7303 /**
7304 * Submit any requests to move the targets into the supplied parent location
7305 *
7306 * @param from the location(s) that are being moved; never null
7307 * @param into the parent location
7308 * @param newName the new name for the node being moved; may be null
7309 * @return this object, for method chaining
7310 */
7311 protected T submit( Locations from,
7312 Location into,
7313 Name newName ) {
7314 return submit(from, into, null, newName);
7315 }
7316
7317 public T into( Location into ) {
7318 return submit(from, into, null, newName);
7319 }
7320
7321 public T into( Path into ) {
7322 return submit(from, Location.create(into), newName);
7323 }
7324
7325 public T into( UUID into ) {
7326 return submit(from, Location.create(into), newName);
7327 }
7328
7329 public T into( Property firstIdProperty,
7330 Property... additionalIdProperties ) {
7331 return submit(from, Location.create(firstIdProperty, additionalIdProperties), newName);
7332 }
7333
7334 public T into( Property into ) {
7335 return submit(from, Location.create(into), newName);
7336 }
7337
7338 public T into( String into ) {
7339 return submit(from, Location.create(createPath(into)), newName);
7340 }
7341
7342 public T before( Location before ) {
7343 return submit(from, null, before, newName);
7344 }
7345
7346 public T before( Path before ) {
7347 return submit(from, null, Location.create(before), newName);
7348 }
7349
7350 public T before( UUID before ) {
7351 return submit(from, null, Location.create(before), newName);
7352 }
7353
7354 public T before( Property firstIdProperty,
7355 Property... additionalIdProperties ) {
7356 return submit(from, null, Location.create(firstIdProperty, additionalIdProperties), newName);
7357 }
7358
7359 public T before( Property before ) {
7360 return submit(from, null, Location.create(before), newName);
7361 }
7362
7363 public T before( String before ) {
7364 return submit(from, null, Location.create(createPath(before)), newName);
7365 }
7366 }
7367
7368 @NotThreadSafe
7369 protected abstract class CopyAction<T> extends AbstractAction<T> implements Copy<T> {
7370 protected Locations from;
7371 protected String fromWorkspaceName;
7372
7373 /*package*/CopyAction( T afterConjunction,
7374 Location from ) {
7375 super(afterConjunction);
7376 this.from = new Locations(from);
7377 this.fromWorkspaceName = Graph.this.getCurrentWorkspaceName();
7378 }
7379
7380 public Copy<T> and( Location from ) {
7381 this.from.add(from);
7382 return this;
7383 }
7384
7385 public Copy<T> and( String from ) {
7386 this.from.add(Location.create(createPath(from)));
7387 return this;
7388 }
7389
7390 public Copy<T> and( Path from ) {
7391 this.from.add(Location.create(from));
7392 return this;
7393 }
7394
7395 public Copy<T> and( Property firstFrom,
7396 Property... additionalFroms ) {
7397 this.from.add(Location.create(firstFrom, additionalFroms));
7398 return this;
7399 }
7400
7401 public Copy<T> and( Iterable<Property> idProperties ) {
7402 this.from.add(Location.create(idProperties));
7403 return this;
7404 }
7405
7406 public Copy<T> and( Property from ) {
7407 this.from.add(Location.create(from));
7408 return this;
7409 }
7410
7411 public Copy<T> and( UUID from ) {
7412 this.from.add(Location.create(from));
7413 return this;
7414 }
7415
7416 /**
7417 * Submit any requests to move the targets into the supplied parent location
7418 *
7419 * @param fromWorkspaceName the name of the workspace containing the {@code from} locations
7420 * @param from the locations that are being copied
7421 * @param into the parent location
7422 * @param nameForCopy the name that should be used for the copy, or null if the name should be the same as the original
7423 * @return this object, for method chaining
7424 */
7425 protected abstract T submit( String fromWorkspaceName,
7426 Locations from,
7427 Location into,
7428 Name nameForCopy );
7429
7430 public CopyTarget<T> fromWorkspace( String workspaceName ) {
7431 this.fromWorkspaceName = workspaceName;
7432
7433 return this;
7434 }
7435
7436 public T into( Location into ) {
7437 return submit(this.fromWorkspaceName, this.from, into, null);
7438 }
7439
7440 public T into( Path into ) {
7441 return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
7442 }
7443
7444 public T into( UUID into ) {
7445 return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
7446 }
7447
7448 public T into( Property firstIdProperty,
7449 Property... additionalIdProperties ) {
7450 return submit(this.fromWorkspaceName, this.from, Location.create(firstIdProperty, additionalIdProperties), null);
7451 }
7452
7453 public T into( Property into ) {
7454 return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
7455 }
7456
7457 public T into( String into ) {
7458 return submit(this.fromWorkspaceName, this.from, Location.create(createPath(into)), null);
7459 }
7460
7461 public T to( Location desiredLocation ) {
7462 if (!desiredLocation.hasPath()) {
7463 throw new IllegalArgumentException(GraphI18n.unableToCopyToLocationWithoutAPath.text(this.from, desiredLocation));
7464 }
7465 Path desiredPath = desiredLocation.getPath();
7466 if (desiredPath.isRoot()) {
7467 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredLocation));
7468 }
7469 Path parent = desiredPath.getParent();
7470 return submit(this.fromWorkspaceName, this.from, Location.create(parent), desiredPath.getLastSegment().getName());
7471 }
7472
7473 public T to( Path desiredPath ) {
7474 if (desiredPath.isRoot()) {
7475 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath));
7476 }
7477 Path parent = desiredPath.getParent();
7478 return submit(this.fromWorkspaceName, this.from, Location.create(parent), desiredPath.getLastSegment().getName());
7479 }
7480
7481 public T to( String desiredPath ) {
7482 return to(createPath(desiredPath));
7483 }
7484 }
7485
7486 @NotThreadSafe
7487 public abstract class CloneAction<T> extends AbstractAction<T> implements Clone<T> {
7488 protected final Location from;
7489
7490 /*package*/CloneAction( T afterConjunction,
7491 Location from ) {
7492 super(afterConjunction);
7493 this.from = from;
7494 }
7495
7496 protected abstract T submit( String fromWorkspaceName,
7497 Location from,
7498 String intoWorkspaceName,
7499 Location into,
7500 Name desiredName,
7501 Segment desiredSegment,
7502 boolean removeExisting );
7503
7504 public AsChild<Into<WithUuids<T>>> fromWorkspace( final String workspaceName ) {
7505 final CloneAction<T> source = this;
7506 return new AsChild<Into<WithUuids<T>>>() {
7507 public Into<WithUuids<T>> as( final Name name ) {
7508 return new CloneTargetAction<T>(afterConjunction(), source) {
7509 @Override
7510 protected T submit( Location into,
7511 boolean removeExisting ) {
7512 String intoWorkspaceName = getCurrentWorkspaceName();
7513 return source.submit(workspaceName, from, intoWorkspaceName, into, name, null, removeExisting);
7514 }
7515 };
7516
7517 }
7518
7519 public Into<WithUuids<T>> as( final String name ) {
7520 return as(context.getValueFactories().getNameFactory().create(name));
7521 }
7522
7523 public Into<WithUuids<T>> as( final Segment segment ) {
7524 return new CloneTargetAction<T>(afterConjunction(), source) {
7525 @Override
7526 protected T submit( Location into,
7527 boolean removeExisting ) {
7528 String intoWorkspaceName = getCurrentWorkspaceName();
7529 return source.submit(workspaceName, from, intoWorkspaceName, into, null, segment, removeExisting);
7530 }
7531 };
7532 }
7533
7534 };
7535 }
7536 }
7537
7538 @NotThreadSafe
7539 public abstract class CloneTargetAction<T> extends AbstractAction<T> implements Into<WithUuids<T>> {
7540 protected final CloneAction<T> source;
7541
7542 /*package*/CloneTargetAction( T afterConjunction,
7543 CloneAction<T> source ) {
7544 super(afterConjunction);
7545 this.source = source;
7546 }
7547
7548 protected abstract T submit( Location into,
7549 boolean removeExisting );
7550
7551 public WithUuids<T> into( final Location into ) {
7552 return new WithUuids<T>() {
7553 public T failingIfAnyUuidsMatch() {
7554 submit(into, false);
7555 return and();
7556 }
7557
7558 public T replacingExistingNodesWithSameUuids() {
7559 submit(into, true);
7560 return and();
7561
7562 }
7563 };
7564 }
7565
7566 public WithUuids<T> into( Path into ) {
7567 return into(Location.create(into));
7568 }
7569
7570 public WithUuids<T> into( UUID into ) {
7571 return into(Location.create(into));
7572 }
7573
7574 public WithUuids<T> into( Property firstIdProperty,
7575 Property... additionalIdProperties ) {
7576 return into(Location.create(firstIdProperty, additionalIdProperties));
7577 }
7578
7579 public WithUuids<T> into( Property into ) {
7580 return into(Location.create(into));
7581 }
7582
7583 public WithUuids<T> into( String into ) {
7584 return into(Location.create(createPath(into)));
7585 }
7586 }
7587
7588 @NotThreadSafe
7589 protected abstract class CreateAction<T> extends AbstractAction<T> implements Create<T> {
7590 private final String workspaceName;
7591 private final Location parent;
7592 private final Name childName;
7593 private final Map<Name, Property> properties = new HashMap<Name, Property>();
7594 private boolean submitted = false;
7595 private NodeConflictBehavior conflictBehavior = NodeConflictBehavior.APPEND;
7596
7597 /*package*/CreateAction( T afterConjunction,
7598 Location parent,
7599 String workspaceName,
7600 Name childName ) {
7601 super(afterConjunction);
7602 this.parent = parent;
7603 this.workspaceName = workspaceName;
7604 this.childName = childName;
7605 }
7606
7607 /**
7608 * {@inheritDoc}
7609 *
7610 * @see org.modeshape.graph.Graph.Create#ifAbsent()
7611 */
7612 public CreateAction<T> ifAbsent() {
7613 conflictBehavior = NodeConflictBehavior.DO_NOT_REPLACE;
7614 return this;
7615 }
7616
7617 /**
7618 * {@inheritDoc}
7619 *
7620 * @see org.modeshape.graph.Graph.Create#orReplace()
7621 */
7622 public CreateAction<T> orReplace() {
7623 conflictBehavior = NodeConflictBehavior.REPLACE;
7624 return this;
7625 }
7626
7627 /**
7628 * {@inheritDoc}
7629 *
7630 * @see org.modeshape.graph.Graph.Create#orUpdate()
7631 */
7632 public CreateAction<T> orUpdate() {
7633 conflictBehavior = NodeConflictBehavior.UPDATE;
7634 return this;
7635 }
7636
7637 /**
7638 * {@inheritDoc}
7639 *
7640 * @see org.modeshape.graph.Graph.Create#byAppending()
7641 */
7642 public CreateAction<T> byAppending() {
7643 conflictBehavior = NodeConflictBehavior.APPEND;
7644 return this;
7645 }
7646
7647 public Create<T> and( UUID uuid ) {
7648 PropertyFactory factory = getContext().getPropertyFactory();
7649 properties.put(ModeShapeLexicon.UUID, factory.create(ModeShapeLexicon.UUID, uuid));
7650 return this;
7651 }
7652
7653 public Create<T> and( Property property ) {
7654 properties.put(property.getName(), property);
7655 return this;
7656 }
7657
7658 public Create<T> and( Iterable<Property> properties ) {
7659 for (Property property : properties) {
7660 this.properties.put(property.getName(), property);
7661 }
7662 return this;
7663 }
7664
7665 public Create<T> and( String name,
7666 Object... values ) {
7667 ExecutionContext context = getContext();
7668 PropertyFactory factory = context.getPropertyFactory();
7669 NameFactory nameFactory = context.getValueFactories().getNameFactory();
7670 Name propertyName = nameFactory.create(name);
7671 properties.put(propertyName, factory.create(propertyName, values));
7672 return this;
7673 }
7674
7675 public Create<T> and( Name name,
7676 Object... values ) {
7677 PropertyFactory factory = getContext().getPropertyFactory();
7678 properties.put(name, factory.create(name, values));
7679 return this;
7680 }
7681
7682 public Create<T> and( Property property,
7683 Property... additionalProperties ) {
7684 properties.put(property.getName(), property);
7685 for (Property additionalProperty : additionalProperties) {
7686 properties.put(additionalProperty.getName(), additionalProperty);
7687 }
7688 return this;
7689 }
7690
7691 public Create<T> with( UUID uuid ) {
7692 return and(uuid);
7693 }
7694
7695 public Create<T> with( Property property ) {
7696 return and(property);
7697 }
7698
7699 public Create<T> with( Iterable<Property> properties ) {
7700 return and(properties);
7701 }
7702
7703 public Create<T> with( Property property,
7704 Property... additionalProperties ) {
7705 return and(property, additionalProperties);
7706 }
7707
7708 public Create<T> with( String name,
7709 Object... values ) {
7710 return and(name, values);
7711 }
7712
7713 public Create<T> with( Name name,
7714 Object... values ) {
7715 return and(name, values);
7716 }
7717
7718 protected abstract T submit( Location parent,
7719 String workspaceName,
7720 Name childName,
7721 Collection<Property> properties,
7722 NodeConflictBehavior conflictBehavior );
7723
7724 @Override
7725 public T and() {
7726 if (!submitted) {
7727 submit(parent, workspaceName, childName, this.properties.values(), this.conflictBehavior);
7728 submitted = true;
7729 }
7730 return super.and();
7731 }
7732 }
7733
7734 @NotThreadSafe
7735 protected abstract class CreateNodeNamedAction<T> extends AbstractAction<T> implements CreateNodeNamed<T> {
7736 private final Location parent;
7737
7738 protected CreateNodeNamedAction( T afterConjunction,
7739 Location parent ) {
7740 super(afterConjunction);
7741 this.parent = parent;
7742 }
7743
7744 public CreateAction<T> nodeNamed( String name ) {
7745 NameFactory factory = getContext().getValueFactories().getNameFactory();
7746 Name nameObj = factory.create(name);
7747 return createWith(afterConjunction(), parent, nameObj);
7748 }
7749
7750 public CreateAction<T> nodeNamed( Name name ) {
7751 return createWith(afterConjunction(), parent, name);
7752 }
7753
7754 protected abstract CreateAction<T> createWith( T afterConjunction,
7755 Location parent,
7756 Name nodeName );
7757 }
7758
7759 @Immutable
7760 protected static final class GraphWorkspace implements Workspace {
7761 private final String name;
7762 private final Location root;
7763
7764 GraphWorkspace( String name,
7765 Location root ) {
7766 assert name != null;
7767 assert root != null;
7768 this.name = name;
7769 this.root = root;
7770 }
7771
7772 /**
7773 * {@inheritDoc}
7774 *
7775 * @see org.modeshape.graph.Workspace#getName()
7776 */
7777 public String getName() {
7778 return name;
7779 }
7780
7781 /**
7782 * {@inheritDoc}
7783 *
7784 * @see org.modeshape.graph.Workspace#getRoot()
7785 */
7786 public Location getRoot() {
7787 return root;
7788 }
7789
7790 /**
7791 * {@inheritDoc}
7792 *
7793 * @see java.lang.Object#hashCode()
7794 */
7795 @Override
7796 public int hashCode() {
7797 return this.name.hashCode();
7798 }
7799
7800 /**
7801 * {@inheritDoc}
7802 *
7803 * @see java.lang.Object#equals(java.lang.Object)
7804 */
7805 @Override
7806 public boolean equals( Object obj ) {
7807 if (obj == this) return true;
7808 if (obj instanceof GraphWorkspace) {
7809 GraphWorkspace that = (GraphWorkspace)obj;
7810 if (!this.getName().equals(that.getName())) return false;
7811 // all root nodes should be equivalent, so no need to check
7812 return true;
7813 }
7814 return false;
7815 }
7816
7817 /**
7818 * {@inheritDoc}
7819 *
7820 * @see java.lang.Object#toString()
7821 */
7822 @Override
7823 public String toString() {
7824 return "Workspace \"" + this.name + "\" (root = " + this.root + " )";
7825 }
7826 }
7827
7828 /**
7829 * A set of nodes returned from a {@link Graph graph}, with methods to access the properties and children of the nodes in the
7830 * result. The {@link #iterator()} method can be used to iterate all over the nodes in the result.
7831 *
7832 * @param <NodeType> the type of node that tis results deals with
7833 */
7834 @Immutable
7835 public interface BaseResults<NodeType extends Node> extends Iterable<NodeType> {
7836
7837 /**
7838 * Get the graph containing the node.
7839 *
7840 * @return the graph
7841 */
7842 Graph getGraph();
7843
7844 /**
7845 * Get the node at the supplied location.
7846 *
7847 * @param path the path of the node in these results
7848 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
7849 */
7850 NodeType getNode( String path );
7851
7852 /**
7853 * Get the node at the supplied location.
7854 *
7855 * @param path the path of the node in these results
7856 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
7857 */
7858 NodeType getNode( Path path );
7859
7860 /**
7861 * Get the node at the supplied location.
7862 *
7863 * @param location the location of the node
7864 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
7865 */
7866 NodeType getNode( Location location );
7867
7868 /**
7869 * Return whether these results include a node at the supplied location.
7870 *
7871 * @param path the path of the node in these results
7872 * @return true if this subgraph includes the supplied location, or false otherwise
7873 */
7874 boolean includes( String path );
7875
7876 /**
7877 * Return whether this subgraph has a node at the supplied location.
7878 *
7879 * @param path the path of the node in these results
7880 * @return true if these results includes the supplied location, or false otherwise
7881 */
7882 boolean includes( Path path );
7883
7884 /**
7885 * Return whether this subgraph has a node at the supplied location.
7886 *
7887 * @param location the location of the node in these results
7888 * @return true if these results includes the supplied location, or false otherwise
7889 */
7890 boolean includes( Location location );
7891
7892 }
7893 }