001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.graph;
025
026 import java.io.File;
027 import java.io.IOException;
028 import java.io.InputStream;
029 import java.io.Reader;
030 import java.math.BigDecimal;
031 import java.net.URI;
032 import java.util.ArrayList;
033 import java.util.Calendar;
034 import java.util.Collection;
035 import java.util.Collections;
036 import java.util.Date;
037 import java.util.HashMap;
038 import java.util.Iterator;
039 import java.util.LinkedList;
040 import java.util.List;
041 import java.util.Map;
042 import java.util.Set;
043 import java.util.UUID;
044 import net.jcip.annotations.Immutable;
045 import net.jcip.annotations.NotThreadSafe;
046 import org.jboss.dna.common.collection.EmptyIterator;
047 import org.jboss.dna.common.util.CheckArg;
048 import org.jboss.dna.graph.cache.CachePolicy;
049 import org.jboss.dna.graph.connector.RepositoryConnection;
050 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
051 import org.jboss.dna.graph.connector.RepositorySource;
052 import org.jboss.dna.graph.connector.RepositorySourceException;
053 import org.jboss.dna.graph.io.GraphImporter;
054 import org.jboss.dna.graph.property.Binary;
055 import org.jboss.dna.graph.property.DateTime;
056 import org.jboss.dna.graph.property.Name;
057 import org.jboss.dna.graph.property.NameFactory;
058 import org.jboss.dna.graph.property.Path;
059 import org.jboss.dna.graph.property.PathNotFoundException;
060 import org.jboss.dna.graph.property.Property;
061 import org.jboss.dna.graph.property.PropertyFactory;
062 import org.jboss.dna.graph.property.Reference;
063 import org.jboss.dna.graph.property.ValueFormatException;
064 import org.jboss.dna.graph.property.Path.Segment;
065 import org.jboss.dna.graph.request.BatchRequestBuilder;
066 import org.jboss.dna.graph.request.CloneWorkspaceRequest;
067 import org.jboss.dna.graph.request.CompositeRequest;
068 import org.jboss.dna.graph.request.CreateNodeRequest;
069 import org.jboss.dna.graph.request.CreateWorkspaceRequest;
070 import org.jboss.dna.graph.request.InvalidRequestException;
071 import org.jboss.dna.graph.request.InvalidWorkspaceException;
072 import org.jboss.dna.graph.request.ReadAllChildrenRequest;
073 import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
074 import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
075 import org.jboss.dna.graph.request.ReadBranchRequest;
076 import org.jboss.dna.graph.request.ReadNodeRequest;
077 import org.jboss.dna.graph.request.ReadPropertyRequest;
078 import org.jboss.dna.graph.request.Request;
079 import org.jboss.dna.graph.request.RequestBuilder;
080 import org.jboss.dna.graph.request.UnsupportedRequestException;
081 import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
082 import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
083 import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
084 import org.xml.sax.SAXException;
085
086 /**
087 * A graph representation of the content within a {@link RepositorySource}, including mechanisms to interact and manipulate that
088 * content. The graph is designed to be an <i><a href="http://en.wikipedia.org/wiki/Domain_Specific_Language">embedded domain
089 * specific language</a></i>, meaning calls to it are designed to read like sentences even though they are really just Java
090 * methods. And to be more readable, methods can be chained together.
091 *
092 * @author Randall Hauch
093 */
094 @NotThreadSafe
095 public class Graph {
096
097 protected static final Iterator<Property> EMPTY_PROPERTIES = new EmptyIterator<Property>();
098 protected static final Iterable<Property> NO_PROPERTIES = new Iterable<Property>() {
099 public final Iterator<Property> iterator() {
100 return EMPTY_PROPERTIES;
101 }
102 };
103
104 /**
105 * Create a graph instance that uses the supplied repository and {@link ExecutionContext context}.
106 *
107 * @param sourceName the name of the source that should be used
108 * @param connectionFactory the factory of repository connections
109 * @param context the context in which all executions should be performed
110 * @return the new graph
111 * @throws IllegalArgumentException if the source or context parameters are null
112 * @throws RepositorySourceException if a source with the supplied name does not exist
113 */
114 public static Graph create( String sourceName,
115 RepositoryConnectionFactory connectionFactory,
116 ExecutionContext context ) {
117 return new Graph(sourceName, connectionFactory, context);
118 }
119
120 /**
121 * Create a graph instance that uses the supplied {@link RepositoryConnection} and {@link ExecutionContext context}.
122 *
123 * @param connection the connection that should be used
124 * @param context the context in which all executions should be performed
125 * @return the new graph
126 * @throws IllegalArgumentException if the connection or context parameters are null
127 */
128 public static Graph create( final RepositoryConnection connection,
129 ExecutionContext context ) {
130 CheckArg.isNotNull(connection, "connection");
131 final String connectorSourceName = connection.getSourceName();
132 RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
133 public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
134 if (connectorSourceName.equals(sourceName)) return connection;
135 return null;
136 }
137 };
138 return new Graph(connectorSourceName, connectionFactory, context);
139 }
140
141 /**
142 * Create a graph instance that uses the supplied {@link RepositoryConnection} and {@link ExecutionContext context}.
143 *
144 * @param source the source that should be used
145 * @param context the context in which all executions should be performed
146 * @return the new graph
147 * @throws IllegalArgumentException if the connection or context parameters are null
148 */
149 public static Graph create( final RepositorySource source,
150 ExecutionContext context ) {
151 CheckArg.isNotNull(source, "source");
152 final String connectorSourceName = source.getName();
153 RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
154 public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
155 if (connectorSourceName.equals(sourceName)) return source.getConnection();
156 return null;
157 }
158 };
159 return new Graph(connectorSourceName, connectionFactory, context);
160 }
161
162 private final String sourceName;
163 private final RepositoryConnectionFactory connectionFactory;
164 private final ExecutionContext context;
165 protected final RequestBuilder requests;
166 protected final Conjunction<Graph> nextGraph;
167 private Workspace currentWorkspace;
168
169 protected Graph( String sourceName,
170 RepositoryConnectionFactory connectionFactory,
171 ExecutionContext context ) {
172 CheckArg.isNotNull(sourceName, "sourceName");
173 CheckArg.isNotNull(connectionFactory, "connectionFactory");
174 CheckArg.isNotNull(context, "context");
175 this.sourceName = sourceName;
176 this.connectionFactory = connectionFactory;
177 this.context = context;
178 this.nextGraph = new Conjunction<Graph>() {
179 public Graph and() {
180 return Graph.this;
181 }
182 };
183 this.requests = new RequestBuilder() {
184 @Override
185 protected <T extends Request> T process( T request ) {
186 Graph.this.execute(request);
187 return request;
188 }
189 };
190 }
191
192 /**
193 * Get the RepositoryConnectionFactory that this graph uses to create {@link RepositoryConnection repository connections}.
194 *
195 * @return the factory repository connections used by this graph; never null
196 */
197 public RepositoryConnectionFactory getConnectionFactory() {
198 return connectionFactory;
199 }
200
201 /**
202 * The name of the repository that will be used by this graph. This name is passed to the {@link #getConnectionFactory()
203 * connection factory} when this graph needs to {@link RepositoryConnectionFactory#createConnection(String) obtain} a
204 * {@link RepositoryConnection repository connection}.
205 *
206 * @return the name of the source
207 */
208 public String getSourceName() {
209 return sourceName;
210 }
211
212 /**
213 * Get the context of execution within which operations on this graph are performed.
214 *
215 * @return the execution context; never null
216 */
217 public ExecutionContext getContext() {
218 return context;
219 }
220
221 /**
222 * Obtain a connection to the source, execute the supplied request, and check the request for {@link Request#getError()
223 * errors}. If an error is found, then it is thrown (or wrapped by a {@link RepositorySourceException} if the error is not a
224 * {@link RuntimeException}.
225 * <p>
226 * This method is called automatically when the {@link #requests request builder} creates each request.
227 * </p>
228 *
229 * @param request the request to be executed (may be a {@link CompositeRequest}.
230 * @throws PathNotFoundException if the request used a node that did not exist
231 * @throws InvalidRequestException if the request was not valid
232 * @throws InvalidWorkspaceException if the workspace used in the request was not valid
233 * @throws UnsupportedRequestException if the request was not supported by the source
234 * @throws RepositorySourceException if an error occurs during execution
235 * @throws RuntimeException if a runtime error occurs during execution
236 */
237 protected void execute( Request request ) {
238 RepositoryConnection connection = Graph.this.getConnectionFactory().createConnection(getSourceName());
239 if (connection == null) {
240 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
241 }
242 try {
243 connection.execute(Graph.this.getContext(), request);
244 } finally {
245 connection.close();
246 }
247 if (request.hasError()) {
248 Throwable error = request.getError();
249 if (error instanceof RuntimeException) throw (RuntimeException)error;
250 throw new RepositorySourceException(getSourceName(), error);
251 }
252 }
253
254 /**
255 * Get the default cache policy for this graph. May be null if such a policy has not been defined for thie
256 * {@link #getSourceName() source}.
257 *
258 * @return the default cache policy, or null if no such policy has been defined for the source
259 * @throws RepositorySourceException if no repository source with the {@link #getSourceName() name} could be found
260 */
261 public CachePolicy getDefaultCachePolicy() {
262 RepositoryConnection connection = this.connectionFactory.createConnection(getSourceName());
263 if (connection == null) {
264 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
265 }
266 try {
267 return connection.getDefaultCachePolicy();
268 } finally {
269 connection.close();
270 }
271 }
272
273 /**
274 * Utility method to set the workspace that will be used by this graph.
275 *
276 * @param workspaceName the name of the workspace; may not be null
277 * @param actualRootLocation the actual location of the root node in the workspace; may not be null
278 * @return the workspace; never null
279 */
280 protected Workspace setWorkspace( String workspaceName,
281 Location actualRootLocation ) {
282 assert workspaceName != null;
283 assert actualRootLocation != null;
284 this.currentWorkspace = new GraphWorkspace(workspaceName, actualRootLocation);
285 return this.currentWorkspace;
286 }
287
288 /**
289 * Get the name of the current workspace being used by this graph. If the graph has not yet been instructed to
290 * {@link #useWorkspace(String) use} or {@link #createWorkspace() create} a workspace, this method will assume that the
291 * source's default workspace is to be used and will obtain from the source the name of that default workspace.
292 *
293 * @return the name of the current workspace; never null
294 * @see #getCurrentWorkspace()
295 */
296 public String getCurrentWorkspaceName() {
297 return getCurrentWorkspace().getName();
298 }
299
300 /**
301 * Get the name of the current workspace being used by this graph. If the graph has not yet been instructed to
302 * {@link #useWorkspace(String) use} or {@link #createWorkspace() create} a workspace, this method will assume that the
303 * source's default workspace is to be used and will obtain from the source the name of that default workspace. If the source
304 * does not have a default workspace, this method will fail with an {@link InvalidWorkspaceException}.
305 *
306 * @return the name of the current workspace; never null
307 * @see #getCurrentWorkspaceName()
308 * @throws InvalidWorkspaceException if there is no current workspace
309 */
310 public Workspace getCurrentWorkspace() {
311 if (this.currentWorkspace == null) {
312 useWorkspace(null);
313 }
314 assert this.currentWorkspace != null;
315 return this.currentWorkspace;
316 }
317
318 /**
319 * Get the set of workspace names that are known to this source and accessible by this {@link #getContext() context}.
320 *
321 * @return the set of workspace names; never null
322 */
323 public Set<String> getWorkspaces() {
324 return requests.getWorkspaces().getAvailableWorkspaceNames();
325 }
326
327 /**
328 * Switch this graph to use another existing workspace in the same source.
329 *
330 * @param workspaceName the name of the existing workspace that this graph should begin using, or null if the graph should use
331 * the "default" workspace in the source (if there is one)
332 * @return the workspace; never null
333 * @throws InvalidWorkspaceException if the workspace with the supplied name does not exist, or if null is supplied as the
334 * workspace name but the source does not have a default workspace
335 */
336 public Workspace useWorkspace( String workspaceName ) {
337 VerifyWorkspaceRequest request = requests.verifyWorkspace(workspaceName);
338 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
339 }
340
341 /**
342 * 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
343 * created, and all subsequent operations will use the new workspace (until it is changed again by
344 * {@link #useWorkspace(String) using another workspace} or {@link #createWorkspace() creating another}.
345 *
346 * @return the interface used to complete the request to create a new workspace; never null
347 */
348 public CreateWorkspace createWorkspace() {
349 return new CreateWorkspace() {
350 /**
351 * {@inheritDoc}
352 *
353 * @see org.jboss.dna.graph.Graph.NameWorkspace#named(java.lang.String)
354 */
355 public Workspace named( String workspaceName ) {
356 CreateWorkspaceRequest request = requests.createWorkspace(workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
357 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
358 }
359
360 /**
361 * {@inheritDoc}
362 *
363 * @see org.jboss.dna.graph.Graph.CreateWorkspace#namedSomethingLike(java.lang.String)
364 */
365 public Workspace namedSomethingLike( String workspaceName ) {
366 CreateWorkspaceRequest request = requests.createWorkspace(workspaceName,
367 CreateConflictBehavior.CREATE_WITH_ADJUSTED_NAME);
368 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
369 }
370
371 /**
372 * {@inheritDoc}
373 *
374 * @see org.jboss.dna.graph.Graph.CreateWorkspace#clonedFrom(java.lang.String)
375 */
376 public NameWorkspace clonedFrom( final String nameOfWorkspaceToClone ) {
377 return new NameWorkspace() {
378 /**
379 * {@inheritDoc}
380 *
381 * @see org.jboss.dna.graph.Graph.NameWorkspace#named(java.lang.String)
382 */
383 public Workspace named( String nameOfWorkspaceToCreate ) {
384 CloneWorkspaceRequest request = requests.cloneWorkspace(nameOfWorkspaceToClone,
385 nameOfWorkspaceToCreate,
386 CreateConflictBehavior.DO_NOT_CREATE,
387 CloneConflictBehavior.DO_NOT_CLONE);
388 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
389 }
390
391 /**
392 * {@inheritDoc}
393 *
394 * @see org.jboss.dna.graph.Graph.NameWorkspace#namedSomethingLike(java.lang.String)
395 */
396 public Workspace namedSomethingLike( String nameOfWorkspaceToCreate ) {
397 CloneWorkspaceRequest request = requests.cloneWorkspace(nameOfWorkspaceToClone,
398 nameOfWorkspaceToCreate,
399 CreateConflictBehavior.CREATE_WITH_ADJUSTED_NAME,
400 CloneConflictBehavior.DO_NOT_CLONE);
401 return setWorkspace(request.getActualWorkspaceName(), request.getActualLocationOfRoot());
402 }
403 };
404 }
405 };
406 }
407
408 /**
409 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
410 * <code>into(...)</code> method on the returned {@link Move} object.
411 * <p>
412 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
413 * method is called.
414 * </p>
415 *
416 * @param from the node that is to be moved.
417 * @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
418 * be moved
419 */
420 public Move<Conjunction<Graph>> move( Node from ) {
421 return move(from.getLocation());
422 }
423
424 /**
425 * Begin the request to move a node at the specified location into a parent node at a different location, which is specified
426 * via the <code>into(...)</code> method on the returned {@link Move} object.
427 * <p>
428 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
429 * method is called.
430 * </p>
431 *
432 * @param from the location of the node that is to be moved.
433 * @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
434 * be moved
435 */
436 public Move<Conjunction<Graph>> move( Location from ) {
437 return new MoveAction<Conjunction<Graph>>(this.nextGraph, from) {
438 @Override
439 protected Conjunction<Graph> submit( Locations from,
440 Location into,
441 Location before,
442 Name newName ) {
443 String workspaceName = getCurrentWorkspaceName();
444 do {
445 requests.moveBranch(from.getLocation(), into, before, workspaceName, newName);
446 } while ((from = from.next()) != null);
447 return and();
448 }
449 };
450 }
451
452 /**
453 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
454 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
455 * <p>
456 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
457 * method is called.
458 * </p>
459 *
460 * @param fromPath the path to the node that is to be moved.
461 * @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
462 * be moved
463 */
464 public Move<Conjunction<Graph>> move( String fromPath ) {
465 return move(Location.create(createPath(fromPath)));
466 }
467
468 /**
469 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
470 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
471 * <p>
472 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
473 * method is called.
474 * </p>
475 *
476 * @param from the path to the node that is to be moved.
477 * @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
478 * be moved
479 */
480 public Move<Conjunction<Graph>> move( Path from ) {
481 return move(Location.create(from));
482 }
483
484 /**
485 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which is
486 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
487 * <p>
488 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
489 * method is called.
490 * </p>
491 *
492 * @param from the UUID of the node that is to be moved.
493 * @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
494 * be moved
495 */
496 public Move<Conjunction<Graph>> move( UUID from ) {
497 return move(Location.create(from));
498 }
499
500 /**
501 * Begin the request to move a node with the specified unique identification property into a parent node at a different
502 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification
503 * property should uniquely identify a single node.
504 * <p>
505 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
506 * method is called.
507 * </p>
508 *
509 * @param idProperty the unique identification property of the node that is to be moved.
510 * @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
511 * be moved
512 */
513 public Move<Conjunction<Graph>> move( Property idProperty ) {
514 return move(Location.create(idProperty));
515 }
516
517 /**
518 * Begin the request to move a node with the specified identification properties into a parent node at a different location,
519 * which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification properties
520 * should uniquely identify a single node.
521 * <p>
522 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
523 * method is called.
524 * </p>
525 *
526 * @param firstIdProperty the first identification property of the node that is to be moved
527 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be moved
528 * @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
529 * be moved
530 */
531 public Move<Conjunction<Graph>> move( Property firstIdProperty,
532 Property... additionalIdProperties ) {
533 return move(Location.create(firstIdProperty, additionalIdProperties));
534 }
535
536 /**
537 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
538 * <code>into(...)</code> method on the returned {@link Copy} object.
539 * <p>
540 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
541 * method is called.
542 * </p>
543 *
544 * @param from the node that is to be copied.
545 * @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
546 * be copied
547 */
548 public Copy<Graph> copy( Node from ) {
549 return copy(from.getLocation());
550 }
551
552 /**
553 * Begin the request to copy a node at the specified location into a parent node at a different location, which is specified
554 * via the <code>into(...)</code> method on the returned {@link Copy} object.
555 * <p>
556 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
557 * method is called.
558 * </p>
559 *
560 * @param from the location of the node that is to be copied.
561 * @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
562 * be copied
563 */
564 public Copy<Graph> copy( Location from ) {
565 return new CopyAction<Graph>(this, from) {
566 @Override
567 protected Graph submit( Locations from,
568 Location into,
569 Name childName ) {
570 String workspaceName = getCurrentWorkspaceName();
571 do {
572 requests.copyBranch(from.getLocation(),
573 workspaceName,
574 into,
575 workspaceName,
576 childName,
577 NodeConflictBehavior.APPEND);
578 } while ((from = from.next()) != null);
579 return and();
580 }
581 };
582 }
583
584 /**
585 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
586 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
587 * <p>
588 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
589 * method is called.
590 * </p>
591 *
592 * @param fromPath the path to the node that is to be copied.
593 * @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
594 * be copied
595 */
596 public Copy<Graph> copy( String fromPath ) {
597 return copy(Location.create(createPath(fromPath)));
598 }
599
600 /**
601 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
602 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
603 * <p>
604 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
605 * method is called.
606 * </p>
607 *
608 * @param from the path to the node that is to be copied.
609 * @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
610 * be copied
611 */
612 public Copy<Graph> copy( Path from ) {
613 return copy(Location.create(from));
614 }
615
616 /**
617 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which is
618 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
619 * <p>
620 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
621 * method is called.
622 * </p>
623 *
624 * @param from the UUID of the node that is to be copied.
625 * @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
626 * be copied
627 */
628 public Copy<Graph> copy( UUID from ) {
629 return copy(Location.create(from));
630 }
631
632 /**
633 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
634 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification
635 * property should uniquely identify a single node.
636 * <p>
637 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
638 * method is called.
639 * </p>
640 *
641 * @param idProperty the unique identification property of the node that is to be copied.
642 * @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
643 * be copied
644 */
645 public Copy<Graph> copy( Property idProperty ) {
646 return copy(Location.create(idProperty));
647 }
648
649 /**
650 * Begin the request to copy a node with the specified identification properties into a parent node at a different location,
651 * which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification properties
652 * should uniquely identify a single node.
653 * <p>
654 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
655 * method is called.
656 * </p>
657 *
658 * @param firstIdProperty the first identification property of the node that is to be copied
659 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
660 * @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
661 * be copied
662 */
663 public Copy<Graph> copy( Property firstIdProperty,
664 Property... additionalIdProperties ) {
665 return copy(Location.create(firstIdProperty, additionalIdProperties));
666 }
667
668 /**
669 * Request to delete the specified node. This request is submitted to the repository immediately.
670 *
671 * @param at the node that is to be deleted
672 * @return an object that may be used to start another request
673 */
674 public Conjunction<Graph> delete( Node at ) {
675 requests.deleteBranch(at.getLocation(), getCurrentWorkspaceName());
676 return nextGraph;
677 }
678
679 /**
680 * Request to delete the node at the given location. This request is submitted to the repository immediately.
681 *
682 * @param at the location of the node that is to be deleted
683 * @return an object that may be used to start another request
684 */
685 public Conjunction<Graph> delete( Location at ) {
686 requests.deleteBranch(at, getCurrentWorkspaceName());
687 return nextGraph;
688 }
689
690 /**
691 * Request to delete the node at the given path. This request is submitted to the repository immediately.
692 *
693 * @param atPath the path of the node that is to be deleted
694 * @return an object that may be used to start another request
695 */
696 public Conjunction<Graph> delete( String atPath ) {
697 return delete(Location.create(createPath(atPath)));
698 }
699
700 /**
701 * Request to delete the node at the given path. This request is submitted to the repository immediately.
702 *
703 * @param at the path of the node that is to be deleted
704 * @return an object that may be used to start another request
705 */
706 public Conjunction<Graph> delete( Path at ) {
707 return delete(Location.create(at));
708 }
709
710 /**
711 * Request to delete the node with the given UUID. This request is submitted to the repository immediately.
712 *
713 * @param at the UUID of the node that is to be deleted
714 * @return an object that may be used to start another request
715 */
716 public Conjunction<Graph> delete( UUID at ) {
717 return delete(Location.create(at));
718 }
719
720 /**
721 * Request to delete the node with the given unique identification property. This request is submitted to the repository
722 * immediately.
723 *
724 * @param idProperty the unique identifying property of the node that is to be deleted
725 * @return an object that may be used to start another request
726 */
727 public Conjunction<Graph> delete( Property idProperty ) {
728 return delete(Location.create(idProperty));
729 }
730
731 /**
732 * Request to delete the node with the given identification properties. The identification properties should uniquely identify
733 * a single node. This request is submitted to the repository immediately.
734 *
735 * @param firstIdProperty the first identification property of the node that is to be copied
736 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
737 * @return an object that may be used to start another request
738 */
739 public Conjunction<Graph> delete( Property firstIdProperty,
740 Property... additionalIdProperties ) {
741 return delete(Location.create(firstIdProperty, additionalIdProperties));
742 }
743
744 /**
745 * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
746 * the new node, or complete/submit the request and return the location, node, or graph.
747 * <p>
748 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
749 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
750 * parent or new node.
751 * </p>
752 *
753 * @param atPath the path to the node that is to be created.
754 * @return an object that may be used to start another request
755 */
756 public CreateAt<Graph> createAt( String atPath ) {
757 return createAt(createPath(atPath));
758 }
759
760 /**
761 * Begin the request to create a node located at the supplied path, and return an interface used to either add properties for
762 * the new node, or complete/submit the request and return the location, node, or graph.
763 * <p>
764 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
765 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
766 * parent or new node.
767 * </p>
768 *
769 * @param at the path to the node that is to be created.
770 * @return an object that may be used to start another request
771 */
772 public CreateAt<Graph> createAt( final Path at ) {
773 CheckArg.isNotNull(at, "at");
774 final Path parent = at.getParent();
775 final Name childName = at.getLastSegment().getName();
776 final String workspaceName = getCurrentWorkspaceName();
777 return new CreateAt<Graph>() {
778 private final List<Property> properties = new LinkedList<Property>();
779
780 public CreateAt<Graph> and( UUID uuid ) {
781 PropertyFactory factory = getContext().getPropertyFactory();
782 properties.add(factory.create(DnaLexicon.UUID, uuid));
783 return this;
784 }
785
786 public CreateAt<Graph> and( Property property ) {
787 properties.add(property);
788 return this;
789 }
790
791 public CreateAt<Graph> and( Iterable<Property> properties ) {
792 for (Property property : properties) {
793 this.properties.add(property);
794 }
795 return this;
796 }
797
798 public CreateAt<Graph> and( String name,
799 Object... values ) {
800 ExecutionContext context = getContext();
801 PropertyFactory factory = context.getPropertyFactory();
802 NameFactory nameFactory = context.getValueFactories().getNameFactory();
803 properties.add(factory.create(nameFactory.create(name), values));
804 return this;
805 }
806
807 public CreateAt<Graph> and( Name name,
808 Object... values ) {
809 ExecutionContext context = getContext();
810 PropertyFactory factory = context.getPropertyFactory();
811 properties.add(factory.create(name, values));
812 return this;
813 }
814
815 public CreateAt<Graph> and( Property property,
816 Property... additionalProperties ) {
817 properties.add(property);
818 for (Property additionalProperty : additionalProperties) {
819 properties.add(additionalProperty);
820 }
821 return this;
822 }
823
824 public CreateAt<Graph> with( UUID uuid ) {
825 return and(uuid);
826 }
827
828 public CreateAt<Graph> with( Property property ) {
829 return and(property);
830 }
831
832 public CreateAt<Graph> with( Iterable<Property> properties ) {
833 return and(properties);
834 }
835
836 public CreateAt<Graph> with( Property property,
837 Property... additionalProperties ) {
838 return and(property, additionalProperties);
839 }
840
841 public CreateAt<Graph> with( String name,
842 Object... values ) {
843 return and(name, values);
844 }
845
846 public CreateAt<Graph> with( Name name,
847 Object... values ) {
848 return and(name, values);
849 }
850
851 public Location getLocation() {
852 Location parentLoc = Location.create(parent);
853 CreateNodeRequest request = requests.createNode(parentLoc, workspaceName, childName, this.properties.iterator());
854 return request.getActualLocationOfNode();
855 }
856
857 public Node getNode() {
858 Location parentLoc = Location.create(parent);
859 CreateNodeRequest request = requests.createNode(parentLoc, workspaceName, childName, this.properties.iterator());
860 return getNodeAt(request.getActualLocationOfNode());
861 }
862
863 public Graph and() {
864 requests.createNode(Location.create(parent), workspaceName, childName, this.properties.iterator());
865 return Graph.this;
866 }
867 };
868 }
869
870 /**
871 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
872 * <p>
873 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
874 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
875 * parent or new node.
876 * </p>
877 *
878 * @param atPath the path to the node that is to be created.
879 * @return an object that may be used to start another request
880 */
881 public Conjunction<Graph> create( String atPath ) {
882 Path at = createPath(atPath);
883 Path parent = at.getParent();
884 Name child = at.getLastSegment().getName();
885 requests.createNode(Location.create(parent), getCurrentWorkspaceName(), child, EMPTY_PROPERTIES);
886 return nextGraph;
887 }
888
889 /**
890 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
891 * <p>
892 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
893 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
894 * parent or new node.
895 * </p>
896 *
897 * @param at the path to the node that is to be created.
898 * @return an object that may be used to start another request
899 */
900 public Conjunction<Graph> create( final Path at ) {
901 Path parent = at.getParent();
902 Name child = at.getLastSegment().getName();
903 requests.createNode(Location.create(parent), getCurrentWorkspaceName(), child, EMPTY_PROPERTIES);
904 return nextGraph;
905 }
906
907 /**
908 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
909 * <p>
910 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
911 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
912 * parent or new node.
913 * </p>
914 *
915 * @param atPath the path to the node that is to be created.
916 * @param properties the properties for the new node
917 * @return an object that may be used to start another request
918 */
919 public Conjunction<Graph> create( String atPath,
920 Property... properties ) {
921 Path at = createPath(atPath);
922 Path parent = at.getParent();
923 Name child = at.getLastSegment().getName();
924 requests.createNode(Location.create(parent), getCurrentWorkspaceName(), child, properties);
925 return nextGraph;
926 }
927
928 /**
929 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
930 * <p>
931 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
932 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
933 * parent or new node.
934 * </p>
935 *
936 * @param at the path to the node that is to be created.
937 * @param properties the properties for the new node
938 * @return an object that may be used to start another request
939 */
940 public Conjunction<Graph> create( Path at,
941 Property... properties ) {
942 CheckArg.isNotNull(at, "at");
943 Path parent = at.getParent();
944 Name child = at.getLastSegment().getName();
945 requests.createNode(Location.create(parent), getCurrentWorkspaceName(), child, properties);
946 return nextGraph;
947 }
948
949 /**
950 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
951 * the repository immediately.
952 * <p>
953 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
954 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
955 * parent or new node.
956 * </p>
957 *
958 * @param at the path to the node that is to be created.
959 * @param properties the properties for the new node
960 * @return an object that may be used to start another request
961 */
962 public Conjunction<Graph> create( Path at,
963 Iterable<Property> properties ) {
964 CheckArg.isNotNull(at, "at");
965 Path parent = at.getParent();
966 Name child = at.getLastSegment().getName();
967 requests.createNode(Location.create(parent), getCurrentWorkspaceName(), child, properties.iterator());
968 return nextGraph;
969 }
970
971 /**
972 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
973 * the repository immediately.
974 * <p>
975 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
976 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
977 * parent or new node.
978 * </p>
979 *
980 * @param atPath the path to the node that is to be created.
981 * @return an object that may be used to start another request
982 */
983 public GetNodeConjunction<Graph> createIfMissing( String atPath ) {
984 Path at = createPath(atPath);
985 Path parent = at.getParent();
986 Name child = at.getLastSegment().getName();
987 Location location = requests.createNode(Location.create(parent),
988 getCurrentWorkspaceName(),
989 child,
990 EMPTY_PROPERTIES,
991 NodeConflictBehavior.UPDATE).getActualLocationOfNode();
992 return new GetNodeOrReturnGraph(location);
993 }
994
995 /**
996 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
997 * the repository immediately.
998 * <p>
999 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1000 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1001 * parent or new node.
1002 * </p>
1003 *
1004 * @param at the path to the node that is to be created.
1005 * @return an object that may be used to start another request
1006 */
1007 public GetNodeConjunction<Graph> createIfMissing( final Path at ) {
1008 Path parent = at.getParent();
1009 Name child = at.getLastSegment().getName();
1010 Location location = requests.createNode(Location.create(parent),
1011 getCurrentWorkspaceName(),
1012 child,
1013 EMPTY_PROPERTIES,
1014 NodeConflictBehavior.UPDATE).getActualLocationOfNode();
1015 return new GetNodeOrReturnGraph(location);
1016 }
1017
1018 /**
1019 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
1020 * the repository immediately.
1021 * <p>
1022 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1023 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1024 * parent or new node.
1025 * </p>
1026 *
1027 * @param atPath the path to the node that is to be created.
1028 * @param properties the properties for the new node
1029 * @return an object that may be used to start another request
1030 */
1031 public GetNodeConjunction<Graph> createIfMissing( String atPath,
1032 Property... properties ) {
1033 Path at = createPath(atPath);
1034 Path parent = at.getParent();
1035 Name child = at.getLastSegment().getName();
1036 Location location = requests.createNode(Location.create(parent),
1037 getCurrentWorkspaceName(),
1038 child,
1039 properties,
1040 NodeConflictBehavior.UPDATE).getActualLocationOfNode();
1041 return new GetNodeOrReturnGraph(location);
1042 }
1043
1044 /**
1045 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
1046 * the repository immediately.
1047 * <p>
1048 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1049 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1050 * parent or new node.
1051 * </p>
1052 *
1053 * @param at the path to the node that is to be created.
1054 * @param properties the properties for the new node
1055 * @return an object that may be used to start another request
1056 */
1057 public GetNodeConjunction<Graph> createIfMissing( Path at,
1058 Property... properties ) {
1059 CheckArg.isNotNull(at, "at");
1060 Path parent = at.getParent();
1061 Name child = at.getLastSegment().getName();
1062 Location location = requests.createNode(Location.create(parent),
1063 getCurrentWorkspaceName(),
1064 child,
1065 properties,
1066 NodeConflictBehavior.UPDATE).getActualLocationOfNode();
1067 return new GetNodeOrReturnGraph(location);
1068 }
1069
1070 /**
1071 * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
1072 * the repository immediately.
1073 * <p>
1074 * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
1075 * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
1076 * parent or new node.
1077 * </p>
1078 *
1079 * @param at the path to the node that is to be created.
1080 * @param properties the properties for the new node
1081 * @return an object that may be used to start another request
1082 */
1083 public GetNodeConjunction<Graph> createIfMissing( Path at,
1084 Iterable<Property> properties ) {
1085 CheckArg.isNotNull(at, "at");
1086 Path parent = at.getParent();
1087 Name child = at.getLastSegment().getName();
1088 Location location = requests.createNode(Location.create(parent),
1089 getCurrentWorkspaceName(),
1090 child,
1091 properties.iterator(),
1092 NodeConflictBehavior.UPDATE).getActualLocationOfNode();
1093 return new GetNodeOrReturnGraph(location);
1094 }
1095
1096 /**
1097 * Begin the request to create a node under the existing parent node at the supplied location. Use this method if you are
1098 * creating a node when you have the {@link Location} of a parent from a previous request.
1099 * <p>
1100 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>node(...)</code>
1101 * method is called on the returned object
1102 * </p>
1103 *
1104 * @param parent the location of the parent
1105 * @return the object used to start creating a node
1106 */
1107 public CreateNode<Conjunction<Graph>> createUnder( final Location parent ) {
1108 final NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
1109 CheckArg.isNotNull(parent, "parent");
1110 return new CreateNode<Conjunction<Graph>>() {
1111 public Conjunction<Graph> node( String name,
1112 Property... properties ) {
1113 Name child = nameFactory.create(name);
1114 requests.createNode(parent, getCurrentWorkspaceName(), child, properties);
1115 return nextGraph;
1116 }
1117
1118 public Conjunction<Graph> node( String name,
1119 Iterator<Property> properties ) {
1120 Name child = nameFactory.create(name);
1121 requests.createNode(parent, getCurrentWorkspaceName(), child, properties);
1122 return nextGraph;
1123 }
1124
1125 public Conjunction<Graph> node( String name,
1126 Iterable<Property> properties ) {
1127 Name child = nameFactory.create(name);
1128 requests.createNode(parent, getCurrentWorkspaceName(), child, properties.iterator());
1129 return nextGraph;
1130 }
1131 };
1132 }
1133
1134 /**
1135 * Set the properties on a node.
1136 *
1137 * @param properties the properties to set
1138 * @return the remove request object that should be used to specify the node on which the properties are to be set.
1139 */
1140 public On<Conjunction<Graph>> set( final Property... properties ) {
1141 return new On<Conjunction<Graph>>() {
1142 public Conjunction<Graph> on( Location location ) {
1143 requests.setProperties(location, getCurrentWorkspaceName(), properties);
1144 return nextGraph;
1145 }
1146
1147 public Conjunction<Graph> on( String path ) {
1148 return on(Location.create(createPath(path)));
1149 }
1150
1151 public Conjunction<Graph> on( Path path ) {
1152 return on(Location.create(path));
1153 }
1154
1155 public Conjunction<Graph> on( Property idProperty ) {
1156 return on(Location.create(idProperty));
1157 }
1158
1159 public Conjunction<Graph> on( Property firstIdProperty,
1160 Property... additionalIdProperties ) {
1161 return on(Location.create(firstIdProperty, additionalIdProperties));
1162 }
1163
1164 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1165 return on(Location.create(idProperties));
1166 }
1167
1168 public Conjunction<Graph> on( UUID uuid ) {
1169 return on(Location.create(uuid));
1170 }
1171 };
1172 }
1173
1174 /**
1175 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
1176 * value(s) and the location of the node onto which the property should be set.
1177 *
1178 * @param propertyName the property name
1179 * @return the interface used to specify the values
1180 */
1181 public SetValues<Conjunction<Graph>> set( String propertyName ) {
1182 Name name = getContext().getValueFactories().getNameFactory().create(propertyName);
1183 return set(name);
1184 }
1185
1186 /**
1187 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
1188 * value(s) and the location of the node onto which the property should be set.
1189 *
1190 * @param propertyName the property name
1191 * @return the interface used to specify the values
1192 */
1193 public SetValues<Conjunction<Graph>> set( final Name propertyName ) {
1194 return new SetValues<Conjunction<Graph>>() {
1195 public SetValuesTo<Conjunction<Graph>> on( final Location location ) {
1196 return new SetValuesTo<Conjunction<Graph>>() {
1197 public Conjunction<Graph> to( Node value ) {
1198 Reference ref = (Reference)convertReferenceValue(value);
1199 Property property = getContext().getPropertyFactory().create(propertyName, ref);
1200 requests.setProperty(location, getCurrentWorkspaceName(), property);
1201 return nextGraph;
1202 }
1203
1204 public Conjunction<Graph> to( Location value ) {
1205 Reference ref = (Reference)convertReferenceValue(value);
1206 Property property = getContext().getPropertyFactory().create(propertyName, ref);
1207 requests.setProperty(location, getCurrentWorkspaceName(), property);
1208 return nextGraph;
1209 }
1210
1211 protected Conjunction<Graph> toValue( Object value ) {
1212 Property property = getContext().getPropertyFactory().create(propertyName, value);
1213 requests.setProperty(location, getCurrentWorkspaceName(), property);
1214 return nextGraph;
1215 }
1216
1217 public Conjunction<Graph> to( String value ) {
1218 return toValue(value);
1219 }
1220
1221 public Conjunction<Graph> to( int value ) {
1222 return toValue(Integer.valueOf(value));
1223 }
1224
1225 public Conjunction<Graph> to( long value ) {
1226 return toValue(Long.valueOf(value));
1227 }
1228
1229 public Conjunction<Graph> to( boolean value ) {
1230 return toValue(Boolean.valueOf(value));
1231 }
1232
1233 public Conjunction<Graph> to( float value ) {
1234 return toValue(Float.valueOf(value));
1235 }
1236
1237 public Conjunction<Graph> to( double value ) {
1238 return toValue(Double.valueOf(value));
1239 }
1240
1241 public Conjunction<Graph> to( BigDecimal value ) {
1242 return toValue(value);
1243 }
1244
1245 public Conjunction<Graph> to( Calendar value ) {
1246 return toValue(value);
1247 }
1248
1249 public Conjunction<Graph> to( Date value ) {
1250 return toValue(value);
1251 }
1252
1253 public Conjunction<Graph> to( DateTime value ) {
1254 return toValue(value);
1255 }
1256
1257 public Conjunction<Graph> to( Name value ) {
1258 return toValue(value);
1259 }
1260
1261 public Conjunction<Graph> to( Path value ) {
1262 return toValue(value);
1263 }
1264
1265 public Conjunction<Graph> to( Reference value ) {
1266 return toValue(value);
1267 }
1268
1269 public Conjunction<Graph> to( URI value ) {
1270 return toValue(value);
1271 }
1272
1273 public Conjunction<Graph> to( UUID value ) {
1274 return toValue(value);
1275 }
1276
1277 public Conjunction<Graph> to( Binary value ) {
1278 return toValue(value);
1279 }
1280
1281 public Conjunction<Graph> to( byte[] value ) {
1282 return toValue(value);
1283 }
1284
1285 public Conjunction<Graph> to( InputStream stream,
1286 long approximateLength ) {
1287 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
1288 return toValue(value);
1289 }
1290
1291 public Conjunction<Graph> to( Reader reader,
1292 long approximateLength ) {
1293 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
1294 return toValue(value);
1295 }
1296
1297 public Conjunction<Graph> to( Object value ) {
1298 value = convertReferenceValue(value);
1299 Property property = getContext().getPropertyFactory().create(propertyName, value);
1300 requests.setProperty(location, getCurrentWorkspaceName(), property);
1301 return nextGraph;
1302 }
1303
1304 public Conjunction<Graph> to( Object firstValue,
1305 Object... otherValues ) {
1306 firstValue = convertReferenceValue(firstValue);
1307 for (int i = 0, len = otherValues.length; i != len; ++i) {
1308 otherValues[i] = convertReferenceValue(otherValues[i]);
1309 }
1310 Property property = getContext().getPropertyFactory().create(propertyName, firstValue, otherValues);
1311 requests.setProperty(location, getCurrentWorkspaceName(), property);
1312 return nextGraph;
1313 }
1314
1315 public Conjunction<Graph> to( Object[] values ) {
1316 for (int i = 0, len = values.length; i != len; ++i) {
1317 values[i] = convertReferenceValue(values[i]);
1318 }
1319 Property property = getContext().getPropertyFactory().create(propertyName, values);
1320 requests.setProperty(location, getCurrentWorkspaceName(), property);
1321 return nextGraph;
1322 }
1323
1324 public Conjunction<Graph> to( Iterable<?> values ) {
1325 List<Object> valueList = new LinkedList<Object>();
1326 for (Object value : values) {
1327 value = convertReferenceValue(value);
1328 valueList.add(value);
1329 }
1330 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
1331 requests.setProperty(location, getCurrentWorkspaceName(), property);
1332 return nextGraph;
1333 }
1334
1335 public Conjunction<Graph> to( Iterator<?> values ) {
1336 List<Object> valueList = new LinkedList<Object>();
1337 while (values.hasNext()) {
1338 Object value = values.next();
1339 valueList.add(value);
1340 }
1341 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
1342 requests.setProperty(location, getCurrentWorkspaceName(), property);
1343 return nextGraph;
1344 }
1345 };
1346 }
1347
1348 public SetValuesTo<Conjunction<Graph>> on( String path ) {
1349 return on(Location.create(createPath(path)));
1350 }
1351
1352 public SetValuesTo<Conjunction<Graph>> on( Path path ) {
1353 return on(Location.create(path));
1354 }
1355
1356 public SetValuesTo<Conjunction<Graph>> on( Property idProperty ) {
1357 return on(Location.create(idProperty));
1358 }
1359
1360 public SetValuesTo<Conjunction<Graph>> on( Property firstIdProperty,
1361 Property... additionalIdProperties ) {
1362 return on(Location.create(firstIdProperty, additionalIdProperties));
1363 }
1364
1365 public SetValuesTo<Conjunction<Graph>> on( Iterable<Property> idProperties ) {
1366 return on(Location.create(idProperties));
1367 }
1368
1369 public SetValuesTo<Conjunction<Graph>> on( UUID uuid ) {
1370 return on(Location.create(uuid));
1371 }
1372
1373 public On<Conjunction<Graph>> to( Node node ) {
1374 Reference value = (Reference)convertReferenceValue(node);
1375 return set(getContext().getPropertyFactory().create(propertyName, value));
1376 }
1377
1378 public On<Conjunction<Graph>> to( Location location ) {
1379 Reference value = (Reference)convertReferenceValue(location);
1380 return set(getContext().getPropertyFactory().create(propertyName, value));
1381 }
1382
1383 protected On<Conjunction<Graph>> toValue( Object value ) {
1384 return set(getContext().getPropertyFactory().create(propertyName, value));
1385 }
1386
1387 public On<Conjunction<Graph>> to( String value ) {
1388 return toValue(value);
1389 }
1390
1391 public On<Conjunction<Graph>> to( int value ) {
1392 return toValue(Integer.valueOf(value));
1393 }
1394
1395 public On<Conjunction<Graph>> to( long value ) {
1396 return toValue(Long.valueOf(value));
1397 }
1398
1399 public On<Conjunction<Graph>> to( boolean value ) {
1400 return toValue(Boolean.valueOf(value));
1401 }
1402
1403 public On<Conjunction<Graph>> to( float value ) {
1404 return toValue(Float.valueOf(value));
1405 }
1406
1407 public On<Conjunction<Graph>> to( double value ) {
1408 return toValue(Double.valueOf(value));
1409 }
1410
1411 public On<Conjunction<Graph>> to( BigDecimal value ) {
1412 return toValue(value);
1413 }
1414
1415 public On<Conjunction<Graph>> to( Calendar value ) {
1416 return toValue(value);
1417 }
1418
1419 public On<Conjunction<Graph>> to( Date value ) {
1420 return toValue(value);
1421 }
1422
1423 public On<Conjunction<Graph>> to( DateTime value ) {
1424 return toValue(value);
1425 }
1426
1427 public On<Conjunction<Graph>> to( Name value ) {
1428 return toValue(value);
1429 }
1430
1431 public On<Conjunction<Graph>> to( Path value ) {
1432 return toValue(value);
1433 }
1434
1435 public On<Conjunction<Graph>> to( Reference value ) {
1436 return toValue(value);
1437 }
1438
1439 public On<Conjunction<Graph>> to( URI value ) {
1440 return toValue(value);
1441 }
1442
1443 public On<Conjunction<Graph>> to( UUID value ) {
1444 return toValue(value);
1445 }
1446
1447 public On<Conjunction<Graph>> to( Binary value ) {
1448 return toValue(value);
1449 }
1450
1451 public On<Conjunction<Graph>> to( byte[] value ) {
1452 return toValue(value);
1453 }
1454
1455 public On<Conjunction<Graph>> to( InputStream stream,
1456 long approximateLength ) {
1457 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
1458 return toValue(value);
1459 }
1460
1461 public On<Conjunction<Graph>> to( Reader reader,
1462 long approximateLength ) {
1463 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
1464 return toValue(value);
1465 }
1466
1467 public On<Conjunction<Graph>> to( Object value ) {
1468 value = convertReferenceValue(value);
1469 return set(getContext().getPropertyFactory().create(propertyName, value));
1470 }
1471
1472 public On<Conjunction<Graph>> to( Object firstValue,
1473 Object... otherValues ) {
1474 firstValue = convertReferenceValue(firstValue);
1475 for (int i = 0, len = otherValues.length; i != len; ++i) {
1476 otherValues[i] = convertReferenceValue(otherValues[i]);
1477 }
1478 return set(getContext().getPropertyFactory().create(propertyName, firstValue, otherValues));
1479 }
1480
1481 public On<Conjunction<Graph>> to( Object[] values ) {
1482 for (int i = 0, len = values.length; i != len; ++i) {
1483 values[i] = convertReferenceValue(values[i]);
1484 }
1485 return set(getContext().getPropertyFactory().create(propertyName, values));
1486 }
1487
1488 public On<Conjunction<Graph>> to( Iterable<?> values ) {
1489 List<Object> valueList = new LinkedList<Object>();
1490 for (Object value : values) {
1491 value = convertReferenceValue(value);
1492 valueList.add(value);
1493 }
1494 return set(getContext().getPropertyFactory().create(propertyName, valueList));
1495 }
1496
1497 public On<Conjunction<Graph>> to( Iterator<?> values ) {
1498 List<Object> valueList = new LinkedList<Object>();
1499 while (values.hasNext()) {
1500 Object value = values.next();
1501 valueList.add(value);
1502 }
1503 return set(getContext().getPropertyFactory().create(propertyName, valueList));
1504 }
1505 };
1506 }
1507
1508 /**
1509 * Remove properties from the node at the given location.
1510 *
1511 * @param propertyNames the names of the properties to be removed
1512 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1513 */
1514 public On<Conjunction<Graph>> remove( final Name... propertyNames ) {
1515 return new On<Conjunction<Graph>>() {
1516 public Conjunction<Graph> on( Location location ) {
1517 requests.removeProperties(location, getCurrentWorkspaceName(), propertyNames);
1518 return nextGraph;
1519 }
1520
1521 public Conjunction<Graph> on( String path ) {
1522 return on(Location.create(createPath(path)));
1523 }
1524
1525 public Conjunction<Graph> on( Path path ) {
1526 return on(Location.create(path));
1527 }
1528
1529 public Conjunction<Graph> on( Property idProperty ) {
1530 return on(Location.create(idProperty));
1531 }
1532
1533 public Conjunction<Graph> on( Property firstIdProperty,
1534 Property... additionalIdProperties ) {
1535 return on(Location.create(firstIdProperty, additionalIdProperties));
1536 }
1537
1538 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1539 return on(Location.create(idProperties));
1540 }
1541
1542 public Conjunction<Graph> on( UUID uuid ) {
1543 return on(Location.create(uuid));
1544 }
1545 };
1546 }
1547
1548 /**
1549 * Remove properties from the node at the given location.
1550 *
1551 * @param propertyNames the names of the properties to be removed
1552 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1553 */
1554 public On<Conjunction<Graph>> remove( final String... propertyNames ) {
1555 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
1556 int number = propertyNames.length;
1557 final Name[] names = new Name[number];
1558 for (int i = 0; i != number; ++i) {
1559 names[i] = nameFactory.create(propertyNames[i]);
1560 }
1561 return new On<Conjunction<Graph>>() {
1562 public Conjunction<Graph> on( Location location ) {
1563 requests.removeProperties(location, getCurrentWorkspaceName(), names);
1564 return nextGraph;
1565 }
1566
1567 public Conjunction<Graph> on( String path ) {
1568 return on(Location.create(createPath(path)));
1569 }
1570
1571 public Conjunction<Graph> on( Path path ) {
1572 return on(Location.create(path));
1573 }
1574
1575 public Conjunction<Graph> on( Property idProperty ) {
1576 return on(Location.create(idProperty));
1577 }
1578
1579 public Conjunction<Graph> on( Property firstIdProperty,
1580 Property... additionalIdProperties ) {
1581 return on(Location.create(firstIdProperty, additionalIdProperties));
1582 }
1583
1584 public Conjunction<Graph> on( Iterable<Property> idProperties ) {
1585 return on(Location.create(idProperties));
1586 }
1587
1588 public Conjunction<Graph> on( UUID uuid ) {
1589 return on(Location.create(uuid));
1590 }
1591 };
1592 }
1593
1594 /**
1595 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
1596 * object. Once the location is specified, the {@link Collection collection of properties} are read and then returned.
1597 *
1598 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
1599 */
1600 public On<Collection<Property>> getProperties() {
1601 return new On<Collection<Property>>() {
1602 public Collection<Property> on( Location location ) {
1603 return requests.readAllProperties(location, getCurrentWorkspaceName()).getProperties();
1604 }
1605
1606 public Collection<Property> on( String path ) {
1607 return on(Location.create(createPath(path)));
1608 }
1609
1610 public Collection<Property> on( Path path ) {
1611 return on(Location.create(path));
1612 }
1613
1614 public Collection<Property> on( Property idProperty ) {
1615 return on(Location.create(idProperty));
1616 }
1617
1618 public Collection<Property> on( Property firstIdProperty,
1619 Property... additionalIdProperties ) {
1620 return on(Location.create(firstIdProperty, additionalIdProperties));
1621 }
1622
1623 public Collection<Property> on( Iterable<Property> idProperties ) {
1624 return on(Location.create(idProperties));
1625 }
1626
1627 public Collection<Property> on( UUID uuid ) {
1628 return on(Location.create(uuid));
1629 }
1630 };
1631 }
1632
1633 /**
1634 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
1635 * object. Once the location is specified, the {@link Map map of properties} are read and then returned.
1636 *
1637 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
1638 * as a map keyed by their name
1639 */
1640 public On<Map<Name, Property>> getPropertiesByName() {
1641 return new On<Map<Name, Property>>() {
1642 public Map<Name, Property> on( Location location ) {
1643 return requests.readAllProperties(location, getCurrentWorkspaceName()).getPropertiesByName();
1644 }
1645
1646 public Map<Name, Property> on( String path ) {
1647 return on(Location.create(createPath(path)));
1648 }
1649
1650 public Map<Name, Property> on( Path path ) {
1651 return on(Location.create(path));
1652 }
1653
1654 public Map<Name, Property> on( Property idProperty ) {
1655 return on(Location.create(idProperty));
1656 }
1657
1658 public Map<Name, Property> on( Property firstIdProperty,
1659 Property... additionalIdProperties ) {
1660 return on(Location.create(firstIdProperty, additionalIdProperties));
1661 }
1662
1663 public Map<Name, Property> on( Iterable<Property> idProperties ) {
1664 return on(Location.create(idProperties));
1665 }
1666
1667 public Map<Name, Property> on( UUID uuid ) {
1668 return on(Location.create(uuid));
1669 }
1670 };
1671 }
1672
1673 /**
1674 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
1675 * object. The returned object is used to supply the remaining information, including either the {@link Children#of(Location)
1676 * location of the parent}, or that a subset of the children should be retrieved {@link Children#inBlockOf(int) in a block}.
1677 *
1678 * @return the object that is used to specify the remaining inputs for the request, and which will return the children
1679 */
1680 public Children<List<Location>> getChildren() {
1681 return new Children<List<Location>>() {
1682 public List<Location> of( String path ) {
1683 return of(Location.create(createPath(path)));
1684 }
1685
1686 public List<Location> of( Path path ) {
1687 return of(Location.create(path));
1688 }
1689
1690 public List<Location> of( Property idProperty ) {
1691 return of(Location.create(idProperty));
1692 }
1693
1694 public List<Location> of( Property firstIdProperty,
1695 Property... additionalIdProperties ) {
1696 return of(Location.create(firstIdProperty, additionalIdProperties));
1697 }
1698
1699 public List<Location> of( Iterable<Property> idProperties ) {
1700 return of(Location.create(idProperties));
1701 }
1702
1703 public List<Location> of( UUID uuid ) {
1704 return of(Location.create(uuid));
1705 }
1706
1707 public List<Location> of( Location at ) {
1708 return requests.readAllChildren(at, getCurrentWorkspaceName()).getChildren();
1709 }
1710
1711 public BlockOfChildren<List<Location>> inBlockOf( final int blockSize ) {
1712 return new BlockOfChildren<List<Location>>() {
1713 public Under<List<Location>> startingAt( final int startingIndex ) {
1714 return new Under<List<Location>>() {
1715 public List<Location> under( String path ) {
1716 return under(Location.create(createPath(path)));
1717 }
1718
1719 public List<Location> under( Path path ) {
1720 return under(Location.create(path));
1721 }
1722
1723 public List<Location> under( Property idProperty ) {
1724 return under(Location.create(idProperty));
1725 }
1726
1727 public List<Location> under( Property firstIdProperty,
1728 Property... additionalIdProperties ) {
1729 return under(Location.create(firstIdProperty, additionalIdProperties));
1730 }
1731
1732 public List<Location> under( UUID uuid ) {
1733 return under(Location.create(uuid));
1734 }
1735
1736 public List<Location> under( Location at ) {
1737 return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize)
1738 .getChildren();
1739 }
1740 };
1741 }
1742
1743 public List<Location> startingAfter( final Location previousSibling ) {
1744 return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize)
1745 .getChildren();
1746 }
1747
1748 public List<Location> startingAfter( String pathOfPreviousSibling ) {
1749 return startingAfter(Location.create(createPath(pathOfPreviousSibling)));
1750 }
1751
1752 public List<Location> startingAfter( Path pathOfPreviousSibling ) {
1753 return startingAfter(Location.create(pathOfPreviousSibling));
1754 }
1755
1756 public List<Location> startingAfter( UUID uuidOfPreviousSibling ) {
1757 return startingAfter(Location.create(uuidOfPreviousSibling));
1758 }
1759
1760 public List<Location> startingAfter( Property idPropertyOfPreviousSibling ) {
1761 return startingAfter(Location.create(idPropertyOfPreviousSibling));
1762 }
1763
1764 public List<Location> startingAfter( Property firstIdProperyOfPreviousSibling,
1765 Property... additionalIdPropertiesOfPreviousSibling ) {
1766 return startingAfter(Location.create(firstIdProperyOfPreviousSibling,
1767 additionalIdPropertiesOfPreviousSibling));
1768 }
1769 };
1770 }
1771 };
1772 }
1773
1774 /**
1775 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
1776 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
1777 *
1778 * @param name the name of the property that is to be read
1779 * @return the object that is used to specified the node whose property is to be read, and which will return the property
1780 */
1781 public On<Property> getProperty( final String name ) {
1782 Name nameObj = context.getValueFactories().getNameFactory().create(name);
1783 return getProperty(nameObj);
1784 }
1785
1786 /**
1787 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
1788 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
1789 *
1790 * @param name the name of the property that is to be read
1791 * @return the object that is used to specified the node whose property is to be read, and which will return the property
1792 */
1793 public On<Property> getProperty( final Name name ) {
1794 return new On<Property>() {
1795 public Property on( String path ) {
1796 return on(Location.create(createPath(path)));
1797 }
1798
1799 public Property on( Path path ) {
1800 return on(Location.create(path));
1801 }
1802
1803 public Property on( Property idProperty ) {
1804 return on(Location.create(idProperty));
1805 }
1806
1807 public Property on( Property firstIdProperty,
1808 Property... additionalIdProperties ) {
1809 return on(Location.create(firstIdProperty, additionalIdProperties));
1810 }
1811
1812 public Property on( Iterable<Property> idProperties ) {
1813 return on(Location.create(idProperties));
1814 }
1815
1816 public Property on( UUID uuid ) {
1817 return on(Location.create(uuid));
1818 }
1819
1820 public Property on( Location at ) {
1821 return requests.readProperty(at, getCurrentWorkspaceName(), name).getProperty();
1822 }
1823 };
1824 }
1825
1826 /**
1827 * Request to read the node with the supplied UUID.
1828 *
1829 * @param uuid the UUID of the node that is to be read
1830 * @return the node that is read from the repository
1831 */
1832 public Node getNodeAt( UUID uuid ) {
1833 return getNodeAt(Location.create(uuid));
1834 }
1835
1836 /**
1837 * Request to read the node at the supplied location.
1838 *
1839 * @param location the location of the node that is to be read
1840 * @return the node that is read from the repository
1841 */
1842 public Node getNodeAt( Location location ) {
1843 return new GraphNode(requests.readNode(location, getCurrentWorkspaceName()));
1844 }
1845
1846 /**
1847 * Request to read the node at the supplied path.
1848 *
1849 * @param path the path of the node that is to be read
1850 * @return the node that is read from the repository
1851 */
1852 public Node getNodeAt( String path ) {
1853 return getNodeAt(Location.create(createPath(path)));
1854 }
1855
1856 /**
1857 * Request to read the node at the supplied path.
1858 *
1859 * @param path the path of the node that is to be read
1860 * @return the node that is read from the repository
1861 */
1862 public Node getNodeAt( Path path ) {
1863 return getNodeAt(Location.create(path));
1864 }
1865
1866 /**
1867 * Request to read the node with the supplied unique identifier property.
1868 *
1869 * @param idProperty the identification property that is unique to the node that is to be read
1870 * @return the node that is read from the repository
1871 */
1872 public Node getNodeAt( Property idProperty ) {
1873 return getNodeAt(Location.create(idProperty));
1874 }
1875
1876 /**
1877 * Request to read the node with the supplied unique identifier properties.
1878 *
1879 * @param firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
1880 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be read
1881 * @return the node that is read from the repository
1882 */
1883 public Node getNodeAt( Property firstIdProperty,
1884 Property... additionalIdProperties ) {
1885 return getNodeAt(Location.create(firstIdProperty, additionalIdProperties));
1886 }
1887
1888 /**
1889 * Request to read the node with the supplied unique identifier properties.
1890 *
1891 * @param idProperties the identification properties that uniquely identify the node that is to be read
1892 * @return the node that is read from the repository
1893 */
1894 public Node getNodeAt( Iterable<Property> idProperties ) {
1895 return getNodeAt(Location.create(idProperties));
1896 }
1897
1898 /**
1899 * Request to read the node given by the supplied reference value.
1900 *
1901 * @param reference the reference property value that is to be resolved into a node
1902 * @return the node that is read from the repository
1903 * @throws ValueFormatException if the supplied reference could not be converted to an identifier property value
1904 */
1905 public Node resolve( Reference reference ) {
1906 CheckArg.isNotNull(reference, "reference");
1907 UUID uuid = context.getValueFactories().getUuidFactory().create(reference);
1908 return getNodeAt(uuid);
1909 }
1910
1911 /**
1912 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code> in
1913 * the resulting {@link At} object. All properties and children of every node in the subgraph will be read and returned in the
1914 * {@link Subgraph} object returned from the <code>at(...)</code> methods.
1915 *
1916 * @param depth the maximum depth of the subgraph that should be read
1917 * @return the component that should be used to specify the location of the node that is the top of the subgraph, and which
1918 * will return the {@link Subgraph} containing the results
1919 */
1920 public At<Subgraph> getSubgraphOfDepth( final int depth ) {
1921 return new At<Subgraph>() {
1922 public Subgraph at( Location location ) {
1923 return new SubgraphResults(requests.readBranch(location, getCurrentWorkspaceName(), depth));
1924 }
1925
1926 public Subgraph at( String path ) {
1927 return at(Location.create(createPath(path)));
1928 }
1929
1930 public Subgraph at( Path path ) {
1931 return at(Location.create(path));
1932 }
1933
1934 public Subgraph at( UUID uuid ) {
1935 return at(Location.create(uuid));
1936 }
1937
1938 public Subgraph at( Property idProperty ) {
1939 return at(Location.create(idProperty));
1940 }
1941
1942 public Subgraph at( Property firstIdProperty,
1943 Property... additionalIdProperties ) {
1944 return at(Location.create(firstIdProperty, additionalIdProperties));
1945 }
1946
1947 public Subgraph at( Iterable<Property> idProperties ) {
1948 return at(Location.create(idProperties));
1949 }
1950 };
1951 }
1952
1953 /**
1954 * Import the content from the provided stream of XML data, specifying via the returned {@link ImportInto object} where the
1955 * content is to be imported.
1956 *
1957 * @param stream the open stream of XML data that the importer can read the content that is to be imported
1958 * @return the object that should be used to specify into which the content is to be imported
1959 * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
1960 */
1961 public ImportInto<Conjunction<Graph>> importXmlFrom( final InputStream stream ) {
1962 CheckArg.isNotNull(stream, "stream");
1963
1964 return new ImportInto<Conjunction<Graph>>() {
1965 private boolean skipRootElement = false;
1966
1967 public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
1968 this.skipRootElement = skipRootElement;
1969 return this;
1970 }
1971
1972 public Conjunction<Graph> into( String path ) throws IOException, SAXException {
1973 return into(Location.create(createPath(path)));
1974 }
1975
1976 public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
1977 return into(Location.create(path));
1978 }
1979
1980 public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
1981 return into(Location.create(idProperty));
1982 }
1983
1984 public Conjunction<Graph> into( Property firstIdProperty,
1985 Property... additionalIdProperties ) throws IOException, SAXException {
1986 return into(Location.create(firstIdProperty, additionalIdProperties));
1987 }
1988
1989 public Conjunction<Graph> into( Iterable<Property> idProperties ) throws IOException, SAXException {
1990 return into(Location.create(idProperties));
1991 }
1992
1993 public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
1994 return into(Location.create(uuid));
1995 }
1996
1997 public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
1998 GraphImporter importer = new GraphImporter(Graph.this);
1999 importer.importXml(stream, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
2000 return Graph.this.nextGraph;
2001 }
2002 };
2003 }
2004
2005 /**
2006 * Import the content from the XML file at the supplied URI, specifying via the returned {@link ImportInto object} where the
2007 * content is to be imported.
2008 *
2009 * @param uri the URI where the importer can read the content that is to be imported
2010 * @return the object that should be used to specify into which the content is to be imported
2011 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2012 */
2013 public ImportInto<Conjunction<Graph>> importXmlFrom( final URI uri ) {
2014 return new ImportInto<Conjunction<Graph>>() {
2015 private boolean skipRootElement = false;
2016
2017 public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
2018 this.skipRootElement = skipRootElement;
2019 return this;
2020 }
2021
2022 public Conjunction<Graph> into( String path ) throws IOException, SAXException {
2023 return into(Location.create(createPath(path)));
2024 }
2025
2026 public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
2027 return into(Location.create(path));
2028 }
2029
2030 public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
2031 return into(Location.create(idProperty));
2032 }
2033
2034 public Conjunction<Graph> into( Property firstIdProperty,
2035 Property... additionalIdProperties ) throws IOException, SAXException {
2036 return into(Location.create(firstIdProperty, additionalIdProperties));
2037 }
2038
2039 public Conjunction<Graph> into( Iterable<Property> idProperties ) throws IOException, SAXException {
2040 return into(Location.create(idProperties));
2041 }
2042
2043 public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
2044 return into(Location.create(uuid));
2045 }
2046
2047 public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
2048 GraphImporter importer = new GraphImporter(Graph.this);
2049 importer.importXml(uri, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
2050 return Graph.this.nextGraph;
2051 }
2052 };
2053 }
2054
2055 /**
2056 * Import the content from the XML file at the supplied file location, specifying via the returned {@link ImportInto object}
2057 * where the content is to be imported.
2058 *
2059 * @param pathToFile the path to the XML file that should be imported.
2060 * @return the object that should be used to specify into which the content is to be imported
2061 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2062 */
2063 public ImportInto<Conjunction<Graph>> importXmlFrom( String pathToFile ) {
2064 CheckArg.isNotNull(pathToFile, "pathToFile");
2065 return importXmlFrom(new File(pathToFile).toURI());
2066 }
2067
2068 /**
2069 * Import the content from the XML file at the supplied file, specifying via the returned {@link ImportInto object} where the
2070 * content is to be imported.
2071 *
2072 * @param file the XML file that should be imported.
2073 * @return the object that should be used to specify into which the content is to be imported
2074 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
2075 */
2076 public ImportInto<Conjunction<Graph>> importXmlFrom( File file ) {
2077 CheckArg.isNotNull(file, "file");
2078 return importXmlFrom(file.toURI());
2079 }
2080
2081 protected Path createPath( String path ) {
2082 return getContext().getValueFactories().getPathFactory().create(path);
2083 }
2084
2085 protected List<Segment> getSegments( List<Location> locations ) {
2086 List<Segment> segments = new ArrayList<Segment>(locations.size());
2087 for (Location location : locations) {
2088 segments.add(location.getPath().getLastSegment());
2089 }
2090 return segments;
2091 }
2092
2093 /**
2094 * Begin a batch of requests to perform various operations. Use this approach when multiple operations are to be built and
2095 * then executed with one submission to the underlying {@link #getSourceName() repository source}. The {@link Results results}
2096 * are not available until the {@link Batch#execute()} method is invoked.
2097 *
2098 * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
2099 * @see Batch#execute()
2100 * @see Results
2101 */
2102 public Batch batch() {
2103 return new Batch(new BatchRequestBuilder());
2104 }
2105
2106 /**
2107 * Begin a batch of requests to perform various operations, but specify the queue where all accumulated requests should be
2108 * placed. Use this approach when multiple operations are to be built and then executed with one submission to the underlying
2109 * {@link #getSourceName() repository source}. The {@link Results results} are not available until the {@link Batch#execute()}
2110 * method is invoked.
2111 *
2112 * @param builder the request builder that should be used; may not be null
2113 * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
2114 * @see Batch#execute()
2115 * @see Results
2116 */
2117 public Batch batch( BatchRequestBuilder builder ) {
2118 CheckArg.isNotNull(builder, "builder");
2119 return new Batch(builder);
2120 }
2121
2122 /**
2123 * Interface for creating multiple requests to perform various operations. Note that all the requests are accumulated until
2124 * the {@link #execute()} method is called. The results of all the operations are then available in the {@link Results} object
2125 * returned by the {@link #execute()}.
2126 *
2127 * @author Randall Hauch
2128 */
2129 @Immutable
2130 public final class Batch implements Executable<Node> {
2131 protected final BatchRequestBuilder requestQueue;
2132 protected final BatchConjunction nextRequests;
2133 protected final String workspaceName;
2134 protected boolean executed = false;
2135
2136 /*package*/Batch( BatchRequestBuilder builder ) {
2137 assert builder != null;
2138 this.requestQueue = builder;
2139 this.workspaceName = Graph.this.getCurrentWorkspaceName();
2140 this.nextRequests = new BatchConjunction() {
2141 public Batch and() {
2142 return Batch.this;
2143 }
2144
2145 public Results execute() {
2146 return Batch.this.execute();
2147 }
2148 };
2149 }
2150
2151 /**
2152 * Return whether this batch has been {@link #execute() executed}.
2153 *
2154 * @return true if this batch has already been executed, or false otherwise
2155 */
2156 public boolean hasExecuted() {
2157 return executed;
2158 }
2159
2160 /**
2161 * Determine whether this batch needs to be executed (there are requests and the batch has not been executed yet).
2162 *
2163 * @return true if there are some requests in this batch that need to be executed, or false execution is not required
2164 */
2165 public boolean isExecuteRequired() {
2166 return !executed && requestQueue.hasRequests();
2167 }
2168
2169 /**
2170 * Obtain the graph that this batch uses.
2171 *
2172 * @return the graph; never null
2173 */
2174 public Graph getGraph() {
2175 return Graph.this;
2176 }
2177
2178 /**
2179 * Get the name of the workspace that this batch is using. This is always constant throughout the lifetime of the batch.
2180 *
2181 * @return the name of the workspace; never null
2182 */
2183 public String getCurrentWorkspaceName() {
2184 return this.workspaceName;
2185 }
2186
2187 protected final void assertNotExecuted() {
2188 if (executed) {
2189 throw new IllegalStateException(GraphI18n.unableToAddMoreRequestsToAlreadyExecutedBatch.text());
2190 }
2191 }
2192
2193 /**
2194 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
2195 * <code>into(...)</code> method on the returned {@link Move} object.
2196 * <p>
2197 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2198 * called.
2199 * </p>
2200 *
2201 * @param from the node that is to be moved.
2202 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2203 * to be moved
2204 */
2205 public Move<BatchConjunction> move( Node from ) {
2206 return move(from.getLocation());
2207 }
2208
2209 /**
2210 * Begin the request to move a node at the specified location into a parent node at a different location, which is
2211 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2212 * <p>
2213 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2214 * called.
2215 * </p>
2216 *
2217 * @param from the location of the node that is to be moved.
2218 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2219 * to be moved
2220 */
2221 public final Move<BatchConjunction> move( Location from ) {
2222 assertNotExecuted();
2223 return new MoveAction<BatchConjunction>(this.nextRequests, from) {
2224 @Override
2225 protected BatchConjunction submit( Locations from,
2226 Location into,
2227 Location before,
2228 Name newName ) {
2229 String workspaceName = getCurrentWorkspaceName();
2230 do {
2231 requestQueue.moveBranch(from.getLocation(), into, before, workspaceName, newName);
2232 } while ((from = from.next()) != null);
2233 return and();
2234 }
2235 };
2236 }
2237
2238 /**
2239 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
2240 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2241 * <p>
2242 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2243 * called.
2244 * </p>
2245 *
2246 * @param fromPath the path to the node that is to be moved.
2247 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2248 * to be moved
2249 */
2250 public Move<BatchConjunction> move( String fromPath ) {
2251 return move(Location.create(createPath(fromPath)));
2252 }
2253
2254 /**
2255 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
2256 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
2257 * <p>
2258 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2259 * called.
2260 * </p>
2261 *
2262 * @param from the path to the node that is to be moved.
2263 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2264 * to be moved
2265 */
2266 public Move<BatchConjunction> move( Path from ) {
2267 return move(Location.create(from));
2268 }
2269
2270 /**
2271 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which
2272 * is specified via the <code>into(...)</code> method on the returned {@link Move} object.
2273 * <p>
2274 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2275 * called.
2276 * </p>
2277 *
2278 * @param from the UUID of the node that is to be moved.
2279 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2280 * to be moved
2281 */
2282 public Move<BatchConjunction> move( UUID from ) {
2283 return move(Location.create(from));
2284 }
2285
2286 /**
2287 * Begin the request to move a node with the specified unique identification property into a parent node at a different
2288 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
2289 * identification property should uniquely identify a single node.
2290 * <p>
2291 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2292 * called.
2293 * </p>
2294 *
2295 * @param idProperty the unique identification property of the node that is to be moved.
2296 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2297 * to be moved
2298 */
2299 public Move<BatchConjunction> move( Property idProperty ) {
2300 return move(Location.create(idProperty));
2301 }
2302
2303 /**
2304 * Begin the request to move a node with the specified identification properties into a parent node at a different
2305 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
2306 * identification properties should uniquely identify a single node.
2307 * <p>
2308 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2309 * called.
2310 * </p>
2311 *
2312 * @param firstIdProperty the first identification property of the node that is to be moved
2313 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be moved
2314 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2315 * to be moved
2316 */
2317 public Move<BatchConjunction> move( Property firstIdProperty,
2318 Property... additionalIdProperties ) {
2319 return move(Location.create(firstIdProperty, additionalIdProperties));
2320 }
2321
2322 /**
2323 * Begin the request to move a node with the specified identification properties into a parent node at a different
2324 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
2325 * identification properties should uniquely identify a single node.
2326 * <p>
2327 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2328 * called.
2329 * </p>
2330 *
2331 * @param idProperties the idenficiation properties of the node that is to be moved
2332 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
2333 * to be moved
2334 */
2335 public Move<BatchConjunction> move( Iterable<Property> idProperties ) {
2336 return move(Location.create(idProperties));
2337 }
2338
2339 /**
2340 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
2341 * <code>into(...)</code> method on the returned {@link Copy} object.
2342 * <p>
2343 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2344 * called.
2345 * </p>
2346 *
2347 * @param from the node that is to be copied.
2348 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2349 * is to be copied
2350 */
2351 public Copy<BatchConjunction> copy( Node from ) {
2352 return copy(from.getLocation());
2353 }
2354
2355 /**
2356 * Begin the request to copy a node at the specified location into a parent node at a different location, which is
2357 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
2358 * <p>
2359 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2360 * called.
2361 * </p>
2362 *
2363 * @param from the location of the node that is to be copied.
2364 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2365 * is to be copied
2366 */
2367 public Copy<BatchConjunction> copy( Location from ) {
2368 assertNotExecuted();
2369 return new CopyAction<BatchConjunction>(this.nextRequests, from) {
2370 @Override
2371 protected BatchConjunction submit( Locations from,
2372 Location into,
2373 Name copyName ) {
2374 String workspaceName = getCurrentWorkspaceName();
2375 do {
2376 requestQueue.copyBranch(from.getLocation(), workspaceName, into, workspaceName, copyName);
2377 } while ((from = from.next()) != null);
2378 return and();
2379 }
2380 };
2381 }
2382
2383 /**
2384 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
2385 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
2386 * <p>
2387 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2388 * called.
2389 * </p>
2390 *
2391 * @param fromPath the path to the node that is to be copied.
2392 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2393 * is to be copied
2394 */
2395 public Copy<BatchConjunction> copy( String fromPath ) {
2396 return copy(Location.create(createPath(fromPath)));
2397 }
2398
2399 /**
2400 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
2401 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
2402 * <p>
2403 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the
2404 * <code>into(...)</code> method is called.
2405 * </p>
2406 *
2407 * @param from the path to the node that is to be copied.
2408 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2409 * is to be copied
2410 */
2411 public Copy<BatchConjunction> copy( Path from ) {
2412 return copy(Location.create(from));
2413 }
2414
2415 /**
2416 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which
2417 * is specified via the <code>into(...)</code> method on the returned {@link Copy} object.
2418 * <p>
2419 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2420 * called.
2421 * </p>
2422 *
2423 * @param from the UUID of the node that is to be copied.
2424 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2425 * is to be copied
2426 */
2427 public Copy<BatchConjunction> copy( UUID from ) {
2428 return copy(Location.create(from));
2429 }
2430
2431 /**
2432 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
2433 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
2434 * identification property should uniquely identify a single node.
2435 * <p>
2436 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2437 * called.
2438 * </p>
2439 *
2440 * @param idProperty the unique identification property of the node that is to be copied.
2441 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2442 * is to be copied
2443 */
2444 public Copy<BatchConjunction> copy( Property idProperty ) {
2445 return copy(Location.create(idProperty));
2446 }
2447
2448 /**
2449 * Begin the request to copy a node with the specified identification properties into a parent node at a different
2450 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
2451 * identification properties should uniquely identify a single node.
2452 * <p>
2453 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2454 * called.
2455 * </p>
2456 *
2457 * @param firstIdProperty the first identification property of the node that is to be copied
2458 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
2459 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2460 * is to be copied
2461 */
2462 public Copy<BatchConjunction> copy( Property firstIdProperty,
2463 Property... additionalIdProperties ) {
2464 return copy(Location.create(firstIdProperty, additionalIdProperties));
2465 }
2466
2467 /**
2468 * Begin the request to copy a node with the specified identification properties into a parent node at a different
2469 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
2470 * identification properties should uniquely identify a single node.
2471 * <p>
2472 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2473 * called.
2474 * </p>
2475 *
2476 * @param idProperties the identification properties of the node that is to be copied
2477 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
2478 * is to be copied
2479 */
2480 public Copy<BatchConjunction> copy( Iterable<Property> idProperties ) {
2481 return copy(Location.create(idProperties));
2482 }
2483
2484 /**
2485 * Request to delete the specified node.
2486 * <p>
2487 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2488 * called.
2489 * </p>
2490 *
2491 * @param at the node that is to be deleted
2492 * @return an object that may be used to start another request
2493 */
2494 public BatchConjunction delete( Node at ) {
2495 return delete(at.getLocation());
2496 }
2497
2498 /**
2499 * Request to delete the node at the given location.
2500 * <p>
2501 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2502 * called.
2503 * </p>
2504 *
2505 * @param at the location of the node that is to be deleted
2506 * @return an object that may be used to start another request
2507 */
2508 public BatchConjunction delete( Location at ) {
2509 assertNotExecuted();
2510 this.requestQueue.deleteBranch(at, getCurrentWorkspaceName());
2511 return nextRequests;
2512 }
2513
2514 /**
2515 * Request to delete the node at the given path.
2516 * <p>
2517 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2518 * called.
2519 * </p>
2520 *
2521 * @param atPath the path of the node that is to be deleted
2522 * @return an object that may be used to start another request
2523 */
2524 public BatchConjunction delete( String atPath ) {
2525 return delete(Location.create(createPath(atPath)));
2526 }
2527
2528 /**
2529 * Request to delete the node at the given path.
2530 * <p>
2531 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2532 * called.
2533 * </p>
2534 *
2535 * @param at the path of the node that is to be deleted
2536 * @return an object that may be used to start another request
2537 */
2538 public BatchConjunction delete( Path at ) {
2539 return delete(Location.create(at));
2540 }
2541
2542 /**
2543 * Request to delete the node with the given UUID.
2544 * <p>
2545 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2546 * called.
2547 * </p>
2548 *
2549 * @param at the UUID of the node that is to be deleted
2550 * @return an object that may be used to start another request
2551 */
2552 public BatchConjunction delete( UUID at ) {
2553 return delete(Location.create(at));
2554 }
2555
2556 /**
2557 * Request to delete the node with the given unique identification property.
2558 * <p>
2559 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2560 * called.
2561 * </p>
2562 *
2563 * @param idProperty the unique identifying property of the node that is to be deleted
2564 * @return an object that may be used to start another request
2565 */
2566 public BatchConjunction delete( Property idProperty ) {
2567 return delete(Location.create(idProperty));
2568 }
2569
2570 /**
2571 * Request to delete the node with the given identification properties. The identification properties should uniquely
2572 * identify a single node.
2573 * <p>
2574 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2575 * called.
2576 * </p>
2577 *
2578 * @param firstIdProperty the first identification property of the node that is to be copied
2579 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
2580 * @return an object that may be used to start another request
2581 */
2582 public BatchConjunction delete( Property firstIdProperty,
2583 Property... additionalIdProperties ) {
2584 return delete(Location.create(firstIdProperty, additionalIdProperties));
2585 }
2586
2587 /**
2588 * Request to delete the node with the given identification properties. The identification properties should uniquely
2589 * identify a single node.
2590 * <p>
2591 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2592 * called.
2593 * </p>
2594 *
2595 * @param idProperties the identification property of the node that is to be copied
2596 * @return an object that may be used to start another request
2597 */
2598 public BatchConjunction delete( Iterable<Property> idProperties ) {
2599 return delete(Location.create(idProperties));
2600 }
2601
2602 /**
2603 * Begin the request to create a node located at the supplied path.
2604 * <p>
2605 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2606 * called.
2607 * </p>
2608 *
2609 * @param atPath the path to the node that is to be created.
2610 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2611 * node where the node is to be created
2612 */
2613 public Create<Batch> create( String atPath ) {
2614 return create(createPath(atPath));
2615 }
2616
2617 /**
2618 * Begin the request to create a node located at the supplied path.
2619 * <p>
2620 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2621 * called.
2622 * </p>
2623 *
2624 * @param atPath the path to the node that is to be created.
2625 * @param property a property for the new node
2626 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2627 * node where the node is to be created
2628 */
2629 public Create<Batch> create( String atPath,
2630 Property property ) {
2631 return create(createPath(atPath)).with(property);
2632 }
2633
2634 /**
2635 * Begin the request to create a node located at the supplied path.
2636 * <p>
2637 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2638 * called.
2639 * </p>
2640 *
2641 * @param atPath the path to the node that is to be created.
2642 * @param firstProperty a property for the new node
2643 * @param additionalProperties additional properties for the new node
2644 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2645 * node where the node is to be created
2646 */
2647 public Create<Batch> create( String atPath,
2648 Property firstProperty,
2649 Property... additionalProperties ) {
2650 return create(createPath(atPath)).with(firstProperty, additionalProperties);
2651 }
2652
2653 /**
2654 * Begin the request to create a node located at the supplied path.
2655 * <p>
2656 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2657 * called.
2658 * </p>
2659 *
2660 * @param at the path to the node that is to be created.
2661 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2662 * node where the node is to be created
2663 */
2664 public final Create<Batch> create( Path at ) {
2665 assertNotExecuted();
2666 CheckArg.isNotNull(at, "at");
2667 Path parent = at.getParent();
2668 Name name = at.getLastSegment().getName();
2669 return create(Location.create(parent), name);
2670 }
2671
2672 protected final CreateAction<Batch> create( Location parent,
2673 Name child ) {
2674 return new CreateAction<Batch>(this, parent, getCurrentWorkspaceName(), child) {
2675 @Override
2676 protected Batch submit( Location parent,
2677 String workspaceName,
2678 Name childName,
2679 Collection<Property> properties,
2680 NodeConflictBehavior behavior ) {
2681 requestQueue.createNode(parent, workspaceName, childName, properties.iterator(), behavior);
2682 return Batch.this;
2683 }
2684
2685 /**
2686 * {@inheritDoc}
2687 *
2688 * @see org.jboss.dna.graph.Graph.Executable#execute()
2689 */
2690 public Results execute() {
2691 and();
2692 return Batch.this.execute();
2693 }
2694 };
2695 }
2696
2697 /**
2698 * Begin the request to create a node located at the supplied path.
2699 * <p>
2700 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2701 * called.
2702 * </p>
2703 *
2704 * @param at the path to the node that is to be created.
2705 * @param properties the iterator over the properties for the new node
2706 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2707 * node where the node is to be created
2708 */
2709 public Create<Batch> create( Path at,
2710 Iterable<Property> properties ) {
2711 Create<Batch> action = create(at);
2712 for (Property property : properties) {
2713 action.and(property);
2714 }
2715 return action;
2716 }
2717
2718 /**
2719 * Begin the request to create a node located at the supplied path.
2720 * <p>
2721 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2722 * called.
2723 * </p>
2724 *
2725 * @param at the path to the node that is to be created.
2726 * @param property a property for the new node
2727 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2728 * node where the node is to be created
2729 */
2730 public Create<Batch> create( Path at,
2731 Property property ) {
2732 return create(at).with(property);
2733 }
2734
2735 /**
2736 * Begin the request to create a node located at the supplied path.
2737 * <p>
2738 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
2739 * called.
2740 * </p>
2741 *
2742 * @param at the path to the node that is to be created.
2743 * @param firstProperty a property for the new node
2744 * @param additionalProperties additional properties for the new node
2745 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
2746 * node where the node is to be created
2747 */
2748 public Create<Batch> create( Path at,
2749 Property firstProperty,
2750 Property... additionalProperties ) {
2751 return create(at).with(firstProperty, additionalProperties);
2752 }
2753
2754 /**
2755 * Begin the request to create a node under the existing parent node at the supplied location. This request is submitted
2756 * to the repository after the returned components are completed.
2757 *
2758 * @param parent the location of the parent
2759 * @return the object used to start creating a node
2760 */
2761 public CreateNodeNamed<Batch> createUnder( Location parent ) {
2762 CheckArg.isNotNull(parent, "parent");
2763 return new CreateNodeNamedAction<Batch>(this, parent) {
2764 @Override
2765 protected CreateAction<Batch> createWith( Batch batch,
2766 Location parent,
2767 Name childName ) {
2768 return Batch.this.create(parent, childName);
2769 }
2770 };
2771 }
2772
2773 /**
2774 * Set the properties on a node.
2775 *
2776 * @param properties the properties to set
2777 * @return the interface that should be used to specify the node on which the properties are to be set.
2778 */
2779 public On<BatchConjunction> set( final Property... properties ) {
2780 return new On<BatchConjunction>() {
2781 public BatchConjunction on( Location location ) {
2782 requestQueue.setProperties(location, getCurrentWorkspaceName(), properties);
2783 return nextRequests;
2784 }
2785
2786 public BatchConjunction on( String path ) {
2787 return on(Location.create(createPath(path)));
2788 }
2789
2790 public BatchConjunction on( Path path ) {
2791 return on(Location.create(path));
2792 }
2793
2794 public BatchConjunction on( Property idProperty ) {
2795 return on(Location.create(idProperty));
2796 }
2797
2798 public BatchConjunction on( Property firstIdProperty,
2799 Property... additionalIdProperties ) {
2800 return on(Location.create(firstIdProperty, additionalIdProperties));
2801 }
2802
2803 public BatchConjunction on( Iterable<Property> idProperties ) {
2804 return on(Location.create(idProperties));
2805 }
2806
2807 public BatchConjunction on( UUID uuid ) {
2808 return on(Location.create(uuid));
2809 }
2810 };
2811 }
2812
2813 /**
2814 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
2815 * value(s) and the location of the node onto which the property should be set.
2816 *
2817 * @param propertyName the property name
2818 * @return the interface used to specify the values
2819 */
2820 public SetValues<BatchConjunction> set( String propertyName ) {
2821 Name name = getContext().getValueFactories().getNameFactory().create(propertyName);
2822 return set(name);
2823 }
2824
2825 /**
2826 * Set a property on a node, starting with the name. The interface returned from this method should be used to specify the
2827 * value(s) and the location of the node onto which the property should be set.
2828 *
2829 * @param propertyName the property name
2830 * @return the interface used to specify the values
2831 */
2832 public SetValues<BatchConjunction> set( final Name propertyName ) {
2833 return new SetValues<BatchConjunction>() {
2834 public SetValuesTo<BatchConjunction> on( final Location location ) {
2835 return new SetValuesTo<BatchConjunction>() {
2836 public BatchConjunction to( Node value ) {
2837 return to(value.getLocation());
2838 }
2839
2840 public BatchConjunction to( Location value ) {
2841 Reference ref = (Reference)convertReferenceValue(value);
2842 Property property = getContext().getPropertyFactory().create(propertyName, ref);
2843 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2844 return nextRequests;
2845 }
2846
2847 protected BatchConjunction toValue( Object value ) {
2848 Property property = getContext().getPropertyFactory().create(propertyName, value);
2849 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2850 return nextRequests;
2851 }
2852
2853 public BatchConjunction to( String value ) {
2854 return toValue(value);
2855 }
2856
2857 public BatchConjunction to( int value ) {
2858 return toValue(Integer.valueOf(value));
2859 }
2860
2861 public BatchConjunction to( long value ) {
2862 return toValue(Long.valueOf(value));
2863 }
2864
2865 public BatchConjunction to( boolean value ) {
2866 return toValue(Boolean.valueOf(value));
2867 }
2868
2869 public BatchConjunction to( float value ) {
2870 return toValue(Float.valueOf(value));
2871 }
2872
2873 public BatchConjunction to( double value ) {
2874 return toValue(Double.valueOf(value));
2875 }
2876
2877 public BatchConjunction to( BigDecimal value ) {
2878 return toValue(value);
2879 }
2880
2881 public BatchConjunction to( Calendar value ) {
2882 return toValue(value);
2883 }
2884
2885 public BatchConjunction to( Date value ) {
2886 return toValue(value);
2887 }
2888
2889 public BatchConjunction to( DateTime value ) {
2890 return toValue(value);
2891 }
2892
2893 public BatchConjunction to( Name value ) {
2894 return toValue(value);
2895 }
2896
2897 public BatchConjunction to( Path value ) {
2898 return toValue(value);
2899 }
2900
2901 public BatchConjunction to( Reference value ) {
2902 return toValue(value);
2903 }
2904
2905 public BatchConjunction to( URI value ) {
2906 return toValue(value);
2907 }
2908
2909 public BatchConjunction to( UUID value ) {
2910 return toValue(value);
2911 }
2912
2913 public BatchConjunction to( Binary value ) {
2914 return toValue(value);
2915 }
2916
2917 public BatchConjunction to( byte[] value ) {
2918 return toValue(value);
2919 }
2920
2921 public BatchConjunction to( InputStream stream,
2922 long approximateLength ) {
2923 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
2924 return toValue(value);
2925 }
2926
2927 public BatchConjunction to( Reader reader,
2928 long approximateLength ) {
2929 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
2930 return toValue(value);
2931 }
2932
2933 public BatchConjunction to( Object value ) {
2934 value = convertReferenceValue(value);
2935 Property property = getContext().getPropertyFactory().create(propertyName, value);
2936 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2937 return nextRequests;
2938 }
2939
2940 public BatchConjunction to( Object firstValue,
2941 Object... otherValues ) {
2942 firstValue = convertReferenceValue(firstValue);
2943 for (int i = 0, len = otherValues.length; i != len; ++i) {
2944 otherValues[i] = convertReferenceValue(otherValues[i]);
2945 }
2946 Property property = getContext().getPropertyFactory().create(propertyName, firstValue, otherValues);
2947 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2948 return nextRequests;
2949 }
2950
2951 public BatchConjunction to( Object[] values ) {
2952 for (int i = 0; i != values.length; ++i) {
2953 values[i] = convertReferenceValue(values[i]);
2954 }
2955 Property property = getContext().getPropertyFactory().create(propertyName, values);
2956 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2957 return nextRequests;
2958 }
2959
2960 public BatchConjunction to( Iterable<?> values ) {
2961 List<Object> valueList = new LinkedList<Object>();
2962 for (Object value : values) {
2963 value = convertReferenceValue(value);
2964 valueList.add(value);
2965 }
2966 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
2967 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2968 return nextRequests;
2969 }
2970
2971 public BatchConjunction to( Iterator<?> values ) {
2972 List<Object> valueList = new LinkedList<Object>();
2973 while (values.hasNext()) {
2974 Object value = values.next();
2975 valueList.add(value);
2976 }
2977 Property property = getContext().getPropertyFactory().create(propertyName, valueList);
2978 requestQueue.setProperty(location, getCurrentWorkspaceName(), property);
2979 return nextRequests;
2980 }
2981
2982 };
2983 }
2984
2985 public SetValuesTo<BatchConjunction> on( String path ) {
2986 return on(Location.create(createPath(path)));
2987 }
2988
2989 public SetValuesTo<BatchConjunction> on( Path path ) {
2990 return on(Location.create(path));
2991 }
2992
2993 public SetValuesTo<BatchConjunction> on( Property idProperty ) {
2994 return on(Location.create(idProperty));
2995 }
2996
2997 public SetValuesTo<BatchConjunction> on( Property firstIdProperty,
2998 Property... additionalIdProperties ) {
2999 return on(Location.create(firstIdProperty, additionalIdProperties));
3000 }
3001
3002 public SetValuesTo<BatchConjunction> on( Iterable<Property> idProperties ) {
3003 return on(Location.create(idProperties));
3004 }
3005
3006 public SetValuesTo<BatchConjunction> on( UUID uuid ) {
3007 return on(Location.create(uuid));
3008 }
3009
3010 public On<BatchConjunction> to( Node value ) {
3011 Object reference = convertReferenceValue(value);
3012 return set(getContext().getPropertyFactory().create(propertyName, reference));
3013 }
3014
3015 public On<BatchConjunction> to( Location value ) {
3016 Object reference = convertReferenceValue(value);
3017 return set(getContext().getPropertyFactory().create(propertyName, reference));
3018 }
3019
3020 protected On<BatchConjunction> toValue( Object value ) {
3021 return set(getContext().getPropertyFactory().create(propertyName, value));
3022 }
3023
3024 public On<BatchConjunction> to( String value ) {
3025 return toValue(value);
3026 }
3027
3028 public On<BatchConjunction> to( int value ) {
3029 return toValue(Integer.valueOf(value));
3030 }
3031
3032 public On<BatchConjunction> to( long value ) {
3033 return toValue(Long.valueOf(value));
3034 }
3035
3036 public On<BatchConjunction> to( boolean value ) {
3037 return toValue(Boolean.valueOf(value));
3038 }
3039
3040 public On<BatchConjunction> to( float value ) {
3041 return toValue(Float.valueOf(value));
3042 }
3043
3044 public On<BatchConjunction> to( double value ) {
3045 return toValue(Double.valueOf(value));
3046 }
3047
3048 public On<BatchConjunction> to( BigDecimal value ) {
3049 return toValue(value);
3050 }
3051
3052 public On<BatchConjunction> to( Calendar value ) {
3053 return toValue(value);
3054 }
3055
3056 public On<BatchConjunction> to( Date value ) {
3057 return toValue(value);
3058 }
3059
3060 public On<BatchConjunction> to( DateTime value ) {
3061 return toValue(value);
3062 }
3063
3064 public On<BatchConjunction> to( Name value ) {
3065 return toValue(value);
3066 }
3067
3068 public On<BatchConjunction> to( Path value ) {
3069 return toValue(value);
3070 }
3071
3072 public On<BatchConjunction> to( Reference value ) {
3073 return toValue(value);
3074 }
3075
3076 public On<BatchConjunction> to( URI value ) {
3077 return toValue(value);
3078 }
3079
3080 public On<BatchConjunction> to( UUID value ) {
3081 return toValue(value);
3082 }
3083
3084 public On<BatchConjunction> to( Binary value ) {
3085 return toValue(value);
3086 }
3087
3088 public On<BatchConjunction> to( byte[] value ) {
3089 return toValue(value);
3090 }
3091
3092 public On<BatchConjunction> to( InputStream stream,
3093 long approximateLength ) {
3094 Binary value = getContext().getValueFactories().getBinaryFactory().create(stream, approximateLength);
3095 return toValue(value);
3096 }
3097
3098 public On<BatchConjunction> to( Reader reader,
3099 long approximateLength ) {
3100 Binary value = getContext().getValueFactories().getBinaryFactory().create(reader, approximateLength);
3101 return toValue(value);
3102 }
3103
3104 public On<BatchConjunction> to( Object value ) {
3105 value = convertReferenceValue(value);
3106 return set(getContext().getPropertyFactory().create(propertyName, value));
3107 }
3108
3109 public On<BatchConjunction> to( Object firstValue,
3110 Object... otherValues ) {
3111 Object[] values = new Object[otherValues.length + 1];
3112 values[0] = convertReferenceValue(firstValue);
3113 for (int i = 0, len = otherValues.length; i != len; ++i) {
3114 values[i + 1] = convertReferenceValue(otherValues[i]);
3115 }
3116 return set(getContext().getPropertyFactory().create(propertyName, values));
3117 }
3118
3119 public On<BatchConjunction> to( Object[] values ) {
3120 for (int i = 0, len = values.length; i != len; ++i) {
3121 values[i] = convertReferenceValue(values[i]);
3122 }
3123 return set(getContext().getPropertyFactory().create(propertyName, values));
3124 }
3125
3126 public On<BatchConjunction> to( Iterable<?> values ) {
3127 List<Object> valueList = new LinkedList<Object>();
3128 for (Object value : values) {
3129 value = convertReferenceValue(value);
3130 valueList.add(value);
3131 }
3132 return set(getContext().getPropertyFactory().create(propertyName, valueList));
3133 }
3134
3135 public On<BatchConjunction> to( Iterator<?> values ) {
3136 List<Object> valueList = new LinkedList<Object>();
3137 while (values.hasNext()) {
3138 Object value = values.next();
3139 valueList.add(value);
3140 }
3141 return set(getContext().getPropertyFactory().create(propertyName, valueList));
3142 }
3143 };
3144 }
3145
3146 /**
3147 * Remove properties from the node at the given location.
3148 *
3149 * @param propertyNames the names of the properties to be removed
3150 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
3151 */
3152 public On<BatchConjunction> remove( final Name... propertyNames ) {
3153 return new On<BatchConjunction>() {
3154 public BatchConjunction on( Location location ) {
3155 requestQueue.removeProperties(location, getCurrentWorkspaceName(), propertyNames);
3156 return nextRequests;
3157 }
3158
3159 public BatchConjunction on( String path ) {
3160 return on(Location.create(createPath(path)));
3161 }
3162
3163 public BatchConjunction on( Path path ) {
3164 return on(Location.create(path));
3165 }
3166
3167 public BatchConjunction on( Property idProperty ) {
3168 return on(Location.create(idProperty));
3169 }
3170
3171 public BatchConjunction on( Property firstIdProperty,
3172 Property... additionalIdProperties ) {
3173 return on(Location.create(firstIdProperty, additionalIdProperties));
3174 }
3175
3176 public BatchConjunction on( Iterable<Property> idProperties ) {
3177 return on(Location.create(idProperties));
3178 }
3179
3180 public BatchConjunction on( UUID uuid ) {
3181 return on(Location.create(uuid));
3182 }
3183 };
3184 }
3185
3186 /**
3187 * Remove properties from the node at the given location.
3188 *
3189 * @param propertyNames the names of the properties to be removed
3190 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
3191 */
3192 public On<BatchConjunction> remove( String... propertyNames ) {
3193 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
3194 int number = propertyNames.length;
3195 final Name[] names = new Name[number];
3196 for (int i = 0; i != number; ++i) {
3197 names[i] = nameFactory.create(propertyNames[i]);
3198 }
3199 return new On<BatchConjunction>() {
3200 public BatchConjunction on( Location location ) {
3201 requestQueue.removeProperties(location, getCurrentWorkspaceName(), names);
3202 return nextRequests;
3203 }
3204
3205 public BatchConjunction on( String path ) {
3206 return on(Location.create(createPath(path)));
3207 }
3208
3209 public BatchConjunction on( Path path ) {
3210 return on(Location.create(path));
3211 }
3212
3213 public BatchConjunction on( Property idProperty ) {
3214 return on(Location.create(idProperty));
3215 }
3216
3217 public BatchConjunction on( Property firstIdProperty,
3218 Property... additionalIdProperties ) {
3219 return on(Location.create(firstIdProperty, additionalIdProperties));
3220 }
3221
3222 public BatchConjunction on( Iterable<Property> idProperties ) {
3223 return on(Location.create(idProperties));
3224 }
3225
3226 public BatchConjunction on( UUID uuid ) {
3227 return on(Location.create(uuid));
3228 }
3229 };
3230 }
3231
3232 /**
3233 * Request to read the node with the supplied UUID.
3234 * <p>
3235 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3236 * called.
3237 * </p>
3238 *
3239 * @param uuid the UUID of the node that is to be read
3240 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3241 */
3242 public BatchConjunction read( UUID uuid ) {
3243 return read(Location.create(uuid));
3244 }
3245
3246 /**
3247 * Request to read the node at the supplied location.
3248 * <p>
3249 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3250 * called.
3251 * </p>
3252 *
3253 * @param location the location of the node that is to be read
3254 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3255 */
3256 public BatchConjunction read( Location location ) {
3257 assertNotExecuted();
3258 requestQueue.readNode(location, getCurrentWorkspaceName());
3259 return nextRequests;
3260 }
3261
3262 /**
3263 * Request to read the node at the supplied path.
3264 * <p>
3265 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3266 * called.
3267 * </p>
3268 *
3269 * @param path the path of the node that is to be read
3270 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3271 */
3272 public BatchConjunction read( String path ) {
3273 return read(Location.create(createPath(path)));
3274 }
3275
3276 /**
3277 * Request to read the node at the supplied path.
3278 * <p>
3279 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3280 * called.
3281 * </p>
3282 *
3283 * @param path the path of the node that is to be read
3284 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3285 */
3286 public BatchConjunction read( Path path ) {
3287 return read(Location.create(path));
3288 }
3289
3290 /**
3291 * Request to read the node with the supplied unique identifier property.
3292 * <p>
3293 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3294 * called.
3295 * </p>
3296 *
3297 * @param idProperty the identification property that is unique to the node that is to be read
3298 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3299 */
3300 public BatchConjunction read( Property idProperty ) {
3301 return read(Location.create(idProperty));
3302 }
3303
3304 /**
3305 * Request to read the node with the supplied unique identifier properties.
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 firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
3312 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be
3313 * read
3314 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3315 */
3316 public BatchConjunction read( Property firstIdProperty,
3317 Property... additionalIdProperties ) {
3318 return read(Location.create(firstIdProperty, additionalIdProperties));
3319 }
3320
3321 /**
3322 * Request to read the node with the supplied unique identifier properties.
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 idProperties the identification properties that uniquely identify the node that is to be read
3329 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
3330 */
3331 public BatchConjunction read( Iterable<Property> idProperties ) {
3332 return read(Location.create(idProperties));
3333 }
3334
3335 /**
3336 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
3337 * returned {@link On} object.
3338 * <p>
3339 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3340 * called.
3341 * </p>
3342 *
3343 * @param propertyName the name of the property that is to be read
3344 * @return the object that is used to specified the node whose property is to be read
3345 */
3346 public On<BatchConjunction> readProperty( String propertyName ) {
3347 assertNotExecuted();
3348 Name name = Graph.this.getContext().getValueFactories().getNameFactory().create(propertyName);
3349 return readProperty(name);
3350 }
3351
3352 /**
3353 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
3354 * returned {@link On} object.
3355 * <p>
3356 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3357 * called.
3358 * </p>
3359 *
3360 * @param name the name of the property that is to be read
3361 * @return the object that is used to specified the node whose property is to be read
3362 */
3363 public On<BatchConjunction> readProperty( final Name name ) {
3364 assertNotExecuted();
3365 return new On<BatchConjunction>() {
3366 public BatchConjunction on( String path ) {
3367 return on(Location.create(createPath(path)));
3368 }
3369
3370 public BatchConjunction on( Path path ) {
3371 return on(Location.create(path));
3372 }
3373
3374 public BatchConjunction on( Property idProperty ) {
3375 return on(Location.create(idProperty));
3376 }
3377
3378 public BatchConjunction on( Property firstIdProperty,
3379 Property... additionalIdProperties ) {
3380 return on(Location.create(firstIdProperty, additionalIdProperties));
3381 }
3382
3383 public BatchConjunction on( Iterable<Property> idProperties ) {
3384 return on(Location.create(idProperties));
3385 }
3386
3387 public BatchConjunction on( UUID uuid ) {
3388 return on(Location.create(uuid));
3389 }
3390
3391 public BatchConjunction on( Location at ) {
3392 requestQueue.readProperty(at, getCurrentWorkspaceName(), name);
3393 return Batch.this.nextRequests;
3394 }
3395 };
3396 }
3397
3398 /**
3399 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
3400 * object.
3401 * <p>
3402 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3403 * called.
3404 * </p>
3405 *
3406 * @return the object that is used to specified the node whose properties are to be read,
3407 */
3408 public On<BatchConjunction> readProperties() {
3409 assertNotExecuted();
3410 return new On<BatchConjunction>() {
3411 public BatchConjunction on( Location location ) {
3412 requestQueue.readAllProperties(location, getCurrentWorkspaceName());
3413 return Batch.this.nextRequests;
3414 }
3415
3416 public BatchConjunction on( String path ) {
3417 return on(Location.create(createPath(path)));
3418 }
3419
3420 public BatchConjunction on( Path path ) {
3421 return on(Location.create(path));
3422 }
3423
3424 public BatchConjunction on( Property idProperty ) {
3425 return on(Location.create(idProperty));
3426 }
3427
3428 public BatchConjunction on( Property firstIdProperty,
3429 Property... additionalIdProperties ) {
3430 return on(Location.create(firstIdProperty, additionalIdProperties));
3431 }
3432
3433 public BatchConjunction on( Iterable<Property> idProperties ) {
3434 return on(Location.create(idProperties));
3435 }
3436
3437 public BatchConjunction on( UUID uuid ) {
3438 return on(Location.create(uuid));
3439 }
3440 };
3441 }
3442
3443 /**
3444 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
3445 * object.
3446 * <p>
3447 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3448 * called.
3449 * </p>
3450 *
3451 * @return the object that is used to specified the node whose children are to be read
3452 */
3453 public Of<BatchConjunction> readChildren() {
3454 assertNotExecuted();
3455 return new Of<BatchConjunction>() {
3456 public BatchConjunction of( String path ) {
3457 return of(Location.create(createPath(path)));
3458 }
3459
3460 public BatchConjunction of( Path path ) {
3461 return of(Location.create(path));
3462 }
3463
3464 public BatchConjunction of( Property idProperty ) {
3465 return of(Location.create(idProperty));
3466 }
3467
3468 public BatchConjunction of( Property firstIdProperty,
3469 Property... additionalIdProperties ) {
3470 return of(Location.create(firstIdProperty, additionalIdProperties));
3471 }
3472
3473 public BatchConjunction of( Iterable<Property> idProperties ) {
3474 return of(Location.create(idProperties));
3475 }
3476
3477 public BatchConjunction of( UUID uuid ) {
3478 return of(Location.create(uuid));
3479 }
3480
3481 public BatchConjunction of( Location at ) {
3482 requestQueue.readAllChildren(at, getCurrentWorkspaceName());
3483 return Batch.this.nextRequests;
3484 }
3485 };
3486 }
3487
3488 /**
3489 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code>
3490 * in the resulting {@link At} object.
3491 * <p>
3492 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
3493 * called.
3494 * </p>
3495 *
3496 * @param depth the maximum depth of the subgraph that should be read
3497 * @return the component that should be used to specify the location of the node that is the top of the subgraph
3498 */
3499 public At<BatchConjunction> readSubgraphOfDepth( final int depth ) {
3500 assertNotExecuted();
3501 return new At<BatchConjunction>() {
3502 public BatchConjunction at( Location location ) {
3503 requestQueue.readBranch(location, getCurrentWorkspaceName());
3504 return Batch.this.nextRequests;
3505 }
3506
3507 public BatchConjunction at( String path ) {
3508 return at(Location.create(createPath(path)));
3509 }
3510
3511 public BatchConjunction at( Path path ) {
3512 return at(Location.create(path));
3513 }
3514
3515 public BatchConjunction at( UUID uuid ) {
3516 return at(Location.create(uuid));
3517 }
3518
3519 public BatchConjunction at( Property idProperty ) {
3520 return at(Location.create(idProperty));
3521 }
3522
3523 public BatchConjunction at( Property firstIdProperty,
3524 Property... additionalIdProperties ) {
3525 return at(Location.create(firstIdProperty, additionalIdProperties));
3526 }
3527
3528 public BatchConjunction at( Iterable<Property> idProperties ) {
3529 return at(Location.create(idProperties));
3530 }
3531 };
3532 }
3533
3534 /**
3535 * {@inheritDoc}
3536 *
3537 * @see org.jboss.dna.graph.Graph.Executable#execute()
3538 */
3539 public Results execute() {
3540 executed = true;
3541 Request request = requestQueue.pop();
3542 if (request == null) {
3543 return new BatchResults();
3544 }
3545 Graph.this.execute(request);
3546 if (request instanceof CompositeRequest) {
3547 CompositeRequest composite = (CompositeRequest)request;
3548 return new BatchResults(composite.getRequests());
3549 }
3550 return new BatchResults(request);
3551 }
3552
3553 /**
3554 * {@inheritDoc}
3555 *
3556 * @see java.lang.Object#toString()
3557 */
3558 @Override
3559 public String toString() {
3560 StringBuilder sb = new StringBuilder();
3561 sb.append("Pending requests:\n");
3562 sb.append(requestQueue.toString());
3563 return sb.toString();
3564 }
3565 }
3566
3567 /**
3568 * Utility method for checking a property value. If the value is a {@link Node} or {@link Location}, a {@link Reference} value
3569 * is created (if the node/location has a UUID); otherwise, the value is returned as is.
3570 *
3571 * @param value the property value
3572 * @return the property value, which may be a {@link Reference} if the input value is a Node or Location
3573 */
3574 protected Object convertReferenceValue( Object value ) {
3575 if (value instanceof Node) {
3576 Node node = (Node)value;
3577 UUID uuid = node.getLocation().getUuid();
3578 if (uuid == null) {
3579 // Look for a property ...
3580 Property uuidProperty = node.getProperty(DnaLexicon.UUID);
3581 if (uuidProperty != null) {
3582 uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
3583 } else {
3584 uuidProperty = node.getProperty(JcrLexicon.UUID);
3585 if (uuidProperty != null) {
3586 uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
3587 }
3588 }
3589 }
3590 if (uuid == null) {
3591 String nodeString = node.getLocation().getString(getContext().getNamespaceRegistry());
3592 String msg = GraphI18n.unableToCreateReferenceToNodeWithoutUuid.text(nodeString);
3593 throw new IllegalArgumentException(msg);
3594 }
3595 return getContext().getValueFactories().getReferenceFactory().create(uuid);
3596 }
3597 if (value instanceof Location) {
3598 Location location = (Location)value;
3599 UUID uuid = location.getUuid();
3600 if (uuid == null) {
3601 String nodeString = location.getString(getContext().getNamespaceRegistry());
3602 String msg = GraphI18n.unableToCreateReferenceToNodeWithoutUuid.text(nodeString);
3603 throw new IllegalArgumentException(msg);
3604 }
3605 return getContext().getValueFactories().getReferenceFactory().create(uuid);
3606 }
3607 return value;
3608 }
3609
3610 /**
3611 * The interface used to specify the name of a new workspace.
3612 */
3613 public interface NameWorkspace {
3614
3615 /**
3616 * Specify the name of the new workspace that is to be created.
3617 *
3618 * @param workspaceName the name of the existing workspace that will be cloned to create the new workspace;
3619 * @return the workspace; never null
3620 * @throws IllegalArgumentException if the name of the new workspace is null
3621 * @throws InvalidWorkspaceException if there is already an existing workspace with the supplied name
3622 */
3623 Workspace named( String workspaceName );
3624
3625 /**
3626 * Specify the name of the new workspace that is to be created. If a workspace with the supplied name already exists, the
3627 * new workspace name will be adjusted so that it is unique.
3628 *
3629 * @param workspaceName the name of the existing workspace that will be cloned to create the new workspace;
3630 * @return the workspace; never null
3631 * @throws IllegalArgumentException if the name of the new workspace is null
3632 */
3633 Workspace namedSomethingLike( String workspaceName );
3634 }
3635
3636 /**
3637 * The interface used to create a new workspace.
3638 */
3639 public interface CreateWorkspace extends NameWorkspace {
3640 /**
3641 * Specify that the new workspace should be initialized as a clone of another existing workspace.
3642 *
3643 * @param originalWorkspaceName the name of the existing workspace that will be cloned to create the new workspace;
3644 * @return the interface that should be used to set the name of the new workspace; never null
3645 * @throws IllegalArgumentException if the name of the original workspace is null
3646 * @throws InvalidWorkspaceException if there is no such workspace with the supplied name
3647 */
3648 NameWorkspace clonedFrom( String originalWorkspaceName );
3649 }
3650
3651 /**
3652 * A interface used to execute the accumulated {@link Batch requests}.
3653 *
3654 * @author Randall Hauch
3655 * @param <NodeType> the type of node that is returned
3656 */
3657 public interface Executable<NodeType extends Node> {
3658 /**
3659 * Stop accumulating the requests, submit them to the repository source, and return the results.
3660 *
3661 * @return the results containing the requested information from the repository.
3662 * @throws PathNotFoundException if a request used a node that did not exist
3663 * @throws InvalidRequestException if a request was not valid
3664 * @throws InvalidWorkspaceException if the workspace used in a request was not valid
3665 * @throws UnsupportedRequestException if a request was not supported by the source
3666 * @throws RepositorySourceException if an error occurs during execution
3667 * @throws RuntimeException if a runtime error occurs during execution
3668 */
3669 Results execute();
3670 }
3671
3672 /**
3673 * A interface that can be used to finish the current request and start another.
3674 *
3675 * @param <Next> the interface that will be used to start another request
3676 * @author Randall Hauch
3677 */
3678 public interface Conjunction<Next> {
3679 /**
3680 * Finish the request and prepare to start another.
3681 *
3682 * @return the interface that can be used to start another request; never null
3683 */
3684 Next and();
3685 }
3686
3687 /**
3688 * A component that defines the location into which a node should be copied or moved.
3689 *
3690 * @param <Next> The interface that is to be returned when this request is completed
3691 * @author Randall Hauch
3692 */
3693 public interface Into<Next> {
3694 /**
3695 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3696 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3697 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3698 * {@link To#to(Location)} instead.
3699 *
3700 * @param parentLocation the location of the new parent
3701 * @return the interface for additional requests or actions
3702 * @see To#to(Location)
3703 */
3704 Next into( Location parentLocation );
3705
3706 /**
3707 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3708 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3709 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3710 * {@link To#to(String)} instead.
3711 *
3712 * @param parentPath the path of the new parent
3713 * @return the interface for additional requests or actions
3714 * @see To#to(String)
3715 */
3716 Next into( String parentPath );
3717
3718 /**
3719 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3720 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3721 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3722 * {@link To#to(Path)} instead.
3723 *
3724 * @param parentPath the path of the new parent
3725 * @return the interface for additional requests or actions
3726 * @see To#to(Path)
3727 */
3728 Next into( Path parentPath );
3729
3730 /**
3731 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3732 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3733 * same-name-sibling index).
3734 *
3735 * @param parentUuid the UUID of the new parent
3736 * @return the interface for additional requests or actions
3737 */
3738 Next into( UUID parentUuid );
3739
3740 /**
3741 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3742 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3743 * same-name-sibling index).
3744 *
3745 * @param parentIdProperty the property that uniquely identifies the new parent
3746 * @return the interface for additional requests or actions
3747 */
3748 Next into( Property parentIdProperty );
3749
3750 /**
3751 * Finish the request by specifying the location of the parent into which the node should be copied/moved. This operation
3752 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3753 * same-name-sibling index).
3754 *
3755 * @param firstParentIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies
3756 * the new parent
3757 * @param additionalParentIdProperties the additional properties that, with the <code>additionalIdProperties</code>,
3758 * uniquely identifies the new parent
3759 * @return the interface for additional requests or actions
3760 */
3761 Next into( Property firstParentIdProperty,
3762 Property... additionalParentIdProperties );
3763 }
3764
3765 /**
3766 * A component that defines the location before which a node should be copied or moved. This is similar to an {@link Into},
3767 * but it allows for placing a node at a particular location within the new destination, rather than always placing the moved
3768 * or copied node as the last child of the new parent.
3769 *
3770 * @param <Next> The interface that is to be returned when this request is completed
3771 * @author Randall Hauch
3772 */
3773 public interface Before<Next> {
3774 /**
3775 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3776 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3777 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3778 * {@link To#to(Location)} instead.
3779 *
3780 * @param parentLocation the location of the new parent
3781 * @return the interface for additional requests or actions
3782 * @see To#to(Location)
3783 */
3784 Next before( Location parentLocation );
3785
3786 /**
3787 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3788 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3789 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3790 * {@link To#to(String)} instead.
3791 *
3792 * @param parentPath the path of the new parent
3793 * @return the interface for additional requests or actions
3794 * @see To#to(String)
3795 */
3796 Next before( String parentPath );
3797
3798 /**
3799 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3800 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3801 * same-name-sibling index). If you want to control the name of the node for the newly copied/moved node, use
3802 * {@link To#to(Path)} instead.
3803 *
3804 * @param parentPath the path of the new parent
3805 * @return the interface for additional requests or actions
3806 * @see To#to(Path)
3807 */
3808 Next before( Path parentPath );
3809
3810 /**
3811 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3812 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3813 * same-name-sibling index).
3814 *
3815 * @param parentUuid the UUID of the new parent
3816 * @return the interface for additional requests or actions
3817 */
3818 Next before( UUID parentUuid );
3819
3820 /**
3821 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3822 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3823 * same-name-sibling index).
3824 *
3825 * @param parentIdProperty the property that uniquely identifies the new parent
3826 * @return the interface for additional requests or actions
3827 */
3828 Next before( Property parentIdProperty );
3829
3830 /**
3831 * Finish the request by specifying the location of the node before which the node should be copied/moved. This operation
3832 * will result in the copied/moved node having the same name as the original (but with the appropriately-determined
3833 * same-name-sibling index).
3834 *
3835 * @param firstParentIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies
3836 * the new parent
3837 * @param additionalParentIdProperties the additional properties that, with the <code>additionalIdProperties</code>,
3838 * uniquely identifies the new parent
3839 * @return the interface for additional requests or actions
3840 */
3841 Next before( Property firstParentIdProperty,
3842 Property... additionalParentIdProperties );
3843 }
3844
3845 /**
3846 * A component that defines the location to which a node should be copied or moved.
3847 *
3848 * @param <Next> The interface that is to be returned when this request is completed
3849 * @author Randall Hauch
3850 */
3851 public interface To<Next> {
3852 /**
3853 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
3854 * {@link Into#into(Location)}, which specifies the location of the parent and which assumes the new node should have the
3855 * same name as the original, this method allows the caller to specify a new name for the new node.
3856 *
3857 * @param desiredLocation the desired location for the new node, which must have a {@link Location#getPath() path}
3858 * @return the interface for additional requests or actions
3859 * @see Into#into(Location)
3860 */
3861 Next to( Location desiredLocation );
3862
3863 /**
3864 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
3865 * {@link Into#into(String)}, which specifies the location of the parent and which assumes the new node should have the
3866 * same name as the original, this method allows the caller to specify a new name for the new node.
3867 *
3868 * @param desiredPath the path for the new node
3869 * @return the interface for additional requests or actions
3870 * @see Into#into(String)
3871 */
3872 Next to( String desiredPath );
3873
3874 /**
3875 * Finish the request by specifying the Location.create where the node should be copied/moved. Unlike
3876 * {@link Into#into(Path)} , which specifies the location of the parent and which assumes the new node should have the
3877 * same name as the original, this method allows the caller to specify a new name for the new node.
3878 *
3879 * @param desiredPath the path for the new node
3880 * @return the interface for additional requests or actions
3881 * @see Into#into(Path)
3882 */
3883 Next to( Path desiredPath );
3884 }
3885
3886 /**
3887 * A component that defines a new name for a node.
3888 *
3889 * @param <Next> The interface that is to be returned when this request is completed
3890 * @author Randall Hauch
3891 */
3892 public interface AsName<Next> {
3893 /**
3894 * Finish the request by specifying the new name.
3895 *
3896 * @param newName the new name
3897 * @return the interface for additional requests or actions
3898 */
3899 Next as( String newName );
3900
3901 /**
3902 * Finish the request by specifying the new name.
3903 *
3904 * @param newName the new name
3905 * @return the interface for additional requests or actions
3906 */
3907 Next as( Name newName );
3908 }
3909
3910 /**
3911 * A interface that is used to add more locations that are to be copied/moved.
3912 *
3913 * @param <Next> The interface that is to be returned when this request is completed
3914 * @author Randall Hauch
3915 */
3916 public interface And<Next> {
3917 /**
3918 * Specify that another node should also be copied or moved.
3919 *
3920 * @param from the location of the node to be copied or moved
3921 * @return the interface for finishing the request
3922 */
3923 Next and( Location from );
3924
3925 /**
3926 * Specify that another node should also be copied or moved.
3927 *
3928 * @param fromPath the path of the node to be copied or moved
3929 * @return the interface for finishing the request
3930 */
3931 Next and( String fromPath );
3932
3933 /**
3934 * Specify that another node should also be copied or moved.
3935 *
3936 * @param from the path of the node to be copied or moved
3937 * @return the interface for finishing the request
3938 */
3939 Next and( Path from );
3940
3941 /**
3942 * Specify that another node should also be copied or moved.
3943 *
3944 * @param from the UUID of the node to be copied or moved
3945 * @return the interface for finishing the request
3946 */
3947 Next and( UUID from );
3948
3949 /**
3950 * Specify that another node should also be copied or moved.
3951 *
3952 * @param idProperty the property that uniquely identifies the node to be copied or moved
3953 * @return the interface for finishing the request
3954 */
3955 Next and( Property idProperty );
3956
3957 /**
3958 * Specify that another node should also be copied or moved.
3959 *
3960 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
3961 * node to be copied or moved
3962 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
3963 * identifies the node to be copied or moved
3964 * @return the interface for finishing the request
3965 */
3966 Next and( Property firstIdProperty,
3967 Property... additionalIdProperties );
3968
3969 /**
3970 * Specify that another node should also be copied or moved.
3971 *
3972 * @param idProperties the properties that uniquely identifies the node to be copied or moved
3973 * @return the interface for finishing the request
3974 */
3975 Next and( Iterable<Property> idProperties );
3976 }
3977
3978 /**
3979 * The interface for defining additional nodes to be moved and the parent into which the node(s) are to be moved.
3980 *
3981 * @param <Next> The interface that is to be returned when this request is completed
3982 * @author Randall Hauch
3983 */
3984 public interface Move<Next> extends AsName<Into<Next>>, Into<Next>, Before<Next>, And<Move<Next>> {
3985 }
3986
3987 /**
3988 * The interface for defining additional nodes to be copied and the locations where the copy is to be placed. The
3989 * <code>to(...)</code> methods allow you to specify the location of the copy, including the name for the node that results
3990 * from the copy. Alternatively, you can use the <code>into(...)</code> methods to specify the parent location where the copy
3991 * is to be placed, which will assume the new copy will have the same name as the original.
3992 *
3993 * @param <Next> The interface that is to be returned when this request is completed
3994 * @author Randall Hauch
3995 */
3996 public interface Copy<Next> extends To<Next>, Into<Next>, And<Copy<Next>> {
3997 }
3998
3999 /**
4000 * The interface for defining additional properties on a new node.
4001 *
4002 * @param <Next> The interface that is to be returned when this create request is completed
4003 * @author Randall Hauch
4004 */
4005 public interface Create<Next> extends Conjunction<Next>, Executable<Node> {
4006 /**
4007 * Create the node only if there is no existing node with the same {@link Path.Segment#getName() name} (ignoring
4008 * {@link Path.Segment#getIndex() same-name-sibling indexes}).
4009 *
4010 * @return this interface for continued specification of the request
4011 */
4012 Create<Next> ifAbsent();
4013
4014 /**
4015 * Create the node if it does not exist, or update any existing node that has the same {@link Path.Segment#getName() name}
4016 * (ignoring {@link Path.Segment#getIndex() same-name-sibling indexes}).
4017 *
4018 * @return this interface for continued specification of the request
4019 */
4020 Create<Next> orUpdate();
4021
4022 /**
4023 * Create the node if it does not exist, or replace any existing node that has the same {@link Path.Segment#getName()
4024 * name} (ignoring {@link Path.Segment#getIndex() same-name-sibling indexes}).
4025 *
4026 * @return this interface for continued specification of the request
4027 */
4028 Create<Next> orReplace();
4029
4030 /**
4031 * Create the node if it does not exist by appending or adjusting the {@link Path.Segment#getIndex() same-name-sibling
4032 * index}). This is the default behavior.
4033 *
4034 * @return this interface for continued specification of the request
4035 */
4036 Create<Next> byAppending();
4037
4038 /**
4039 * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
4040 *
4041 * @param uuid the UUID
4042 * @return this same interface so additional properties may be added
4043 */
4044 Create<Next> with( UUID uuid );
4045
4046 /**
4047 * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
4048 *
4049 * @param property the property
4050 * @return this same interface so additional properties may be added
4051 */
4052 Create<Next> with( Property property );
4053
4054 /**
4055 * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
4056 *
4057 * @param properties the properties that should be added
4058 * @return this same interface so additional properties may be added
4059 */
4060 Create<Next> with( Iterable<Property> properties );
4061
4062 /**
4063 * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
4064 *
4065 * @param propertyName the name of the property
4066 * @param values the property values
4067 * @return this same interface so additional properties may be added
4068 */
4069 Create<Next> with( String propertyName,
4070 Object... values );
4071
4072 /**
4073 * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
4074 *
4075 * @param propertyName the name of the property
4076 * @param values the property values
4077 * @return this same interface so additional properties may be added
4078 */
4079 Create<Next> with( Name propertyName,
4080 Object... values );
4081
4082 /**
4083 * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
4084 *
4085 * @param firstProperty the first property
4086 * @param additionalProperties the additional property
4087 * @return this same interface so additional properties may be added
4088 */
4089 Create<Next> with( Property firstProperty,
4090 Property... additionalProperties );
4091
4092 /**
4093 * Specify the UUID that should the new node should have.
4094 *
4095 * @param uuid the UUID
4096 * @return this same interface so additional properties may be added
4097 */
4098 Create<Next> and( UUID uuid );
4099
4100 /**
4101 * Specify a property that should the new node should have.
4102 *
4103 * @param property the property
4104 * @return this same interface so additional properties may be added
4105 */
4106 Create<Next> and( Property property );
4107
4108 /**
4109 * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
4110 * the properties in the supplied {@link Iterable}.
4111 *
4112 * @param properties the properties that should be added
4113 * @return this same interface so additional properties may be added
4114 */
4115 Create<Next> and( Iterable<Property> properties );
4116
4117 /**
4118 * Specify a property that should the new node should have.
4119 *
4120 * @param propertyName the name of the property
4121 * @param values the property values
4122 * @return this same interface so additional properties may be added
4123 */
4124 Create<Next> and( String propertyName,
4125 Object... values );
4126
4127 /**
4128 * Specify a property that should the new node should have.
4129 *
4130 * @param propertyName the name of the property
4131 * @param values the property values
4132 * @return this same interface so additional properties may be added
4133 */
4134 Create<Next> and( Name propertyName,
4135 Object... values );
4136
4137 /**
4138 * Specify properties that should the new node should have.
4139 *
4140 * @param firstProperty the first property
4141 * @param additionalProperties the additional property
4142 * @return this same interface so additional properties may be added
4143 */
4144 Create<Next> and( Property firstProperty,
4145 Property... additionalProperties );
4146 }
4147
4148 /**
4149 * The interface for defining additional properties on a new node.
4150 *
4151 * @param <Next> The interface that is to be returned when this create request is completed
4152 * @author Randall Hauch
4153 */
4154 public interface CreateAt<Next> extends Conjunction<Next> {
4155 /**
4156 * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
4157 *
4158 * @param uuid the UUID
4159 * @return this same interface so additional properties may be added
4160 */
4161 CreateAt<Next> with( UUID uuid );
4162
4163 /**
4164 * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
4165 *
4166 * @param property the property
4167 * @return this same interface so additional properties may be added
4168 */
4169 CreateAt<Next> with( Property property );
4170
4171 /**
4172 * Specify property that should the new node should have. This is an alias for {@link #and(Iterable)}.
4173 *
4174 * @param properties the properties that should be added
4175 * @return this same interface so additional properties may be added
4176 */
4177 CreateAt<Next> with( Iterable<Property> properties );
4178
4179 /**
4180 * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
4181 *
4182 * @param propertyName the name of the property
4183 * @param values the property values
4184 * @return this same interface so additional properties may be added
4185 */
4186 CreateAt<Next> with( String propertyName,
4187 Object... values );
4188
4189 /**
4190 * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
4191 *
4192 * @param propertyName the name of the property
4193 * @param values the property values
4194 * @return this same interface so additional properties may be added
4195 */
4196 CreateAt<Next> with( Name propertyName,
4197 Object... values );
4198
4199 /**
4200 * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
4201 *
4202 * @param firstProperty the first property
4203 * @param additionalProperties the additional property
4204 * @return this same interface so additional properties may be added
4205 */
4206 CreateAt<Next> with( Property firstProperty,
4207 Property... additionalProperties );
4208
4209 /**
4210 * Specify the UUID that should the new node should have.
4211 *
4212 * @param uuid the UUID
4213 * @return this same interface so additional properties may be added
4214 */
4215 CreateAt<Next> and( UUID uuid );
4216
4217 /**
4218 * Specify a property that should the new node should have.
4219 *
4220 * @param property the property
4221 * @return this same interface so additional properties may be added
4222 */
4223 CreateAt<Next> and( Property property );
4224
4225 /**
4226 * Specify property that should the new node should have. This is equivalent to calling {@link #and(Property)} for each of
4227 * the properties in the supplied {@link Iterable}.
4228 *
4229 * @param properties the properties that should be added
4230 * @return this same interface so additional properties may be added
4231 */
4232 CreateAt<Next> and( Iterable<Property> properties );
4233
4234 /**
4235 * Specify a property that should the new node should have.
4236 *
4237 * @param propertyName the name of the property
4238 * @param values the property values
4239 * @return this same interface so additional properties may be added
4240 */
4241 CreateAt<Next> and( String propertyName,
4242 Object... values );
4243
4244 /**
4245 * Specify a property that should the new node should have.
4246 *
4247 * @param propertyName the name of the property
4248 * @param values the property values
4249 * @return this same interface so additional properties may be added
4250 */
4251 CreateAt<Next> and( Name propertyName,
4252 Object... values );
4253
4254 /**
4255 * Specify properties that should the new node should have.
4256 *
4257 * @param firstProperty the first property
4258 * @param additionalProperties the additional property
4259 * @return this same interface so additional properties may be added
4260 */
4261 CreateAt<Next> and( Property firstProperty,
4262 Property... additionalProperties );
4263
4264 /**
4265 * Complete this request, submit it, and return the actual location of the created node.
4266 *
4267 * @return the actual location of the just-created node; never null
4268 */
4269 Location getLocation();
4270
4271 /**
4272 * Complete this request, submit it, and return the actual node that was created.
4273 *
4274 * @return the actual node that was just created; never null
4275 */
4276 Node getNode();
4277 }
4278
4279 /**
4280 * The interface for defining the node upon which a request operates.
4281 *
4282 * @param <Next> The interface that is to be returned when the request is completed
4283 * @author Randall Hauch
4284 */
4285 public interface On<Next> {
4286 /**
4287 * Specify the location of the node upon which the request is to operate.
4288 *
4289 * @param to the location of the new parent
4290 * @return the interface for additional requests or actions
4291 */
4292 Next on( Location to );
4293
4294 /**
4295 * Specify the path of the node upon which the request is to operate.
4296 *
4297 * @param toPath the path of the new parent
4298 * @return the interface for additional requests or actions
4299 */
4300 Next on( String toPath );
4301
4302 /**
4303 * Specify the path of the node upon which the request is to operate.
4304 *
4305 * @param to the path of the new parent
4306 * @return the interface for additional requests or actions
4307 */
4308 Next on( Path to );
4309
4310 /**
4311 * Specify the UUID of the node upon which the request is to operate.
4312 *
4313 * @param to the UUID of the new parent
4314 * @return the interface for additional requests or actions
4315 */
4316 Next on( UUID to );
4317
4318 /**
4319 * Specify the unique identification property that identifies the node upon which the request is to operate.
4320 *
4321 * @param idProperty the property that uniquely identifies the new parent
4322 * @return the interface for additional requests or actions
4323 */
4324 Next on( Property idProperty );
4325
4326 /**
4327 * Specify the unique identification properties that identify the node upon which the request is to operate.
4328 *
4329 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
4330 * new parent
4331 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
4332 * identifies the new parent
4333 * @return the interface for additional requests or actions
4334 */
4335 Next on( Property firstIdProperty,
4336 Property... additionalIdProperties );
4337
4338 /**
4339 * Specify the unique identification properties that identify the node upon which the request is to operate.
4340 *
4341 * @param idProperties the properties that uniquely identifies the new parent
4342 * @return the interface for additional requests or actions
4343 */
4344 Next on( Iterable<Property> idProperties );
4345 }
4346
4347 /**
4348 * The interface for defining the node upon which a request operates.
4349 *
4350 * @param <Next> The interface that is to be returned when the request is completed
4351 * @author Randall Hauch
4352 */
4353 public interface Of<Next> {
4354 /**
4355 * Specify the location of the node upon which the request is to operate.
4356 *
4357 * @param to the location of the new parent
4358 * @return the interface for additional requests or actions
4359 */
4360 Next of( Location to );
4361
4362 /**
4363 * Specify the path of the node upon which the request is to operate.
4364 *
4365 * @param toPath the path of the new parent
4366 * @return the interface for additional requests or actions
4367 */
4368 Next of( String toPath );
4369
4370 /**
4371 * Specify the path of the node upon which the request is to operate.
4372 *
4373 * @param to the path of the new parent
4374 * @return the interface for additional requests or actions
4375 */
4376 Next of( Path to );
4377
4378 /**
4379 * Specify the UUID of the node upon which the request is to operate.
4380 *
4381 * @param to the UUID of the new parent
4382 * @return the interface for additional requests or actions
4383 */
4384 Next of( UUID to );
4385
4386 /**
4387 * Specify the unique identification property that identifies the node upon which the request is to operate.
4388 *
4389 * @param idProperty the property that uniquely identifies the new parent
4390 * @return the interface for additional requests or actions
4391 */
4392 Next of( Property idProperty );
4393
4394 /**
4395 * Specify the unique identification properties that identify the node upon which the request is to operate.
4396 *
4397 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
4398 * new parent
4399 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
4400 * identifies the new parent
4401 * @return the interface for additional requests or actions
4402 */
4403 Next of( Property firstIdProperty,
4404 Property... additionalIdProperties );
4405
4406 /**
4407 * Specify the unique identification properties that identify the node upon which the request is to operate.
4408 *
4409 * @param idProperties the properties that uniquely identifies the new parent
4410 * @return the interface for additional requests or actions
4411 */
4412 Next of( Iterable<Property> idProperties );
4413 }
4414
4415 /**
4416 * The interface for defining the node upon which which a request operates.
4417 *
4418 * @param <Next> The interface that is to be returned when the request is completed
4419 * @author Randall Hauch
4420 */
4421 public interface At<Next> {
4422 /**
4423 * Specify the location of the node upon which the request is to operate.
4424 *
4425 * @param to the location of the new parent
4426 * @return the interface for additional requests or actions
4427 */
4428 Next at( Location to );
4429
4430 /**
4431 * Specify the path of the node upon which the request is to operate.
4432 *
4433 * @param toPath the path of the new parent
4434 * @return the interface for additional requests or actions
4435 */
4436 Next at( String toPath );
4437
4438 /**
4439 * Specify the path of the node upon which the request is to operate.
4440 *
4441 * @param to the path of the new parent
4442 * @return the interface for additional requests or actions
4443 */
4444 Next at( Path to );
4445
4446 /**
4447 * Specify the UUID of the node upon which the request is to operate.
4448 *
4449 * @param to the UUID of the new parent
4450 * @return the interface for additional requests or actions
4451 */
4452 Next at( UUID to );
4453
4454 /**
4455 * Specify the unique identification property that identifies the node upon which the request is to operate.
4456 *
4457 * @param idProperty the property that uniquely identifies the new parent
4458 * @return the interface for additional requests or actions
4459 */
4460 Next at( Property idProperty );
4461
4462 /**
4463 * Specify the unique identification properties that identify the node upon which the request is to operate.
4464 *
4465 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
4466 * new parent
4467 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
4468 * identifies the new parent
4469 * @return the interface for additional requests or actions
4470 */
4471 Next at( Property firstIdProperty,
4472 Property... additionalIdProperties );
4473
4474 /**
4475 * Specify the unique identification properties that identify the node upon which the request is to operate.
4476 *
4477 * @param idProperties the properties that uniquely identifies the new parent
4478 * @return the interface for additional requests or actions
4479 */
4480 Next at( Iterable<Property> idProperties );
4481 }
4482
4483 /**
4484 * A component used to supply the details for getting children of another node. If all of the children are to be obtained,
4485 * then the parent can be specified using one of the <code>of(...)</code> methods on this component. If, however, only some of
4486 * the nodes are to be returned (e.g., a "block" of children), then specify the {@link #inBlockOf(int) block size} followed by
4487 * the {@link BlockOfChildren block size and parent}.
4488 *
4489 * @param <Next>
4490 * @author Randall Hauch
4491 */
4492 public interface Children<Next> extends Of<Next> {
4493 /**
4494 * Specify that a block of children are to be retreived, and in particular the number of children that are to be returned.
4495 *
4496 * @param blockSize the number of children that are to be retrieved in the block; must be positive
4497 * @return the interface used to specify the starting point for the block and the parent
4498 */
4499 BlockOfChildren<Next> inBlockOf( int blockSize );
4500 }
4501
4502 /**
4503 * A component used to specify a block of children starting either {@link #startingAt(int) at a particular index} or
4504 * {@link #startingAfter(Location) after a previous sibling}.
4505 *
4506 * @param <Next>
4507 * @author Randall Hauch
4508 */
4509 public interface BlockOfChildren<Next> {
4510 /**
4511 * Specify the block of children is to start at the supplied index.
4512 *
4513 * @param startingIndex the zero-based index of the first child to be returned in the block
4514 * @return interface used to specify the parent of the children; never null
4515 */
4516 Under<Next> startingAt( int startingIndex );
4517
4518 /**
4519 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4520 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4521 * block.
4522 *
4523 * @param previousSibling the location of the sibling node that is before the first node in the block
4524 * @return the children; never null
4525 */
4526 Next startingAfter( Location previousSibling );
4527
4528 /**
4529 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4530 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4531 * block.
4532 *
4533 * @param pathToPreviousSiblingName the path of the sibling node that is before the first node in the block
4534 * @return the children; never null
4535 */
4536 Next startingAfter( String pathToPreviousSiblingName );
4537
4538 /**
4539 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4540 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4541 * block.
4542 *
4543 * @param previousSibling the path of the sibling node that is before the first node in the block
4544 * @return the children; never null
4545 */
4546 Next startingAfter( Path previousSibling );
4547
4548 /**
4549 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4550 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4551 * block.
4552 *
4553 * @param previousSiblingUuid the UUID of the sibling node that is before the first node in the block
4554 * @return the children; never null
4555 */
4556 Next startingAfter( UUID previousSiblingUuid );
4557
4558 /**
4559 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4560 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4561 * block.
4562 *
4563 * @param idPropertyOfPreviousSibling the property that uniquely identifies the previous sibling
4564 * @return the children; never null
4565 */
4566 Next startingAfter( Property idPropertyOfPreviousSibling );
4567
4568 /**
4569 * Specify the block of children is to start with the child immediately following the supplied node. This method is
4570 * typically used when a previous block of children has already been retrieved and this request is retrieving the next
4571 * block.
4572 *
4573 * @param firstIdPropertyOfPreviousSibling the first property that, with the <code>additionalIdProperties</code>, uniquely
4574 * identifies the previous sibling
4575 * @param additionalIdPropertiesOfPreviousSibling the additional properties that, with the
4576 * <code>additionalIdProperties</code>, uniquely identifies the previous sibling
4577 * @return the children; never null
4578 */
4579 Next startingAfter( Property firstIdPropertyOfPreviousSibling,
4580 Property... additionalIdPropertiesOfPreviousSibling );
4581 }
4582
4583 /**
4584 * The interface for defining the node under which which a request operates.
4585 *
4586 * @param <Next> The interface that is to be returned when the request is completed
4587 * @author Randall Hauch
4588 */
4589 public interface Under<Next> {
4590 /**
4591 * Specify the location of the node under which the request is to operate.
4592 *
4593 * @param to the location of the new parent
4594 * @return the interface for additional requests or actions
4595 */
4596 Next under( Location to );
4597
4598 /**
4599 * Specify the path of the node under which the request is to operate.
4600 *
4601 * @param toPath the path of the new parent
4602 * @return the interface for additional requests or actions
4603 */
4604 Next under( String toPath );
4605
4606 /**
4607 * Specify the path of the node under which the request is to operate.
4608 *
4609 * @param to the path of the new parent
4610 * @return the interface for additional requests or actions
4611 */
4612 Next under( Path to );
4613
4614 /**
4615 * Specify the UUID of the node under which the request is to operate.
4616 *
4617 * @param to the UUID of the new parent
4618 * @return the interface for additional requests or actions
4619 */
4620 Next under( UUID to );
4621
4622 /**
4623 * Specify the unique identification property that identifies the node under which the request is to operate.
4624 *
4625 * @param idProperty the property that uniquely identifies the new parent
4626 * @return the interface for additional requests or actions
4627 */
4628 Next under( Property idProperty );
4629
4630 /**
4631 * Specify the unique identification properties that identify the node under which the request is to operate.
4632 *
4633 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
4634 * new parent
4635 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
4636 * identifies the new parent
4637 * @return the interface for additional requests or actions
4638 */
4639 Next under( Property firstIdProperty,
4640 Property... additionalIdProperties );
4641 }
4642
4643 /**
4644 * A component used to set the values on a property.
4645 *
4646 * @param <Next> the next command
4647 * @author Randall Hauch
4648 */
4649 public interface SetValues<Next> extends On<SetValuesTo<Next>>, SetValuesTo<On<Next>> {
4650 }
4651
4652 /**
4653 * A component used to set the values on a property.
4654 *
4655 * @param <Next>
4656 * @author Randall Hauch
4657 */
4658 public interface SetValuesTo<Next> {
4659
4660 /**
4661 * 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
4662 * {@link Location#getUuid() UUID}.
4663 *
4664 * @param node the node to which a reference should be set
4665 * @return the interface for additional requests or actions
4666 * @throws IllegalArgumentException if the value is a Node that has no {@link Location#getUuid() UUID}
4667 */
4668 Next to( Node node );
4669
4670 /**
4671 * Set the property value to be a reference to the given location. Note that it is an error if the Location does not have
4672 * a {@link Location#getUuid() UUID}.
4673 *
4674 * @param location the location to which a reference should be set
4675 * @return the interface for additional requests or actions
4676 * @throws IllegalArgumentException if the value is a Location that has no {@link Location#getUuid() UUID}
4677 */
4678 Next to( Location location );
4679
4680 /**
4681 * Set the property value to the given string.
4682 *
4683 * @param value the property value
4684 * @return the interface for additional requests or actions
4685 */
4686 Next to( String value );
4687
4688 /**
4689 * Set the property value to the given integer value.
4690 *
4691 * @param value the property value
4692 * @return the interface for additional requests or actions
4693 */
4694 Next to( int value );
4695
4696 /**
4697 * Set the property value to the given long value.
4698 *
4699 * @param value the property value
4700 * @return the interface for additional requests or actions
4701 */
4702 Next to( long value );
4703
4704 /**
4705 * Set the property value to the given boolean value.
4706 *
4707 * @param value the property value
4708 * @return the interface for additional requests or actions
4709 */
4710 Next to( boolean value );
4711
4712 /**
4713 * Set the property value to the given float value.
4714 *
4715 * @param value the property value
4716 * @return the interface for additional requests or actions
4717 */
4718 Next to( float value );
4719
4720 /**
4721 * Set the property value to the given double value.
4722 *
4723 * @param value the property value
4724 * @return the interface for additional requests or actions
4725 */
4726 Next to( double value );
4727
4728 /**
4729 * Set the property value to the given decimal value.
4730 *
4731 * @param value the property value
4732 * @return the interface for additional requests or actions
4733 */
4734 Next to( BigDecimal value );
4735
4736 /**
4737 * Set the property value to the date given by the supplied calendar.
4738 *
4739 * @param value the property value
4740 * @return the interface for additional requests or actions
4741 */
4742 Next to( Calendar value );
4743
4744 /**
4745 * Set the property value to the given date.
4746 *
4747 * @param value the property value
4748 * @return the interface for additional requests or actions
4749 */
4750 Next to( Date value );
4751
4752 /**
4753 * Set the property value to the given date-time instant.
4754 *
4755 * @param value the property value
4756 * @return the interface for additional requests or actions
4757 */
4758 Next to( DateTime value );
4759
4760 /**
4761 * Set the property value to the given Name.
4762 *
4763 * @param value the property value
4764 * @return the interface for additional requests or actions
4765 */
4766 Next to( Name value );
4767
4768 /**
4769 * Set the property value to the given Path.
4770 *
4771 * @param value the property value
4772 * @return the interface for additional requests or actions
4773 */
4774 Next to( Path value );
4775
4776 /**
4777 * Set the property value to the given Reference. See also {@link #to(Node)}.
4778 *
4779 * @param value the property value
4780 * @return the interface for additional requests or actions
4781 */
4782 Next to( Reference value );
4783
4784 /**
4785 * Set the property value to the given URI.
4786 *
4787 * @param value the property value
4788 * @return the interface for additional requests or actions
4789 */
4790 Next to( URI value );
4791
4792 /**
4793 * Set the property value to the given UUID.
4794 *
4795 * @param value the property value
4796 * @return the interface for additional requests or actions
4797 */
4798 Next to( UUID value );
4799
4800 /**
4801 * Set the property value to the given binary value.
4802 *
4803 * @param value the property value
4804 * @return the interface for additional requests or actions
4805 */
4806 Next to( Binary value );
4807
4808 /**
4809 * Set the property value to the given byte array.
4810 *
4811 * @param value the property value
4812 * @return the interface for additional requests or actions
4813 */
4814 Next to( byte[] value );
4815
4816 /**
4817 * Set the property value to the given string.
4818 *
4819 * @param stream the stream containing the content to be used for the property value
4820 * @param approximateLength the approximate length of the content (in bytes)
4821 * @return the interface for additional requests or actions
4822 */
4823 Next to( InputStream stream,
4824 long approximateLength );
4825
4826 /**
4827 * Set the property value to the given string.
4828 *
4829 * @param reader the reader containing the content to be used for the property value
4830 * @param approximateLength the approximate length of the content (in bytes)
4831 * @return the interface for additional requests or actions
4832 */
4833 Next to( Reader reader,
4834 long approximateLength );
4835
4836 /**
4837 * Set the property value to the given object. The supplied <code>value</code> should be a valid property value, or a
4838 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
4839 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
4840 *
4841 * @param value the property value
4842 * @return the interface for additional requests or actions
4843 * @throws IllegalArgumentException if the value is a Node or Location that has no {@link Location#getUuid() UUID}
4844 */
4845 Next to( Object value );
4846
4847 /**
4848 * Set the property values to the given object. Each of the supplied <code>values</code> should be a valid property value,
4849 * or a {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note
4850 * that it is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
4851 *
4852 * @param values the property values
4853 * @return the interface for additional requests or actions
4854 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
4855 * UUID}
4856 */
4857 Next to( Object[] values );
4858
4859 /**
4860 * Set the property value to the given objects. Each of the supplied values should be a valid property value, or a
4861 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
4862 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
4863 *
4864 * @param firstValue the first property value
4865 * @param otherValues the remaining property values
4866 * @return the interface for additional requests or actions
4867 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
4868 * UUID}
4869 */
4870 Next to( Object firstValue,
4871 Object... otherValues );
4872
4873 /**
4874 * Set the property value to the given object. Each of the supplied values should be a valid property value, or a
4875 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
4876 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
4877 *
4878 * @param values the container for the property values
4879 * @return the interface for additional requests or actions
4880 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
4881 * UUID}
4882 */
4883 Next to( Iterable<?> values );
4884
4885 /**
4886 * Set the property value to the given object. Each of the supplied values should be a valid property value, or a
4887 * {@link Node} (or {@link Location}) if the property value is to be a reference to that node (or location). Note that it
4888 * is an error if the Node (or Location) does not have a {@link Location#getUuid() UUID}.
4889 *
4890 * @param values the iterator over the property values
4891 * @return the interface for additional requests or actions
4892 * @throws IllegalArgumentException if the any of the values is a Node or Location that has no {@link Location#getUuid()
4893 * UUID}
4894 */
4895 Next to( Iterator<?> values );
4896 }
4897
4898 /**
4899 * A component that defines a node that is to be created.
4900 *
4901 * @param <Next> The interface that is to be returned to complete the create request
4902 * @author Randall Hauch
4903 */
4904 public interface CreateNode<Next> {
4905 /**
4906 * Specify the name of the node that is to be created.
4907 *
4908 * @param nodeName the name of the new node
4909 * @param properties the properties for the new node
4910 * @return the next component for making additional requests.
4911 */
4912 Next node( String nodeName,
4913 Property... properties );
4914
4915 /**
4916 * Specify the name of the node that is to be created.
4917 *
4918 * @param nodeName the name of the new node
4919 * @param properties the properties for the new node
4920 * @return the next component for making additional requests.
4921 */
4922 Next node( String nodeName,
4923 Iterator<Property> properties );
4924
4925 /**
4926 * Specify the name of the node that is to be created.
4927 *
4928 * @param nodeName the name of the new node
4929 * @param properties the properties for the new node
4930 * @return the next component for making additional requests.
4931 */
4932 Next node( String nodeName,
4933 Iterable<Property> properties );
4934 }
4935
4936 /**
4937 * A component that defines a node that is to be created.
4938 *
4939 * @param <Next> The interface that is to be returned to complete the create request
4940 * @author Randall Hauch
4941 */
4942 public interface CreateNodeNamed<Next> {
4943 /**
4944 * Specify the name of the node that is to be created.
4945 *
4946 * @param nodeName the name of the new node
4947 * @return the interface used to complete the request
4948 */
4949 Create<Next> nodeNamed( String nodeName );
4950
4951 /**
4952 * Specify the name of the node that is to be created.
4953 *
4954 * @param nodeName the name of the new node
4955 * @return the interface used to complete the request
4956 */
4957 Create<Next> nodeNamed( Name nodeName );
4958 }
4959
4960 /**
4961 * A component that defines the location into which a node should be copied or moved.
4962 *
4963 * @param <Next> The interface that is to be returned when this request is completed
4964 * @author Randall Hauch
4965 */
4966 public interface ImportInto<Next> {
4967 /**
4968 * Specify whether the root element in the XML document should be skipped (that is, not be represented by a node). By
4969 * default, the root element is not skipped.
4970 *
4971 * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
4972 * @return the interface used to specify the location where the content should be placed
4973 */
4974 ImportInto<Next> skippingRootElement( boolean skip );
4975
4976 /**
4977 * Finish the import by specifying the Location.create into which the node should be copied/moved.
4978 *
4979 * @param to the location of the new parent
4980 * @return the interface for additional requests or actions
4981 * @throws IOException if there is a problem reading the content being imported
4982 * @throws SAXException if there is a problem with the SAX Parser
4983 */
4984 Next into( Location to ) throws IOException, SAXException;
4985
4986 /**
4987 * Finish the import by specifying the Location.create into which the node should be copied/moved.
4988 *
4989 * @param toPath the path of the new parent
4990 * @return the interface for additional requests or actions
4991 * @throws IOException if there is a problem reading the content being imported
4992 * @throws SAXException if there is a problem with the SAX Parser
4993 */
4994 Next into( String toPath ) throws IOException, SAXException;
4995
4996 /**
4997 * Finish the import by specifying the Location.create into which the node should be copied/moved.
4998 *
4999 * @param to the path of the new parent
5000 * @return the interface for additional requests or actions
5001 * @throws IOException if there is a problem reading the content being imported
5002 * @throws SAXException if there is a problem with the SAX Parser
5003 */
5004 Next into( Path to ) throws IOException, SAXException;
5005
5006 /**
5007 * Finish the import by specifying the Location.create into which the node should be copied/moved.
5008 *
5009 * @param to the UUID of the new parent
5010 * @return the interface for additional requests or actions
5011 * @throws IOException if there is a problem reading the content being imported
5012 * @throws SAXException if there is a problem with the SAX Parser
5013 */
5014 Next into( UUID to ) throws IOException, SAXException;
5015
5016 /**
5017 * Finish the import by specifying the Location.create into which the node should be copied/moved.
5018 *
5019 * @param idProperty the property that uniquely identifies the new parent
5020 * @return the interface for additional requests or actions
5021 * @throws IOException if there is a problem reading the content being imported
5022 * @throws SAXException if there is a problem with the SAX Parser
5023 */
5024 Next into( Property idProperty ) throws IOException, SAXException;
5025
5026 /**
5027 * Finish the import by specifying the Location.create into which the node should be copied/moved.
5028 *
5029 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
5030 * new parent
5031 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
5032 * identifies the new parent
5033 * @return the interface for additional requests or actions
5034 * @throws IOException if there is a problem reading the content being imported
5035 * @throws SAXException if there is a problem with the SAX Parser
5036 */
5037 Next into( Property firstIdProperty,
5038 Property... additionalIdProperties ) throws IOException, SAXException;
5039
5040 /**
5041 * Finish the import by specifying the Location.create into which the node should be copied/moved.
5042 *
5043 * @param idProperties the properties that uniquely identifies the new parent
5044 * @return the interface for additional requests or actions
5045 * @throws IOException if there is a problem reading the content being imported
5046 * @throws SAXException if there is a problem with the SAX Parser
5047 */
5048 Next into( Iterable<Property> idProperties ) throws IOException, SAXException;
5049 }
5050
5051 public interface BatchConjunction extends Conjunction<Batch>, Executable<Node> {
5052 }
5053
5054 public interface GetNodeConjunction<Next> extends Conjunction<Next> {
5055 Node andReturn();
5056 }
5057
5058 protected class GetNodeOrReturnGraph implements GetNodeConjunction<Graph> {
5059 private final Location location;
5060
5061 GetNodeOrReturnGraph( Location location ) {
5062 assert location != null;
5063 this.location = location;
5064 }
5065
5066 /**
5067 * {@inheritDoc}
5068 *
5069 * @see org.jboss.dna.graph.Graph.Conjunction#and()
5070 */
5071 public Graph and() {
5072 return Graph.this;
5073 }
5074
5075 /**
5076 * {@inheritDoc}
5077 *
5078 * @see org.jboss.dna.graph.Graph.GetNodeConjunction#andReturn()
5079 */
5080 public Node andReturn() {
5081 return and().getNodeAt(location);
5082 }
5083 }
5084
5085 // ----------------------------------------------------------------------------------------------------------------
5086 // Node Implementation
5087 // ----------------------------------------------------------------------------------------------------------------
5088 @Immutable
5089 protected class GraphNode implements Node {
5090 private final ReadNodeRequest request;
5091
5092 /*package*/GraphNode( ReadNodeRequest request ) {
5093 this.request = request;
5094 }
5095
5096 public Location getLocation() {
5097 return request.getActualLocationOfNode();
5098 }
5099
5100 public Graph getGraph() {
5101 return Graph.this;
5102 }
5103
5104 public Collection<Property> getProperties() {
5105 return request.getProperties();
5106 }
5107
5108 public Property getProperty( Name name ) {
5109 return getPropertiesByName().get(name);
5110 }
5111
5112 public Property getProperty( String nameStr ) {
5113 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
5114 return getPropertiesByName().get(name);
5115 }
5116
5117 public Map<Name, Property> getPropertiesByName() {
5118 return request.getPropertiesByName();
5119 }
5120
5121 public List<Location> getChildren() {
5122 return request.getChildren();
5123 }
5124
5125 public boolean hasChildren() {
5126 return request.getChildren().size() > 0;
5127 }
5128
5129 public List<Segment> getChildrenSegments() {
5130 return getSegments(getChildren());
5131 }
5132
5133 public Iterator<Location> iterator() {
5134 return request.getChildren().iterator();
5135 }
5136
5137 @Override
5138 public int hashCode() {
5139 return getLocation().hashCode();
5140 }
5141
5142 @Override
5143 public boolean equals( Object obj ) {
5144 if (obj instanceof Node) {
5145 Node that = (Node)obj;
5146 return this.getLocation().equals(that.getLocation());
5147 }
5148 return false;
5149 }
5150
5151 @Override
5152 public String toString() {
5153 return "Node " + getLocation().toString();
5154 }
5155 }
5156
5157 // ----------------------------------------------------------------------------------------------------------------
5158 // Results implementation for the batched requests
5159 // ----------------------------------------------------------------------------------------------------------------
5160 @Immutable
5161 class BatchResults implements Results {
5162 private final Map<Path, BatchResultsNode> nodes = new HashMap<Path, BatchResultsNode>();
5163
5164 /*package*/BatchResults( List<Request> requests ) {
5165 for (Request request : requests) {
5166 if (request instanceof ReadAllPropertiesRequest) {
5167 ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
5168 getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
5169 } else if (request instanceof ReadPropertyRequest) {
5170 ReadPropertyRequest read = (ReadPropertyRequest)request;
5171 getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
5172 } else if (request instanceof ReadNodeRequest) {
5173 ReadNodeRequest read = (ReadNodeRequest)request;
5174 BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
5175 node.setProperties(read.getPropertiesByName());
5176 node.setChildren(read.getChildren());
5177 } else if (request instanceof ReadBlockOfChildrenRequest) {
5178 throw new IllegalStateException();
5179 } else if (request instanceof ReadAllChildrenRequest) {
5180 ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
5181 getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
5182 } else if (request instanceof ReadBranchRequest) {
5183 ReadBranchRequest read = (ReadBranchRequest)request;
5184 for (Location location : read) {
5185 BatchResultsNode node = getOrCreateNode(location);
5186 node.setProperties(read.getPropertiesFor(location));
5187 node.setChildren(read.getChildren(location));
5188 }
5189 }
5190 }
5191 for (Map.Entry<Path, BatchResultsNode> entry : nodes.entrySet()) {
5192 entry.getValue().freeze();
5193 }
5194 }
5195
5196 /*package*/BatchResults( Request request ) {
5197 if (request instanceof ReadAllPropertiesRequest) {
5198 ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
5199 getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
5200 } else if (request instanceof ReadPropertyRequest) {
5201 ReadPropertyRequest read = (ReadPropertyRequest)request;
5202 getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
5203 } else if (request instanceof ReadNodeRequest) {
5204 ReadNodeRequest read = (ReadNodeRequest)request;
5205 BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
5206 node.setProperties(read.getPropertiesByName());
5207 node.setChildren(read.getChildren());
5208 } else if (request instanceof ReadBlockOfChildrenRequest) {
5209 throw new IllegalStateException();
5210 } else if (request instanceof ReadAllChildrenRequest) {
5211 ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
5212 getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
5213 } else if (request instanceof ReadBranchRequest) {
5214 ReadBranchRequest read = (ReadBranchRequest)request;
5215 for (Location location : read) {
5216 BatchResultsNode node = getOrCreateNode(location);
5217 node.setProperties(read.getPropertiesFor(location));
5218 node.setChildren(read.getChildren(location));
5219 }
5220 }
5221 for (Map.Entry<Path, BatchResultsNode> entry : nodes.entrySet()) {
5222 entry.getValue().freeze();
5223 }
5224 }
5225
5226 /*package*/BatchResults() {
5227 }
5228
5229 private BatchResultsNode getOrCreateNode( Location location ) {
5230 BatchResultsNode node = nodes.get(location);
5231 if (node == null) {
5232 node = new BatchResultsNode(location);
5233 assert location.getPath() != null;
5234 nodes.put(location.getPath(), node);
5235 }
5236 return node;
5237 }
5238
5239 public Graph getGraph() {
5240 return Graph.this;
5241 }
5242
5243 protected void checkIsAbsolute( Path path ) {
5244 if (!path.isAbsolute()) {
5245 throw new IllegalArgumentException(GraphI18n.pathIsNotAbsolute.text(path));
5246 }
5247 }
5248
5249 public Node getNode( String pathStr ) {
5250 Path path = createPath(pathStr);
5251 checkIsAbsolute(path);
5252 return nodes.get(path);
5253 }
5254
5255 public Node getNode( Path path ) {
5256 CheckArg.isNotNull(path, "path");
5257 checkIsAbsolute(path);
5258 return nodes.get(path);
5259 }
5260
5261 public Node getNode( Location location ) {
5262 CheckArg.isNotNull(location, "location");
5263 CheckArg.isNotNull(location.getPath(), "location.getPath()");
5264 return nodes.get(location.getPath());
5265 }
5266
5267 public boolean includes( String path ) {
5268 return getNode(path) != null;
5269 }
5270
5271 public boolean includes( Path path ) {
5272 return getNode(path) != null;
5273 }
5274
5275 public boolean includes( Location location ) {
5276 return getNode(location) != null;
5277 }
5278
5279 public Iterator<Node> iterator() {
5280 List<Path> paths = new ArrayList<Path>(nodes.keySet());
5281 Collections.sort(paths);
5282 final Iterator<Path> pathIter = paths.iterator();
5283 return new Iterator<Node>() {
5284 public boolean hasNext() {
5285 return pathIter.hasNext();
5286 }
5287
5288 public Node next() {
5289 Path nextPath = pathIter.next();
5290 return getNode(nextPath);
5291 }
5292
5293 public void remove() {
5294 throw new UnsupportedOperationException();
5295 }
5296 };
5297 }
5298 }
5299
5300 @Immutable
5301 class BatchResultsNode implements Node {
5302 private final Location location;
5303 private Map<Name, Property> properties;
5304 private List<Location> children;
5305
5306 BatchResultsNode( Location location ) {
5307 this.location = location;
5308 }
5309
5310 void addProperty( Property property ) {
5311 if (this.properties == null) this.properties = new HashMap<Name, Property>();
5312 this.properties.put(property.getName(), property);
5313 }
5314
5315 void setProperties( Map<Name, Property> properties ) {
5316 this.properties = properties;
5317 }
5318
5319 void setChildren( List<Location> children ) {
5320 this.children = children;
5321 }
5322
5323 void freeze() {
5324 if (properties != null) properties = Collections.unmodifiableMap(properties);
5325 else properties = Collections.emptyMap();
5326 if (children != null) children = Collections.unmodifiableList(children);
5327 else children = Collections.emptyList();
5328 }
5329
5330 public List<Segment> getChildrenSegments() {
5331 return getSegments(getChildren());
5332 }
5333
5334 public Graph getGraph() {
5335 return Graph.this;
5336 }
5337
5338 public Location getLocation() {
5339 return location;
5340 }
5341
5342 public Collection<Property> getProperties() {
5343 return properties.values();
5344 }
5345
5346 public Map<Name, Property> getPropertiesByName() {
5347 return properties;
5348 }
5349
5350 public Property getProperty( Name name ) {
5351 return properties.get(name);
5352 }
5353
5354 public Property getProperty( String nameStr ) {
5355 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
5356 return properties.get(name);
5357 }
5358
5359 public List<Location> getChildren() {
5360 return children;
5361 }
5362
5363 public boolean hasChildren() {
5364 return children.size() != 0;
5365 }
5366
5367 public Iterator<Location> iterator() {
5368 return children.iterator();
5369 }
5370
5371 @Override
5372 public int hashCode() {
5373 return location.hashCode();
5374 }
5375
5376 @Override
5377 public boolean equals( Object obj ) {
5378 if (obj instanceof Node) {
5379 Node that = (Node)obj;
5380 return this.location.equals(that.getLocation());
5381 }
5382 return false;
5383 }
5384
5385 @Override
5386 public String toString() {
5387 return "Node " + getLocation().toString();
5388 }
5389
5390 }
5391
5392 // ----------------------------------------------------------------------------------------------------------------
5393 // Subgraph and SubgraphNode implementations
5394 // ----------------------------------------------------------------------------------------------------------------
5395 @Immutable
5396 class SubgraphResults implements Subgraph {
5397 private final ReadBranchRequest request;
5398
5399 SubgraphResults( ReadBranchRequest request ) {
5400 this.request = request;
5401 }
5402
5403 public Graph getGraph() {
5404 return Graph.this;
5405 }
5406
5407 public Location getLocation() {
5408 return request.getActualLocationOfNode();
5409 }
5410
5411 public SubgraphNode getRoot() {
5412 return getNode(getLocation());
5413 }
5414
5415 public int getMaximumDepth() {
5416 return request.maximumDepth();
5417 }
5418
5419 public Iterator<SubgraphNode> iterator() {
5420 final Iterator<Location> iter = request.iterator();
5421 return new Iterator<SubgraphNode>() {
5422 public boolean hasNext() {
5423 return iter.hasNext();
5424 }
5425
5426 public SubgraphNode next() {
5427 return getNode(iter.next());
5428 }
5429
5430 public void remove() {
5431 throw new UnsupportedOperationException();
5432 }
5433 };
5434 }
5435
5436 public boolean includes( Path path ) {
5437 CheckArg.isNotNull(path, "path");
5438 path = getAbsolutePath(path);
5439 return request.includes(path);
5440 }
5441
5442 public boolean includes( Location location ) {
5443 CheckArg.isNotNull(location, "location");
5444 return request.includes(location);
5445 }
5446
5447 public boolean includes( String pathStr ) {
5448 Path path = createPath(pathStr);
5449 path = getAbsolutePath(path);
5450 return includes(path);
5451 }
5452
5453 public SubgraphNode getNode( Location location ) {
5454 if (!location.hasPath()) return null;
5455 Location actualLocation = request.getLocationFor(location.getPath());
5456 if (actualLocation == null) return null;
5457 return new SubgraphNodeImpl(actualLocation, request);
5458 }
5459
5460 public SubgraphNode getNode( Path path ) {
5461 path = getAbsolutePath(path);
5462 if (!includes(path)) return null;
5463 Location location = request.getLocationFor(path);
5464 if (location == null) return null;
5465 return new SubgraphNodeImpl(location, request);
5466 }
5467
5468 public SubgraphNode getNode( String pathStr ) {
5469 CheckArg.isNotEmpty(pathStr, "path");
5470 Path path = createPath(pathStr);
5471 path = getAbsolutePath(path);
5472 return getNode(path);
5473 }
5474
5475 public SubgraphNode getNode( Name relativePath ) {
5476 Path path = getGraph().getContext()
5477 .getValueFactories()
5478 .getPathFactory()
5479 .create(getLocation().getPath(), relativePath);
5480 path = path.getNormalizedPath();
5481 return getNode(path);
5482 }
5483
5484 protected Path getAbsolutePath( Path absoluteOrRelative ) {
5485 Path result = absoluteOrRelative;
5486 if (!result.isAbsolute()) {
5487 result = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), result);
5488 result = result.getNormalizedPath();
5489 }
5490 return result;
5491 }
5492
5493 @Override
5494 public int hashCode() {
5495 return getLocation().hashCode();
5496 }
5497
5498 @Override
5499 public String toString() {
5500 return "Subgraph " + getLocation().toString();
5501 }
5502 }
5503
5504 protected static final List<Location> NO_CHILDREN = Collections.emptyList();
5505
5506 @Immutable
5507 class SubgraphNodeImpl implements SubgraphNode {
5508 private final Location location;
5509 private final ReadBranchRequest request;
5510
5511 SubgraphNodeImpl( Location location,
5512 ReadBranchRequest request ) {
5513 this.location = location;
5514 this.request = request;
5515 }
5516
5517 public List<Location> getChildren() {
5518 List<Location> children = request.getChildren(location);
5519 if (children == null) children = NO_CHILDREN;
5520 return children;
5521 }
5522
5523 public Graph getGraph() {
5524 return Graph.this;
5525 }
5526
5527 public Location getLocation() {
5528 return location;
5529 }
5530
5531 public Collection<Property> getProperties() {
5532 return getPropertiesByName().values();
5533 }
5534
5535 public Map<Name, Property> getPropertiesByName() {
5536 return request.getPropertiesFor(location);
5537 }
5538
5539 public Property getProperty( Name name ) {
5540 return getPropertiesByName().get(name);
5541 }
5542
5543 public Property getProperty( String nameStr ) {
5544 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
5545 return getPropertiesByName().get(name);
5546 }
5547
5548 public boolean hasChildren() {
5549 return getChildren().size() != 0;
5550 }
5551
5552 public List<Segment> getChildrenSegments() {
5553 return getSegments(getChildren());
5554 }
5555
5556 public Iterator<Location> iterator() {
5557 return getChildren().iterator();
5558 }
5559
5560 public SubgraphNode getNode( Name childName ) {
5561 Path path = getContext().getValueFactories().getPathFactory().create(location.getPath(), childName);
5562 Location location = request.getLocationFor(path);
5563 if (location == null) return null;
5564 return new SubgraphNodeImpl(location, request);
5565 }
5566
5567 public SubgraphNode getNode( Path relativePath ) {
5568 Path path = getContext().getValueFactories().getPathFactory().create(location.getPath(), relativePath);
5569 path = path.getNormalizedPath();
5570 Location location = request.getLocationFor(path);
5571 if (location == null) return null;
5572 return new SubgraphNodeImpl(location, request);
5573 }
5574
5575 @Override
5576 public int hashCode() {
5577 return location.hashCode();
5578 }
5579
5580 @Override
5581 public boolean equals( Object obj ) {
5582 if (obj instanceof Node) {
5583 Node that = (Node)obj;
5584 return this.location.equals(that.getLocation());
5585 }
5586 return false;
5587 }
5588
5589 @Override
5590 public String toString() {
5591 return "Node " + getLocation().toString();
5592 }
5593 }
5594
5595 // ----------------------------------------------------------------------------------------------------------------
5596 // Action Implementations
5597 // ----------------------------------------------------------------------------------------------------------------
5598 @Immutable
5599 protected abstract class AbstractAction<T> implements Conjunction<T> {
5600 private final T afterConjunction;
5601
5602 /*package*/AbstractAction( T afterConjunction ) {
5603 this.afterConjunction = afterConjunction;
5604 }
5605
5606 /*package*/T afterConjunction() {
5607 return this.afterConjunction;
5608 }
5609
5610 public T and() {
5611 return this.afterConjunction;
5612 }
5613
5614 /*package*/Path createPath( String path ) {
5615 return Graph.this.getContext().getValueFactories().getPathFactory().create(path);
5616 }
5617
5618 /*package*/Name createName( String name ) {
5619 return Graph.this.getContext().getValueFactories().getNameFactory().create(name);
5620 }
5621 }
5622
5623 @NotThreadSafe
5624 protected abstract class MoveAction<T> extends AbstractAction<T> implements Move<T> {
5625 private final Locations from;
5626 private Name newName;
5627
5628 /*package*/MoveAction( T afterConjunction,
5629 Location from ) {
5630 super(afterConjunction);
5631 this.from = new Locations(from);
5632 }
5633
5634 public Move<T> and( Location from ) {
5635 this.from.add(from);
5636 return this;
5637 }
5638
5639 public Move<T> and( String from ) {
5640 this.from.add(Location.create(createPath(from)));
5641 return this;
5642 }
5643
5644 public Move<T> and( Path from ) {
5645 this.from.add(Location.create(from));
5646 return this;
5647 }
5648
5649 public Move<T> and( Property firstFrom,
5650 Property... additionalFroms ) {
5651 this.from.add(Location.create(firstFrom, additionalFroms));
5652 return this;
5653 }
5654
5655 public Move<T> and( Iterable<Property> idPropertiesFrom ) {
5656 this.from.add(Location.create(idPropertiesFrom));
5657 return this;
5658 }
5659
5660 public Move<T> and( Property from ) {
5661 this.from.add(Location.create(from));
5662 return this;
5663 }
5664
5665 public Move<T> and( UUID from ) {
5666 this.from.add(Location.create(from));
5667 return this;
5668 }
5669
5670 public Into<T> as( Name newName ) {
5671 this.newName = newName;
5672 return this;
5673 }
5674
5675 /**
5676 * {@inheritDoc}
5677 *
5678 * @see org.jboss.dna.graph.Graph.AsName#as(java.lang.String)
5679 */
5680 public Into<T> as( String newName ) {
5681 return as(createName(newName));
5682 }
5683
5684 /**
5685 * Submit any requests to move the targets into the supplied parent location
5686 *
5687 * @param from the location(s) that are being moved; never null
5688 * @param into the parent location
5689 * @param before the location of the child of the parent before which this node should be placed
5690 * @param newName the new name for the node being moved; may be null
5691 * @return this object, for method chaining
5692 */
5693 protected abstract T submit( Locations from,
5694 Location into,
5695 Location before,
5696 Name newName );
5697
5698 /**
5699 * Submit any requests to move the targets into the supplied parent location
5700 *
5701 * @param from the location(s) that are being moved; never null
5702 * @param into the parent location
5703 * @param newName the new name for the node being moved; may be null
5704 * @return this object, for method chaining
5705 */
5706 protected T submit( Locations from,
5707 Location into,
5708 Name newName ) {
5709 return submit(from, into, null, newName);
5710 }
5711
5712 public T into( Location into ) {
5713 return submit(from, into, null, newName);
5714 }
5715
5716 public T into( Path into ) {
5717 return submit(from, Location.create(into), newName);
5718 }
5719
5720 public T into( UUID into ) {
5721 return submit(from, Location.create(into), newName);
5722 }
5723
5724 public T into( Property firstIdProperty,
5725 Property... additionalIdProperties ) {
5726 return submit(from, Location.create(firstIdProperty, additionalIdProperties), newName);
5727 }
5728
5729 public T into( Property into ) {
5730 return submit(from, Location.create(into), newName);
5731 }
5732
5733 public T into( String into ) {
5734 return submit(from, Location.create(createPath(into)), newName);
5735 }
5736
5737 public T before( Location before ) {
5738 return submit(from, null, before, newName);
5739 }
5740
5741 public T before( Path before ) {
5742 return submit(from, null, Location.create(before), newName);
5743 }
5744
5745 public T before( UUID before ) {
5746 return submit(from, null, Location.create(before), newName);
5747 }
5748
5749 public T before( Property firstIdProperty,
5750 Property... additionalIdProperties ) {
5751 return submit(from, null, Location.create(firstIdProperty, additionalIdProperties), newName);
5752 }
5753
5754 public T before( Property before ) {
5755 return submit(from, null, Location.create(before), newName);
5756 }
5757
5758 public T before( String before ) {
5759 return submit(from, null, Location.create(createPath(before)), newName);
5760 }
5761 }
5762
5763 @NotThreadSafe
5764 protected abstract class CopyAction<T> extends AbstractAction<T> implements Copy<T> {
5765 private final Locations from;
5766
5767 /*package*/CopyAction( T afterConjunction,
5768 Location from ) {
5769 super(afterConjunction);
5770 this.from = new Locations(from);
5771 }
5772
5773 public Copy<T> and( Location from ) {
5774 this.from.add(from);
5775 return this;
5776 }
5777
5778 public Copy<T> and( String from ) {
5779 this.from.add(Location.create(createPath(from)));
5780 return this;
5781 }
5782
5783 public Copy<T> and( Path from ) {
5784 this.from.add(Location.create(from));
5785 return this;
5786 }
5787
5788 public Copy<T> and( Property firstFrom,
5789 Property... additionalFroms ) {
5790 this.from.add(Location.create(firstFrom, additionalFroms));
5791 return this;
5792 }
5793
5794 public Copy<T> and( Iterable<Property> idProperties ) {
5795 this.from.add(Location.create(idProperties));
5796 return this;
5797 }
5798
5799 public Copy<T> and( Property from ) {
5800 this.from.add(Location.create(from));
5801 return this;
5802 }
5803
5804 public Copy<T> and( UUID from ) {
5805 this.from.add(Location.create(from));
5806 return this;
5807 }
5808
5809 /**
5810 * Submit any requests to move the targets into the supplied parent location
5811 *
5812 * @param from the locations that are being copied
5813 * @param into the parent location
5814 * @param nameForCopy the name that should be used for the copy, or null if the name should be the same as the original
5815 * @return this object, for method chaining
5816 */
5817 protected abstract T submit( Locations from,
5818 Location into,
5819 Name nameForCopy );
5820
5821 public T into( Location into ) {
5822 return submit(from, into, null);
5823 }
5824
5825 public T into( Path into ) {
5826 return submit(from, Location.create(into), null);
5827 }
5828
5829 public T into( UUID into ) {
5830 return submit(from, Location.create(into), null);
5831 }
5832
5833 public T into( Property firstIdProperty,
5834 Property... additionalIdProperties ) {
5835 return submit(from, Location.create(firstIdProperty, additionalIdProperties), null);
5836 }
5837
5838 public T into( Property into ) {
5839 return submit(from, Location.create(into), null);
5840 }
5841
5842 public T into( String into ) {
5843 return submit(from, Location.create(createPath(into)), null);
5844 }
5845
5846 public T to( Location desiredLocation ) {
5847 if (!desiredLocation.hasPath()) {
5848 throw new IllegalArgumentException(GraphI18n.unableToCopyToLocationWithoutAPath.text(this.from, desiredLocation));
5849 }
5850 Path desiredPath = desiredLocation.getPath();
5851 if (desiredPath.isRoot()) {
5852 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredLocation));
5853 }
5854 Path parent = desiredPath.getParent();
5855 return submit(from, Location.create(parent), desiredPath.getLastSegment().getName());
5856 }
5857
5858 public T to( Path desiredPath ) {
5859 if (desiredPath.isRoot()) {
5860 throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath));
5861 }
5862 Path parent = desiredPath.getParent();
5863 return submit(from, Location.create(parent), desiredPath.getLastSegment().getName());
5864 }
5865
5866 public T to( String desiredPath ) {
5867 return to(createPath(desiredPath));
5868 }
5869 }
5870
5871 @NotThreadSafe
5872 protected abstract class CreateAction<T> extends AbstractAction<T> implements Create<T> {
5873 private final String workspaceName;
5874 private final Location parent;
5875 private final Name childName;
5876 private final Map<Name, Property> properties = new HashMap<Name, Property>();
5877 private boolean submitted = false;
5878 private NodeConflictBehavior conflictBehavior = NodeConflictBehavior.APPEND;
5879
5880 /*package*/CreateAction( T afterConjunction,
5881 Location parent,
5882 String workspaceName,
5883 Name childName ) {
5884 super(afterConjunction);
5885 this.parent = parent;
5886 this.workspaceName = workspaceName;
5887 this.childName = childName;
5888 }
5889
5890 /**
5891 * {@inheritDoc}
5892 *
5893 * @see org.jboss.dna.graph.Graph.Create#ifAbsent()
5894 */
5895 public Create<T> ifAbsent() {
5896 conflictBehavior = NodeConflictBehavior.DO_NOT_REPLACE;
5897 return this;
5898 }
5899
5900 /**
5901 * {@inheritDoc}
5902 *
5903 * @see org.jboss.dna.graph.Graph.Create#orReplace()
5904 */
5905 public Create<T> orReplace() {
5906 conflictBehavior = NodeConflictBehavior.REPLACE;
5907 return this;
5908 }
5909
5910 /**
5911 * {@inheritDoc}
5912 *
5913 * @see org.jboss.dna.graph.Graph.Create#orUpdate()
5914 */
5915 public Create<T> orUpdate() {
5916 conflictBehavior = NodeConflictBehavior.UPDATE;
5917 return this;
5918 }
5919
5920 /**
5921 * {@inheritDoc}
5922 *
5923 * @see org.jboss.dna.graph.Graph.Create#byAppending()
5924 */
5925 public Create<T> byAppending() {
5926 conflictBehavior = NodeConflictBehavior.APPEND;
5927 return this;
5928 }
5929
5930 public Create<T> and( UUID uuid ) {
5931 PropertyFactory factory = getContext().getPropertyFactory();
5932 properties.put(DnaLexicon.UUID, factory.create(DnaLexicon.UUID, uuid));
5933 return this;
5934 }
5935
5936 public Create<T> and( Property property ) {
5937 properties.put(property.getName(), property);
5938 return this;
5939 }
5940
5941 public Create<T> and( Iterable<Property> properties ) {
5942 for (Property property : properties) {
5943 this.properties.put(property.getName(), property);
5944 }
5945 return this;
5946 }
5947
5948 public Create<T> and( String name,
5949 Object... values ) {
5950 ExecutionContext context = getContext();
5951 PropertyFactory factory = context.getPropertyFactory();
5952 NameFactory nameFactory = context.getValueFactories().getNameFactory();
5953 Name propertyName = nameFactory.create(name);
5954 properties.put(propertyName, factory.create(propertyName, values));
5955 return this;
5956 }
5957
5958 public Create<T> and( Name name,
5959 Object... values ) {
5960 PropertyFactory factory = getContext().getPropertyFactory();
5961 properties.put(name, factory.create(name, values));
5962 return this;
5963 }
5964
5965 public Create<T> and( Property property,
5966 Property... additionalProperties ) {
5967 properties.put(property.getName(), property);
5968 for (Property additionalProperty : additionalProperties) {
5969 properties.put(additionalProperty.getName(), additionalProperty);
5970 }
5971 return this;
5972 }
5973
5974 public Create<T> with( UUID uuid ) {
5975 return and(uuid);
5976 }
5977
5978 public Create<T> with( Property property ) {
5979 return and(property);
5980 }
5981
5982 public Create<T> with( Iterable<Property> properties ) {
5983 return and(properties);
5984 }
5985
5986 public Create<T> with( Property property,
5987 Property... additionalProperties ) {
5988 return and(property, additionalProperties);
5989 }
5990
5991 public Create<T> with( String name,
5992 Object... values ) {
5993 return and(name, values);
5994 }
5995
5996 public Create<T> with( Name name,
5997 Object... values ) {
5998 return and(name, values);
5999 }
6000
6001 protected abstract T submit( Location parent,
6002 String workspaceName,
6003 Name childName,
6004 Collection<Property> properties,
6005 NodeConflictBehavior conflictBehavior );
6006
6007 @Override
6008 public T and() {
6009 if (!submitted) {
6010 submit(parent, workspaceName, childName, this.properties.values(), this.conflictBehavior);
6011 submitted = true;
6012 }
6013 return super.and();
6014 }
6015 }
6016
6017 @NotThreadSafe
6018 protected abstract class CreateNodeNamedAction<T> extends AbstractAction<T> implements CreateNodeNamed<T> {
6019 private final Location parent;
6020
6021 protected CreateNodeNamedAction( T afterConjunction,
6022 Location parent ) {
6023 super(afterConjunction);
6024 this.parent = parent;
6025 }
6026
6027 public CreateAction<T> nodeNamed( String name ) {
6028 NameFactory factory = getContext().getValueFactories().getNameFactory();
6029 Name nameObj = factory.create(name);
6030 return createWith(afterConjunction(), parent, nameObj);
6031 }
6032
6033 public CreateAction<T> nodeNamed( Name name ) {
6034 return createWith(afterConjunction(), parent, name);
6035 }
6036
6037 protected abstract CreateAction<T> createWith( T afterConjunction,
6038 Location parent,
6039 Name nodeName );
6040 }
6041
6042 @Immutable
6043 protected static final class GraphWorkspace implements Workspace {
6044 private final String name;
6045 private final Location root;
6046
6047 GraphWorkspace( String name,
6048 Location root ) {
6049 assert name != null;
6050 assert root != null;
6051 this.name = name;
6052 this.root = root;
6053 }
6054
6055 /**
6056 * {@inheritDoc}
6057 *
6058 * @see org.jboss.dna.graph.Workspace#getName()
6059 */
6060 public String getName() {
6061 return name;
6062 }
6063
6064 /**
6065 * {@inheritDoc}
6066 *
6067 * @see org.jboss.dna.graph.Workspace#getRoot()
6068 */
6069 public Location getRoot() {
6070 return root;
6071 }
6072
6073 /**
6074 * {@inheritDoc}
6075 *
6076 * @see java.lang.Object#hashCode()
6077 */
6078 @Override
6079 public int hashCode() {
6080 return this.name.hashCode();
6081 }
6082
6083 /**
6084 * {@inheritDoc}
6085 *
6086 * @see java.lang.Object#equals(java.lang.Object)
6087 */
6088 @Override
6089 public boolean equals( Object obj ) {
6090 if (obj == this) return true;
6091 if (obj instanceof GraphWorkspace) {
6092 GraphWorkspace that = (GraphWorkspace)obj;
6093 if (!this.getName().equals(that.getName())) return false;
6094 // all root nodes should be equivalent, so no need to check
6095 return true;
6096 }
6097 return false;
6098 }
6099
6100 /**
6101 * {@inheritDoc}
6102 *
6103 * @see java.lang.Object#toString()
6104 */
6105 @Override
6106 public String toString() {
6107 return "Workspace \"" + this.name + "\" (root = " + this.root + " )";
6108 }
6109 }
6110
6111 /**
6112 * A set of nodes returned from a {@link Graph graph}, with methods to access the properties and children of the nodes in the
6113 * result. The {@link #iterator()} method can be used to iterate all over the nodes in the result.
6114 *
6115 * @author Randall Hauch
6116 * @param <NodeType> the type of node that tis results deals with
6117 */
6118 @Immutable
6119 public interface BaseResults<NodeType extends Node> extends Iterable<NodeType> {
6120
6121 /**
6122 * Get the graph containing the node.
6123 *
6124 * @return the graph
6125 */
6126 Graph getGraph();
6127
6128 /**
6129 * Get the node at the supplied location.
6130 *
6131 * @param path the path of the node in these results
6132 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
6133 */
6134 NodeType getNode( String path );
6135
6136 /**
6137 * Get the node at the supplied location.
6138 *
6139 * @param path the path of the node in these results
6140 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
6141 */
6142 NodeType getNode( Path path );
6143
6144 /**
6145 * Get the node at the supplied location.
6146 *
6147 * @param location the location of the node
6148 * @return the node, or null if the node is not {@link #includes(Path) included} in these results
6149 */
6150 NodeType getNode( Location location );
6151
6152 /**
6153 * Return whether these results include a node at the supplied location.
6154 *
6155 * @param path the path of the node in these results
6156 * @return true if this subgraph includes the supplied location, or false otherwise
6157 */
6158 boolean includes( String path );
6159
6160 /**
6161 * Return whether this subgraph has a node at the supplied location.
6162 *
6163 * @param path the path of the node in these results
6164 * @return true if these results includes the supplied location, or false otherwise
6165 */
6166 boolean includes( Path path );
6167
6168 /**
6169 * Return whether this subgraph has a node at the supplied location.
6170 *
6171 * @param location the location of the node in these results
6172 * @return true if these results includes the supplied location, or false otherwise
6173 */
6174 boolean includes( Location location );
6175
6176 }
6177 }