001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.graph;
023
024 import java.io.File;
025 import java.io.IOException;
026 import java.net.URI;
027 import java.util.ArrayList;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.HashMap;
031 import java.util.Iterator;
032 import java.util.LinkedList;
033 import java.util.List;
034 import java.util.Map;
035 import java.util.UUID;
036 import net.jcip.annotations.Immutable;
037 import net.jcip.annotations.NotThreadSafe;
038 import org.jboss.dna.common.util.CheckArg;
039 import org.jboss.dna.graph.cache.CachePolicy;
040 import org.jboss.dna.graph.connectors.RepositoryConnection;
041 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
042 import org.jboss.dna.graph.connectors.RepositorySource;
043 import org.jboss.dna.graph.connectors.RepositorySourceException;
044 import org.jboss.dna.graph.properties.Name;
045 import org.jboss.dna.graph.properties.NameFactory;
046 import org.jboss.dna.graph.properties.Path;
047 import org.jboss.dna.graph.properties.Property;
048 import org.jboss.dna.graph.properties.PropertyFactory;
049 import org.jboss.dna.graph.properties.Path.Segment;
050 import org.jboss.dna.graph.requests.CompositeRequest;
051 import org.jboss.dna.graph.requests.CopyBranchRequest;
052 import org.jboss.dna.graph.requests.CreateNodeRequest;
053 import org.jboss.dna.graph.requests.DeleteBranchRequest;
054 import org.jboss.dna.graph.requests.MoveBranchRequest;
055 import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
056 import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
057 import org.jboss.dna.graph.requests.ReadBlockOfChildrenRequest;
058 import org.jboss.dna.graph.requests.ReadBranchRequest;
059 import org.jboss.dna.graph.requests.ReadNodeRequest;
060 import org.jboss.dna.graph.requests.ReadPropertyRequest;
061 import org.jboss.dna.graph.requests.RemovePropertiesRequest;
062 import org.jboss.dna.graph.requests.Request;
063 import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
064 import org.xml.sax.SAXException;
065
066 /**
067 * A graph representation of the content within a {@link RepositorySource}, including mechanisms to interact and manipulate that
068 * content. The graph is designed to be an <i><a href="http://en.wikipedia.org/wiki/Domain_Specific_Language">embedded domain
069 * specific language</a></i>, meaning calls to it are designed to read like sentences even though they are really just Java
070 * methods. And to be more readable, methods can be chained together.
071 *
072 * @author Randall Hauch
073 */
074 @NotThreadSafe
075 public class Graph {
076
077 /**
078 * Create a graph instance that uses the supplied repository and {@link ExecutionContext context}.
079 *
080 * @param sourceName the name of the source that should be used
081 * @param connectionFactory the factory of repository connections
082 * @param context the context in which all executions should be performed
083 * @return the new graph
084 * @throws IllegalArgumentException if the source or context parameters are null
085 */
086 public static Graph create( String sourceName,
087 RepositoryConnectionFactory connectionFactory,
088 ExecutionContext context ) {
089 return new Graph(sourceName, connectionFactory, context);
090 }
091
092 private final String sourceName;
093 private final RepositoryConnectionFactory connectionFactory;
094 private final ExecutionContext context;
095 private final RequestQueue requestQueue;
096 private final Conjunction<Graph> nextGraph;
097
098 protected Graph( String sourceName,
099 RepositoryConnectionFactory connectionFactory,
100 ExecutionContext context ) {
101 CheckArg.isNotNull(sourceName, "sourceName");
102 CheckArg.isNotNull(connectionFactory, "connectionFactory");
103 CheckArg.isNotNull(context, "context");
104 this.sourceName = sourceName;
105 this.connectionFactory = connectionFactory;
106 this.context = context;
107 this.requestQueue = new GraphRequestQueue();
108 this.nextGraph = new Conjunction<Graph>() {
109 public Graph and() {
110 return Graph.this;
111 }
112 };
113 }
114
115 /**
116 * Get the RepositoryConnectionFactory that this graph uses to create {@link RepositoryConnection repository connections}.
117 *
118 * @return the factory repository connections used by this graph; never null
119 */
120 public RepositoryConnectionFactory getConnectionFactory() {
121 return connectionFactory;
122 }
123
124 /**
125 * The name of the repository that will be used by this graph. This name is passed to the {@link #getConnectionFactory()
126 * connection factory} when this graph needs to {@link RepositoryConnectionFactory#createConnection(String) obtain} a
127 * {@link RepositoryConnection repository connection}.
128 *
129 * @return the name of the source
130 */
131 public String getSourceName() {
132 return sourceName;
133 }
134
135 /**
136 * Get the context of execution within which operations on this graph are performed.
137 *
138 * @return the execution context; never null
139 */
140 public ExecutionContext getContext() {
141 return context;
142 }
143
144 /*package*/RequestQueue queue() {
145 return this.requestQueue;
146 }
147
148 /**
149 * Get the default cache policy for this graph. May be null if such a policy has not been defined for thie
150 * {@link #getSourceName() source}.
151 *
152 * @return the default cache policy, or null if no such policy has been defined for the source
153 * @throws RepositorySourceException if no repository source with the {@link #getSourceName() name} could be found
154 */
155 public CachePolicy getDefaultCachePolicy() {
156 RepositoryConnection connection = this.connectionFactory.createConnection(getSourceName());
157 if (connection == null) {
158 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
159 }
160 try {
161 return connection.getDefaultCachePolicy();
162 } finally {
163 connection.close();
164 }
165 }
166
167 /**
168 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
169 * <code>into(...)</code> method on the returned {@link Move} object.
170 * <p>
171 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
172 * method is called.
173 * </p>
174 *
175 * @param from the node that is to be moved.
176 * @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
177 * be moved
178 */
179 public Move<Conjunction<Graph>> move( Node from ) {
180 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, from.getLocation());
181 }
182
183 /**
184 * Begin the request to move a node at the specified location into a parent node at a different location, which is specified
185 * via the <code>into(...)</code> method on the returned {@link Move} object.
186 * <p>
187 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
188 * method is called.
189 * </p>
190 *
191 * @param from the location of the node that is to be moved.
192 * @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
193 * be moved
194 */
195 public Move<Conjunction<Graph>> move( Location from ) {
196 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, from);
197 }
198
199 /**
200 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
201 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
202 * <p>
203 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
204 * method is called.
205 * </p>
206 *
207 * @param fromPath the path to the node that is to be moved.
208 * @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
209 * be moved
210 */
211 public Move<Conjunction<Graph>> move( String fromPath ) {
212 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(createPath(fromPath)));
213 }
214
215 /**
216 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
217 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
218 * <p>
219 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
220 * method is called.
221 * </p>
222 *
223 * @param from the path to the node that is to be moved.
224 * @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
225 * be moved
226 */
227 public Move<Conjunction<Graph>> move( Path from ) {
228 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(from));
229 }
230
231 /**
232 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which is
233 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
234 * <p>
235 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
236 * method is called.
237 * </p>
238 *
239 * @param from the UUID of the node that is to be moved.
240 * @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
241 * be moved
242 */
243 public Move<Conjunction<Graph>> move( UUID from ) {
244 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(from));
245 }
246
247 /**
248 * Begin the request to move a node with the specified unique identification property into a parent node at a different
249 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification
250 * property should uniquely identify a single node.
251 * <p>
252 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
253 * method is called.
254 * </p>
255 *
256 * @param idProperty the unique identification property of the node that is to be moved.
257 * @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
258 * be moved
259 */
260 public Move<Conjunction<Graph>> move( Property idProperty ) {
261 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(idProperty));
262 }
263
264 /**
265 * Begin the request to move a node with the specified identification properties into a parent node at a different location,
266 * which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The identification properties
267 * should uniquely identify a single node.
268 * <p>
269 * Like all other methods on the {@link Graph}, the move request will be performed immediately when the <code>into(...)</code>
270 * method is called.
271 * </p>
272 *
273 * @param firstIdProperty the first identification property of the node that is to be moved
274 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be moved
275 * @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
276 * be moved
277 */
278 public Move<Conjunction<Graph>> move( Property firstIdProperty,
279 Property... additionalIdProperties ) {
280 return new MoveAction<Conjunction<Graph>>(this.nextGraph, this.requestQueue, new Location(firstIdProperty,
281 additionalIdProperties));
282 }
283
284 /**
285 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
286 * <code>into(...)</code> method on the returned {@link Copy} object.
287 * <p>
288 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
289 * method is called.
290 * </p>
291 *
292 * @param from the node that is to be copied.
293 * @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
294 * be copied
295 */
296 public Copy<Graph> copy( Node from ) {
297 return new CopyAction<Graph>(this, this.requestQueue, from.getLocation());
298 }
299
300 /**
301 * Begin the request to copy a node at the specified location into a parent node at a different location, which is specified
302 * via the <code>into(...)</code> method on the returned {@link Copy} object.
303 * <p>
304 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
305 * method is called.
306 * </p>
307 *
308 * @param from the location of the node that is to be copied.
309 * @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
310 * be copied
311 */
312 public Copy<Graph> copy( Location from ) {
313 return new CopyAction<Graph>(this, this.requestQueue, from);
314 }
315
316 /**
317 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
318 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
319 * <p>
320 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
321 * method is called.
322 * </p>
323 *
324 * @param fromPath the path to the node that is to be copied.
325 * @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
326 * be copied
327 */
328 public Copy<Graph> copy( String fromPath ) {
329 return new CopyAction<Graph>(this, this.requestQueue, new Location(createPath(fromPath)));
330 }
331
332 /**
333 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
334 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
335 * <p>
336 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
337 * method is called.
338 * </p>
339 *
340 * @param from the path to the node that is to be copied.
341 * @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
342 * be copied
343 */
344 public Copy<Graph> copy( Path from ) {
345 return new CopyAction<Graph>(this, this.requestQueue, new Location(from));
346 }
347
348 /**
349 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which is
350 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
351 * <p>
352 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
353 * method is called.
354 * </p>
355 *
356 * @param from the UUID of the node that is to be copied.
357 * @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
358 * be copied
359 */
360 public Copy<Graph> copy( UUID from ) {
361 return new CopyAction<Graph>(this, this.requestQueue, new Location(from));
362 }
363
364 /**
365 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
366 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification
367 * property should uniquely identify a single node.
368 * <p>
369 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
370 * method is called.
371 * </p>
372 *
373 * @param idProperty the unique identification property of the node that is to be copied.
374 * @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
375 * be copied
376 */
377 public Copy<Graph> copy( Property idProperty ) {
378 return new CopyAction<Graph>(this, this.requestQueue, new Location(idProperty));
379 }
380
381 /**
382 * Begin the request to copy a node with the specified identification properties into a parent node at a different location,
383 * which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The identification properties
384 * should uniquely identify a single node.
385 * <p>
386 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the <code>into(...)</code>
387 * method is called.
388 * </p>
389 *
390 * @param firstIdProperty the first identification property of the node that is to be copied
391 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
392 * @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
393 * be copied
394 */
395 public Copy<Graph> copy( Property firstIdProperty,
396 Property... additionalIdProperties ) {
397 return new CopyAction<Graph>(this, this.requestQueue, new Location(firstIdProperty, additionalIdProperties));
398 }
399
400 /**
401 * Request to delete the specified node. This request is submitted to the repository immediately.
402 *
403 * @param at the node that is to be deleted
404 * @return an object that may be used to start another request
405 */
406 public Conjunction<Graph> delete( Node at ) {
407 this.requestQueue.submit(new DeleteBranchRequest(at.getLocation()));
408 return nextGraph;
409 }
410
411 /**
412 * Request to delete the node at the given location. This request is submitted to the repository immediately.
413 *
414 * @param at the location of the node that is to be deleted
415 * @return an object that may be used to start another request
416 */
417 public Conjunction<Graph> delete( Location at ) {
418 this.requestQueue.submit(new DeleteBranchRequest(at));
419 return nextGraph;
420 }
421
422 /**
423 * Request to delete the node at the given path. This request is submitted to the repository immediately.
424 *
425 * @param atPath the path of the node that is to be deleted
426 * @return an object that may be used to start another request
427 */
428 public Conjunction<Graph> delete( String atPath ) {
429 this.requestQueue.submit(new DeleteBranchRequest(new Location(createPath(atPath))));
430 return nextGraph;
431 }
432
433 /**
434 * Request to delete the node at the given path. This request is submitted to the repository immediately.
435 *
436 * @param at the path of the node that is to be deleted
437 * @return an object that may be used to start another request
438 */
439 public Conjunction<Graph> delete( Path at ) {
440 this.requestQueue.submit(new DeleteBranchRequest(new Location(at)));
441 return nextGraph;
442 }
443
444 /**
445 * Request to delete the node with the given UUID. This request is submitted to the repository immediately.
446 *
447 * @param at the UUID of the node that is to be deleted
448 * @return an object that may be used to start another request
449 */
450 public Conjunction<Graph> delete( UUID at ) {
451 this.requestQueue.submit(new DeleteBranchRequest(new Location(at)));
452 return nextGraph;
453 }
454
455 /**
456 * Request to delete the node with the given unique identification property. This request is submitted to the repository
457 * immediately.
458 *
459 * @param idProperty the unique identifying property of the node that is to be deleted
460 * @return an object that may be used to start another request
461 */
462 public Conjunction<Graph> delete( Property idProperty ) {
463 this.requestQueue.submit(new DeleteBranchRequest(new Location(idProperty)));
464 return nextGraph;
465 }
466
467 /**
468 * Request to delete the node with the given identification properties. The identification properties should uniquely identify
469 * a single node. This request is submitted to the repository immediately.
470 *
471 * @param firstIdProperty the first identification property of the node that is to be copied
472 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
473 * @return an object that may be used to start another request
474 */
475 public Conjunction<Graph> delete( Property firstIdProperty,
476 Property... additionalIdProperties ) {
477 this.requestQueue.submit(new DeleteBranchRequest(new Location(firstIdProperty, additionalIdProperties)));
478 return nextGraph;
479 }
480
481 /**
482 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
483 *
484 * @param atPath the path to the node that is to be created.
485 * @return an object that may be used to start another request
486 */
487 public Conjunction<Graph> create( String atPath ) {
488 this.requestQueue.submit(new CreateNodeRequest(new Location(createPath(atPath))));
489 return nextGraph;
490 }
491
492 /**
493 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
494 *
495 * @param atPath the path to the node that is to be created.
496 * @param properties the properties for the new node
497 * @return an object that may be used to start another request
498 */
499 public Conjunction<Graph> create( String atPath,
500 Property... properties ) {
501 this.requestQueue.submit(new CreateNodeRequest(new Location(createPath(atPath)), properties));
502 return nextGraph;
503 }
504
505 /**
506 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
507 *
508 * @param at the path to the node that is to be created.
509 * @return an object that may be used to start another request
510 */
511 public Conjunction<Graph> create( Path at ) {
512 this.requestQueue.submit(new CreateNodeRequest(new Location(at)));
513 return nextGraph;
514 }
515
516 /**
517 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
518 *
519 * @param at the path to the node that is to be created.
520 * @param properties the properties for the new node
521 * @return an object that may be used to start another request
522 */
523 public Conjunction<Graph> create( Path at,
524 Property... properties ) {
525 this.requestQueue.submit(new CreateNodeRequest(new Location(at), properties));
526 return nextGraph;
527 }
528
529 /**
530 * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
531 *
532 * @param at the path to the node that is to be created.
533 * @param properties the properties for the new node
534 * @return an object that may be used to start another request
535 */
536 public Conjunction<Graph> create( Path at,
537 Iterable<Property> properties ) {
538 this.requestQueue.submit(new CreateNodeRequest(new Location(at), properties));
539 return nextGraph;
540 }
541
542 /**
543 * Set the properties on a node.
544 *
545 * @param properties the properties to set
546 * @return the remove request object that should be used to specify the node on which the properties are to be set.
547 */
548 public On<Conjunction<Graph>> set( final Property... properties ) {
549 return new On<Conjunction<Graph>>() {
550 @SuppressWarnings( "synthetic-access" )
551 public Conjunction<Graph> on( Location location ) {
552 UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, properties);
553 queue().submit(request);
554 return nextGraph;
555 }
556
557 public Conjunction<Graph> on( String path ) {
558 return on(new Location(createPath(path)));
559 }
560
561 public Conjunction<Graph> on( Path path ) {
562 return on(new Location(path));
563 }
564
565 public Conjunction<Graph> on( Property idProperty ) {
566 return on(new Location(idProperty));
567 }
568
569 public Conjunction<Graph> on( Property firstIdProperty,
570 Property... additionalIdProperties ) {
571 return on(new Location(firstIdProperty, additionalIdProperties));
572 }
573
574 public Conjunction<Graph> on( UUID uuid ) {
575 return on(new Location(uuid));
576 }
577 };
578 }
579
580 /**
581 * Remove properties from the node at the given location.
582 *
583 * @param propertyNames the names of the properties to be removed
584 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
585 */
586 public On<Conjunction<Graph>> remove( final Name... propertyNames ) {
587 return new On<Conjunction<Graph>>() {
588 @SuppressWarnings( "synthetic-access" )
589 public Conjunction<Graph> on( Location location ) {
590 RemovePropertiesRequest request = new RemovePropertiesRequest(location, propertyNames);
591 queue().submit(request);
592 return nextGraph;
593 }
594
595 public Conjunction<Graph> on( String path ) {
596 return on(new Location(createPath(path)));
597 }
598
599 public Conjunction<Graph> on( Path path ) {
600 return on(new Location(path));
601 }
602
603 public Conjunction<Graph> on( Property idProperty ) {
604 return on(new Location(idProperty));
605 }
606
607 public Conjunction<Graph> on( Property firstIdProperty,
608 Property... additionalIdProperties ) {
609 return on(new Location(firstIdProperty, additionalIdProperties));
610 }
611
612 public Conjunction<Graph> on( UUID uuid ) {
613 return on(new Location(uuid));
614 }
615 };
616 }
617
618 /**
619 * Remove properties from the node at the given location.
620 *
621 * @param propertyNames the names of the properties to be removed
622 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
623 */
624 public On<Conjunction<Graph>> remove( String... propertyNames ) {
625 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
626 final List<Name> names = new LinkedList<Name>();
627 for (String propertyName : propertyNames) {
628 names.add(nameFactory.create(propertyName));
629 }
630 return new On<Conjunction<Graph>>() {
631 @SuppressWarnings( "synthetic-access" )
632 public Conjunction<Graph> on( Location location ) {
633 RemovePropertiesRequest request = new RemovePropertiesRequest(location, names);
634 queue().submit(request);
635 return nextGraph;
636 }
637
638 public Conjunction<Graph> on( String path ) {
639 return on(new Location(createPath(path)));
640 }
641
642 public Conjunction<Graph> on( Path path ) {
643 return on(new Location(path));
644 }
645
646 public Conjunction<Graph> on( Property idProperty ) {
647 return on(new Location(idProperty));
648 }
649
650 public Conjunction<Graph> on( Property firstIdProperty,
651 Property... additionalIdProperties ) {
652 return on(new Location(firstIdProperty, additionalIdProperties));
653 }
654
655 public Conjunction<Graph> on( UUID uuid ) {
656 return on(new Location(uuid));
657 }
658 };
659 }
660
661 /**
662 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
663 * object. Once the location is specified, the {@link Collection collection of properties} are read and then returned.
664 *
665 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
666 */
667 public On<Collection<Property>> getProperties() {
668 return new On<Collection<Property>>() {
669 public Collection<Property> on( Location location ) {
670 ReadAllPropertiesRequest request = new ReadAllPropertiesRequest(location);
671 queue().submit(request);
672 return request.getProperties();
673 }
674
675 public Collection<Property> on( String path ) {
676 return on(new Location(createPath(path)));
677 }
678
679 public Collection<Property> on( Path path ) {
680 return on(new Location(path));
681 }
682
683 public Collection<Property> on( Property idProperty ) {
684 return on(new Location(idProperty));
685 }
686
687 public Collection<Property> on( Property firstIdProperty,
688 Property... additionalIdProperties ) {
689 return on(new Location(firstIdProperty, additionalIdProperties));
690 }
691
692 public Collection<Property> on( UUID uuid ) {
693 return on(new Location(uuid));
694 }
695 };
696 }
697
698 /**
699 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
700 * object. Once the location is specified, the {@link Map map of properties} are read and then returned.
701 *
702 * @return the object that is used to specified the node whose properties are to be read, and which will return the properties
703 * as a map keyed by their name
704 */
705 public On<Map<Name, Property>> getPropertiesByName() {
706 return new On<Map<Name, Property>>() {
707 public Map<Name, Property> on( Location location ) {
708 ReadAllPropertiesRequest request = new ReadAllPropertiesRequest(location);
709 queue().submit(request);
710 return request.getPropertiesByName();
711 }
712
713 public Map<Name, Property> on( String path ) {
714 return on(new Location(createPath(path)));
715 }
716
717 public Map<Name, Property> on( Path path ) {
718 return on(new Location(path));
719 }
720
721 public Map<Name, Property> on( Property idProperty ) {
722 return on(new Location(idProperty));
723 }
724
725 public Map<Name, Property> on( Property firstIdProperty,
726 Property... additionalIdProperties ) {
727 return on(new Location(firstIdProperty, additionalIdProperties));
728 }
729
730 public Map<Name, Property> on( UUID uuid ) {
731 return on(new Location(uuid));
732 }
733 };
734 }
735
736 /**
737 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
738 * object. Once the location is specified, the {@link List list of children} are read and then returned.
739 *
740 * @return the object that is used to specified the node whose children are to be read, and which will return the children
741 */
742 public Of<List<Location>> getChildren() {
743 return new Of<List<Location>>() {
744 public List<Location> of( String path ) {
745 return of(new Location(createPath(path)));
746 }
747
748 public List<Location> of( Path path ) {
749 return of(new Location(path));
750 }
751
752 public List<Location> of( Property idProperty ) {
753 return of(new Location(idProperty));
754 }
755
756 public List<Location> of( Property firstIdProperty,
757 Property... additionalIdProperties ) {
758 return of(new Location(firstIdProperty, additionalIdProperties));
759 }
760
761 public List<Location> of( UUID uuid ) {
762 return of(new Location(uuid));
763 }
764
765 public List<Location> of( Location at ) {
766 ReadAllChildrenRequest request = new ReadAllChildrenRequest(at);
767 queue().submit(request);
768 return request.getChildren();
769 }
770 };
771 }
772
773 /**
774 * Request that the children in the specified index range be read on the node defined via the <code>of(...)</code> method on
775 * the returned {@link Of} object. Once the location is specified, the {@link List list of children} are read and then
776 * returned.
777 *
778 * @param startingIndex the index of the first child to be read
779 * @param endingIndex the index past the last the first child to be read
780 * @return the object that is used to specified the node whose children are to be read, and which will return the children
781 */
782 public Of<List<Location>> getChildrenInRange( final int startingIndex,
783 final int endingIndex ) {
784 CheckArg.isNonNegative(startingIndex, "startingIndex");
785 CheckArg.isPositive(endingIndex, "endingIndex");
786 int count = endingIndex - startingIndex;
787 return getChildrenInBlock(startingIndex, count);
788 }
789
790 /**
791 * Request that the children in the specified block be read on the node defined via the <code>of(...)</code> method on the
792 * returned {@link Of} object. Once the location is specified, the {@link List list of children} are read and then returned.
793 *
794 * @param startingIndex the index of the first child to be read
795 * @param blockSize the maximum number of children that should be read
796 * @return the object that is used to specified the node whose children are to be read, and which will return the children
797 */
798 public Of<List<Location>> getChildrenInBlock( final int startingIndex,
799 final int blockSize ) {
800 CheckArg.isNonNegative(startingIndex, "startingIndex");
801 CheckArg.isPositive(blockSize, "blockSize");
802 return new Of<List<Location>>() {
803 public List<Location> of( String path ) {
804 return of(new Location(createPath(path)));
805 }
806
807 public List<Location> of( Path path ) {
808 return of(new Location(path));
809 }
810
811 public List<Location> of( Property idProperty ) {
812 return of(new Location(idProperty));
813 }
814
815 public List<Location> of( Property firstIdProperty,
816 Property... additionalIdProperties ) {
817 return of(new Location(firstIdProperty, additionalIdProperties));
818 }
819
820 public List<Location> of( UUID uuid ) {
821 return of(new Location(uuid));
822 }
823
824 public List<Location> of( Location at ) {
825 ReadBlockOfChildrenRequest request = new ReadBlockOfChildrenRequest(at, startingIndex, blockSize);
826 queue().submit(request);
827 return request.getChildren();
828 }
829 };
830 }
831
832 /**
833 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
834 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
835 *
836 * @param name the name of the property that is to be read
837 * @return the object that is used to specified the node whose property is to be read, and which will return the property
838 */
839 public On<Property> getProperty( final String name ) {
840 Name nameObj = context.getValueFactories().getNameFactory().create(name);
841 return getProperty(nameObj);
842 }
843
844 /**
845 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
846 * returned {@link On} object. Once the location is specified, the {@link Property property} is read and then returned.
847 *
848 * @param name the name of the property that is to be read
849 * @return the object that is used to specified the node whose property is to be read, and which will return the property
850 */
851 public On<Property> getProperty( final Name name ) {
852 return new On<Property>() {
853 public Property on( String path ) {
854 return on(new Location(createPath(path)));
855 }
856
857 public Property on( Path path ) {
858 return on(new Location(path));
859 }
860
861 public Property on( Property idProperty ) {
862 return on(new Location(idProperty));
863 }
864
865 public Property on( Property firstIdProperty,
866 Property... additionalIdProperties ) {
867 return on(new Location(firstIdProperty, additionalIdProperties));
868 }
869
870 public Property on( UUID uuid ) {
871 return on(new Location(uuid));
872 }
873
874 public Property on( Location at ) {
875 ReadPropertyRequest request = new ReadPropertyRequest(at, name);
876 queue().submit(request);
877 return request.getProperty();
878 }
879 };
880 }
881
882 /**
883 * Request to read the node with the supplied UUID.
884 *
885 * @param uuid the UUID of the node that is to be read
886 * @return the node that is read from the repository
887 */
888 public Node getNodeAt( UUID uuid ) {
889 return getNodeAt(new Location(uuid));
890 }
891
892 /**
893 * Request to read the node at the supplied location.
894 *
895 * @param location the location of the node that is to be read
896 * @return the node that is read from the repository
897 */
898 public Node getNodeAt( Location location ) {
899 ReadNodeRequest request = new ReadNodeRequest(location);
900 this.requestQueue.submit(request);
901 return new GraphNode(request);
902 }
903
904 /**
905 * Request to read the node at the supplied path.
906 *
907 * @param path the path of the node that is to be read
908 * @return the node that is read from the repository
909 */
910 public Node getNodeAt( String path ) {
911 return getNodeAt(new Location(createPath(path)));
912 }
913
914 /**
915 * Request to read the node at the supplied path.
916 *
917 * @param path the path of the node that is to be read
918 * @return the node that is read from the repository
919 */
920 public Node getNodeAt( Path path ) {
921 return getNodeAt(new Location(path));
922 }
923
924 /**
925 * Request to read the node with the supplied unique identifier property.
926 *
927 * @param idProperty the identification property that is unique to the node that is to be read
928 * @return the node that is read from the repository
929 */
930 public Node getNodeAt( Property idProperty ) {
931 return getNodeAt(new Location(idProperty));
932 }
933
934 /**
935 * Request to read the node with the supplied unique identifier properties.
936 *
937 * @param firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
938 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be read
939 * @return the node that is read from the repository
940 */
941 public Node getNodeAt( Property firstIdProperty,
942 Property... additionalIdProperties ) {
943 return getNodeAt(new Location(firstIdProperty, additionalIdProperties));
944 }
945
946 /**
947 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code> in
948 * the resulting {@link At} object. All properties and children of every node in the subgraph will be read and returned in the
949 * {@link Subgraph} object returned from the <code>at(...)</code> methods.
950 *
951 * @param depth the maximum depth of the subgraph that should be read
952 * @return the component that should be used to specify the location of the node that is the top of the subgraph, and which
953 * will return the {@link Subgraph} containing the results
954 */
955 public At<Subgraph> getSubgraphOfDepth( final int depth ) {
956 return new At<Subgraph>() {
957 public Subgraph at( Location location ) {
958 ReadBranchRequest request = new ReadBranchRequest(location, depth);
959 queue().submit(request);
960 return new SubgraphResults(request);
961 }
962
963 public Subgraph at( String path ) {
964 return at(new Location(createPath(path)));
965 }
966
967 public Subgraph at( Path path ) {
968 return at(new Location(path));
969 }
970
971 public Subgraph at( UUID uuid ) {
972 return at(new Location(uuid));
973 }
974
975 public Subgraph at( Property idProperty ) {
976 return at(new Location(idProperty));
977 }
978
979 public Subgraph at( Property firstIdProperty,
980 Property... additionalIdProperties ) {
981 return at(new Location(firstIdProperty, additionalIdProperties));
982 }
983 };
984 }
985
986 /**
987 * Import the content from the XML file at the supplied URI, specifying via the returned {@link ImportInto object} where the
988 * content is to be imported.
989 *
990 * @param uri the URI where the importer can read the content that is to be imported
991 * @return the object that should be used to specify into which the content is to be imported
992 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
993 */
994 public ImportInto<Conjunction<Graph>> importXmlFrom( final URI uri ) {
995 return new ImportInto<Conjunction<Graph>>() {
996 private boolean skipRootElement = false;
997
998 public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
999 this.skipRootElement = skipRootElement;
1000 return this;
1001 }
1002
1003 public Conjunction<Graph> into( String path ) throws IOException, SAXException {
1004 return into(new Location(createPath(path)));
1005 }
1006
1007 public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
1008 return into(new Location(path));
1009 }
1010
1011 public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
1012 return into(new Location(idProperty));
1013 }
1014
1015 public Conjunction<Graph> into( Property firstIdProperty,
1016 Property... additionalIdProperties ) throws IOException, SAXException {
1017 return into(new Location(firstIdProperty, additionalIdProperties));
1018 }
1019
1020 public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
1021 return into(new Location(uuid));
1022 }
1023
1024 @SuppressWarnings( "synthetic-access" )
1025 public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
1026 GraphImporter importer = new GraphImporter(Graph.this);
1027 importer.importXml(uri, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
1028 return Graph.this.nextGraph;
1029 }
1030 };
1031 }
1032
1033 /**
1034 * Import the content from the XML file at the supplied file location, specifying via the returned {@link ImportInto object}
1035 * where the content is to be imported.
1036 *
1037 * @param pathToFile the path to the XML file that should be imported.
1038 * @return the object that should be used to specify into which the content is to be imported
1039 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
1040 */
1041 public ImportInto<Conjunction<Graph>> importXmlFrom( String pathToFile ) {
1042 CheckArg.isNotNull(pathToFile, "pathToFile");
1043 return importXmlFrom(new File(pathToFile).toURI());
1044 }
1045
1046 /**
1047 * Import the content from the XML file at the supplied file, specifying via the returned {@link ImportInto object} where the
1048 * content is to be imported.
1049 *
1050 * @param file the XML file that should be imported.
1051 * @return the object that should be used to specify into which the content is to be imported
1052 * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
1053 */
1054 public ImportInto<Conjunction<Graph>> importXmlFrom( File file ) {
1055 CheckArg.isNotNull(file, "file");
1056 return importXmlFrom(file.toURI());
1057 }
1058
1059 /*package*/Path createPath( String path ) {
1060 return getContext().getValueFactories().getPathFactory().create(path);
1061 }
1062
1063 /*package*/void execute( Request request ) {
1064 RepositoryConnection connection = Graph.this.getConnectionFactory().createConnection(getSourceName());
1065 if (connection == null) {
1066 throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
1067 }
1068 try {
1069 connection.execute(Graph.this.getContext(), request);
1070 } finally {
1071 connection.close();
1072 }
1073 if (request.hasError()) {
1074 Throwable error = request.getError();
1075 if (error instanceof RuntimeException) throw (RuntimeException)error;
1076 throw new RepositorySourceException(getSourceName(), error);
1077 }
1078 }
1079
1080 /*package*/List<Segment> getSegments( List<Location> locations ) {
1081 List<Segment> segments = new ArrayList<Segment>(locations.size());
1082 for (Location location : locations) {
1083 segments.add(location.getPath().getLastSegment());
1084 }
1085 return segments;
1086 }
1087
1088 /**
1089 * Begin a batch of requests to perform various operations. Use this approach when multiple operations are to be built and
1090 * then executed with one submission to the underlying {@link #getSourceName() repository source}. The {@link Results results}
1091 * are not available until the {@link Batch#execute()} method is invoked.
1092 *
1093 * @return the batch object used to build and accumulate multiple requests and to submit them all for processing at once.
1094 * @see Batch#execute()
1095 * @see Results
1096 */
1097 public Batch batch() {
1098 return new Batch();
1099 }
1100
1101 /**
1102 * Interface for creating multiple requests to perform various operations. Note that all the requests are accumulated until
1103 * the {@link #execute()} method is called. The results of all the operations are then available in the {@link Results} object
1104 * returned by the {@link #execute()}.
1105 *
1106 * @author Randall Hauch
1107 */
1108 @Immutable
1109 public final class Batch implements Executable {
1110 protected final CompositingRequestQueue requestQueue = new CompositingRequestQueue();
1111 protected final BatchConjunction nextRequests;
1112 protected boolean executed = false;
1113
1114 /*package*/Batch() {
1115 this.nextRequests = new BatchConjunction() {
1116 public Batch and() {
1117 return Batch.this;
1118 }
1119
1120 public Results execute() {
1121 executed = true;
1122 return Batch.this.requestQueue.execute();
1123 }
1124 };
1125 }
1126
1127 /**
1128 * Obtain the graph that this batch uses.
1129 *
1130 * @return the graph; never null
1131 */
1132 public Graph getGraph() {
1133 return Graph.this;
1134 }
1135
1136 protected final void assertNotExecuted() {
1137 if (executed) {
1138 throw new IllegalStateException(GraphI18n.unableToAddMoreRequestsToAlreadyExecutedBatch.text());
1139 }
1140 }
1141
1142 /**
1143 * Begin the request to move the specified node into a parent node at a different location, which is specified via the
1144 * <code>into(...)</code> method on the returned {@link Move} object.
1145 * <p>
1146 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1147 * called.
1148 * </p>
1149 *
1150 * @param from the node that is to be moved.
1151 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1152 * to be moved
1153 */
1154 public Move<BatchConjunction> move( Node from ) {
1155 assertNotExecuted();
1156 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, from.getLocation());
1157 }
1158
1159 /**
1160 * Begin the request to move a node at the specified location into a parent node at a different location, which is
1161 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
1162 * <p>
1163 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1164 * called.
1165 * </p>
1166 *
1167 * @param from the location of the node that is to be moved.
1168 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1169 * to be moved
1170 */
1171 public Move<BatchConjunction> move( Location from ) {
1172 assertNotExecuted();
1173 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, from);
1174 }
1175
1176 /**
1177 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
1178 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
1179 * <p>
1180 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1181 * called.
1182 * </p>
1183 *
1184 * @param fromPath the path to the node that is to be moved.
1185 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1186 * to be moved
1187 */
1188 public Move<BatchConjunction> move( String fromPath ) {
1189 assertNotExecuted();
1190 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(createPath(fromPath)));
1191 }
1192
1193 /**
1194 * Begin the request to move a node located at the supplied path into a parent node at a different location, which is
1195 * specified via the <code>into(...)</code> method on the returned {@link Move} object.
1196 * <p>
1197 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1198 * called.
1199 * </p>
1200 *
1201 * @param from the path to the node that is to be moved.
1202 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1203 * to be moved
1204 */
1205 public Move<BatchConjunction> move( Path from ) {
1206 assertNotExecuted();
1207 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(from));
1208 }
1209
1210 /**
1211 * Begin the request to move a node with the specified unique identifier into a parent node at a different location, which
1212 * is specified via the <code>into(...)</code> method on the returned {@link Move} object.
1213 * <p>
1214 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1215 * called.
1216 * </p>
1217 *
1218 * @param from the UUID of the node that is to be moved.
1219 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1220 * to be moved
1221 */
1222 public Move<BatchConjunction> move( UUID from ) {
1223 assertNotExecuted();
1224 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(from));
1225 }
1226
1227 /**
1228 * Begin the request to move a node with the specified unique identification property into a parent node at a different
1229 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
1230 * identification property should uniquely identify a single node.
1231 * <p>
1232 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1233 * called.
1234 * </p>
1235 *
1236 * @param idProperty the unique identification property of the node that is to be moved.
1237 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1238 * to be moved
1239 */
1240 public Move<BatchConjunction> move( Property idProperty ) {
1241 assertNotExecuted();
1242 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(idProperty));
1243 }
1244
1245 /**
1246 * Begin the request to move a node with the specified identification properties into a parent node at a different
1247 * location, which is specified via the <code>into(...)</code> method on the returned {@link Move} object. The
1248 * identification properties should uniquely identify a single node.
1249 * <p>
1250 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1251 * called.
1252 * </p>
1253 *
1254 * @param firstIdProperty the first identification property of the node that is to be moved
1255 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be moved
1256 * @return the object that can be used to specify addition nodes to be moved or the location of the node where the node is
1257 * to be moved
1258 */
1259 public Move<BatchConjunction> move( Property firstIdProperty,
1260 Property... additionalIdProperties ) {
1261 assertNotExecuted();
1262 return new MoveAction<BatchConjunction>(this.nextRequests, this.requestQueue, new Location(firstIdProperty,
1263 additionalIdProperties));
1264 }
1265
1266 /**
1267 * Begin the request to copy the specified node into a parent node at a different location, which is specified via the
1268 * <code>into(...)</code> method on the returned {@link Copy} object.
1269 * <p>
1270 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1271 * called.
1272 * </p>
1273 *
1274 * @param from the node that is to be copied.
1275 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1276 * is to be copied
1277 */
1278 public Copy<BatchConjunction> copy( Node from ) {
1279 assertNotExecuted();
1280 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, from.getLocation());
1281 }
1282
1283 /**
1284 * Begin the request to copy a node at the specified location into a parent node at a different location, which is
1285 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
1286 * <p>
1287 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1288 * called.
1289 * </p>
1290 *
1291 * @param from the location of the node that is to be copied.
1292 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1293 * is to be copied
1294 */
1295 public Copy<BatchConjunction> copy( Location from ) {
1296 assertNotExecuted();
1297 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, from);
1298 }
1299
1300 /**
1301 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
1302 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
1303 * <p>
1304 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1305 * called.
1306 * </p>
1307 *
1308 * @param fromPath the path to the node that is to be copied.
1309 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1310 * is to be copied
1311 */
1312 public Copy<BatchConjunction> copy( String fromPath ) {
1313 assertNotExecuted();
1314 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(createPath(fromPath)));
1315 }
1316
1317 /**
1318 * Begin the request to copy a node located at the supplied path into a parent node at a different location, which is
1319 * specified via the <code>into(...)</code> method on the returned {@link Copy} object.
1320 * <p>
1321 * Like all other methods on the {@link Graph}, the copy request will be performed immediately when the
1322 * <code>into(...)</code> method is called.
1323 * </p>
1324 *
1325 * @param from the path to the node that is to be copied.
1326 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1327 * is to be copied
1328 */
1329 public Copy<BatchConjunction> copy( Path from ) {
1330 assertNotExecuted();
1331 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(from));
1332 }
1333
1334 /**
1335 * Begin the request to copy a node with the specified unique identifier into a parent node at a different location, which
1336 * is specified via the <code>into(...)</code> method on the returned {@link Copy} object.
1337 * <p>
1338 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1339 * called.
1340 * </p>
1341 *
1342 * @param from the UUID of the node that is to be copied.
1343 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1344 * is to be copied
1345 */
1346 public Copy<BatchConjunction> copy( UUID from ) {
1347 assertNotExecuted();
1348 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(from));
1349 }
1350
1351 /**
1352 * Begin the request to copy a node with the specified unique identification property into a parent node at a different
1353 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
1354 * identification property should uniquely identify a single node.
1355 * <p>
1356 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1357 * called.
1358 * </p>
1359 *
1360 * @param idProperty the unique identification property of the node that is to be copied.
1361 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1362 * is to be copied
1363 */
1364 public Copy<BatchConjunction> copy( Property idProperty ) {
1365 assertNotExecuted();
1366 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(idProperty));
1367 }
1368
1369 /**
1370 * Begin the request to copy a node with the specified identification properties into a parent node at a different
1371 * location, which is specified via the <code>into(...)</code> method on the returned {@link Copy} object. The
1372 * identification properties should uniquely identify a single node.
1373 * <p>
1374 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1375 * called.
1376 * </p>
1377 *
1378 * @param firstIdProperty the first identification property of the node that is to be copied
1379 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
1380 * @return the object that can be used to specify addition nodes to be copied or the location of the node where the node
1381 * is to be copied
1382 */
1383 public Copy<BatchConjunction> copy( Property firstIdProperty,
1384 Property... additionalIdProperties ) {
1385 assertNotExecuted();
1386 return new CopyAction<BatchConjunction>(nextRequests, this.requestQueue, new Location(firstIdProperty,
1387 additionalIdProperties));
1388 }
1389
1390 /**
1391 * Request to delete the specified node.
1392 * <p>
1393 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1394 * called.
1395 * </p>
1396 *
1397 * @param at the node that is to be deleted
1398 * @return an object that may be used to start another request
1399 */
1400 public BatchConjunction delete( Node at ) {
1401 assertNotExecuted();
1402 this.requestQueue.submit(new DeleteBranchRequest(at.getLocation()));
1403 return nextRequests;
1404 }
1405
1406 /**
1407 * Request to delete the node at the given location.
1408 * <p>
1409 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1410 * called.
1411 * </p>
1412 *
1413 * @param at the location of the node that is to be deleted
1414 * @return an object that may be used to start another request
1415 */
1416 public BatchConjunction delete( Location at ) {
1417 assertNotExecuted();
1418 this.requestQueue.submit(new DeleteBranchRequest(at));
1419 return nextRequests;
1420 }
1421
1422 /**
1423 * Request to delete the node at the given path.
1424 * <p>
1425 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1426 * called.
1427 * </p>
1428 *
1429 * @param atPath the path of the node that is to be deleted
1430 * @return an object that may be used to start another request
1431 */
1432 public BatchConjunction delete( String atPath ) {
1433 assertNotExecuted();
1434 this.requestQueue.submit(new DeleteBranchRequest(new Location(createPath(atPath))));
1435 return nextRequests;
1436 }
1437
1438 /**
1439 * Request to delete the node at the given path.
1440 * <p>
1441 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1442 * called.
1443 * </p>
1444 *
1445 * @param at the path of the node that is to be deleted
1446 * @return an object that may be used to start another request
1447 */
1448 public BatchConjunction delete( Path at ) {
1449 assertNotExecuted();
1450 this.requestQueue.submit(new DeleteBranchRequest(new Location(at)));
1451 return nextRequests;
1452 }
1453
1454 /**
1455 * Request to delete the node with the given UUID.
1456 * <p>
1457 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1458 * called.
1459 * </p>
1460 *
1461 * @param at the UUID of the node that is to be deleted
1462 * @return an object that may be used to start another request
1463 */
1464 public BatchConjunction delete( UUID at ) {
1465 assertNotExecuted();
1466 this.requestQueue.submit(new DeleteBranchRequest(new Location(at)));
1467 return nextRequests;
1468 }
1469
1470 /**
1471 * Request to delete the node with the given unique identification property.
1472 * <p>
1473 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1474 * called.
1475 * </p>
1476 *
1477 * @param idProperty the unique identifying property of the node that is to be deleted
1478 * @return an object that may be used to start another request
1479 */
1480 public BatchConjunction delete( Property idProperty ) {
1481 assertNotExecuted();
1482 this.requestQueue.submit(new DeleteBranchRequest(new Location(idProperty)));
1483 return nextRequests;
1484 }
1485
1486 /**
1487 * Request to delete the node with the given identification properties. The identification properties should uniquely
1488 * identify a single node.
1489 * <p>
1490 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1491 * called.
1492 * </p>
1493 *
1494 * @param firstIdProperty the first identification property of the node that is to be copied
1495 * @param additionalIdProperties the remaining idenficiation properties of the node that is to be copied
1496 * @return an object that may be used to start another request
1497 */
1498 public BatchConjunction delete( Property firstIdProperty,
1499 Property... additionalIdProperties ) {
1500 assertNotExecuted();
1501 this.requestQueue.submit(new DeleteBranchRequest(new Location(firstIdProperty, additionalIdProperties)));
1502 return nextRequests;
1503 }
1504
1505 /**
1506 * Begin the request to create a node located at the supplied path.
1507 * <p>
1508 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1509 * called.
1510 * </p>
1511 *
1512 * @param atPath the path to the node that is to be created.
1513 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1514 * node where the node is to be created
1515 */
1516 public Create<BatchConjunction> create( String atPath ) {
1517 assertNotExecuted();
1518 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(createPath(atPath)));
1519 }
1520
1521 /**
1522 * Begin the request to create a node located at the supplied path.
1523 * <p>
1524 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1525 * called.
1526 * </p>
1527 *
1528 * @param atPath the path to the node that is to be created.
1529 * @param property a property for the new node
1530 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1531 * node where the node is to be created
1532 */
1533 public Create<BatchConjunction> create( String atPath,
1534 Property property ) {
1535 assertNotExecuted();
1536 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(createPath(atPath))).with(property);
1537 }
1538
1539 /**
1540 * Begin the request to create a node located at the supplied path.
1541 * <p>
1542 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1543 * called.
1544 * </p>
1545 *
1546 * @param atPath the path to the node that is to be created.
1547 * @param firstProperty a property for the new node
1548 * @param additionalProperties additional properties for the new node
1549 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1550 * node where the node is to be created
1551 */
1552 public Create<BatchConjunction> create( String atPath,
1553 Property firstProperty,
1554 Property... additionalProperties ) {
1555 assertNotExecuted();
1556 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(createPath(atPath))).with(firstProperty,
1557 additionalProperties);
1558 }
1559
1560 /**
1561 * Begin the request to create a node located at the supplied path.
1562 * <p>
1563 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1564 * called.
1565 * </p>
1566 *
1567 * @param at the path to the node that is to be created.
1568 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1569 * node where the node is to be created
1570 */
1571 public Create<BatchConjunction> create( Path at ) {
1572 assertNotExecuted();
1573 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(at));
1574 }
1575
1576 /**
1577 * Begin the request to create a node located at the supplied path.
1578 * <p>
1579 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1580 * called.
1581 * </p>
1582 *
1583 * @param at the path to the node that is to be created.
1584 * @param properties the iterator over the properties for the new node
1585 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1586 * node where the node is to be created
1587 */
1588 public Create<BatchConjunction> create( Path at,
1589 Iterable<Property> properties ) {
1590 assertNotExecuted();
1591 CreateAction<BatchConjunction> action = new CreateAction<BatchConjunction>(nextRequests, requestQueue,
1592 new Location(at));
1593 for (Property property : properties) {
1594 action.and(property);
1595 }
1596 return action;
1597 }
1598
1599 /**
1600 * Begin the request to create a node located at the supplied path.
1601 * <p>
1602 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1603 * called.
1604 * </p>
1605 *
1606 * @param at the path to the node that is to be created.
1607 * @param property a property for the new node
1608 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1609 * node where the node is to be created
1610 */
1611 public Create<BatchConjunction> create( Path at,
1612 Property property ) {
1613 assertNotExecuted();
1614 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(at)).with(property);
1615 }
1616
1617 /**
1618 * Begin the request to create a node located at the supplied path.
1619 * <p>
1620 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1621 * called.
1622 * </p>
1623 *
1624 * @param at the path to the node that is to be created.
1625 * @param firstProperty a property for the new node
1626 * @param additionalProperties additional properties for the new node
1627 * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
1628 * node where the node is to be created
1629 */
1630 public Create<BatchConjunction> create( Path at,
1631 Property firstProperty,
1632 Property... additionalProperties ) {
1633 assertNotExecuted();
1634 return new CreateAction<BatchConjunction>(nextRequests, requestQueue, new Location(at)).with(firstProperty,
1635 additionalProperties);
1636 }
1637
1638 /**
1639 * Set the properties on a node.
1640 *
1641 * @param properties the properties to set
1642 * @return the remove request object that should be used to specify the node on which the properties are to be set.
1643 */
1644 public On<BatchConjunction> set( final Property... properties ) {
1645 return new On<BatchConjunction>() {
1646 public BatchConjunction on( Location location ) {
1647 UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, properties);
1648 queue().submit(request);
1649 return nextRequests;
1650 }
1651
1652 public BatchConjunction on( String path ) {
1653 return on(new Location(createPath(path)));
1654 }
1655
1656 public BatchConjunction on( Path path ) {
1657 return on(new Location(path));
1658 }
1659
1660 public BatchConjunction on( Property idProperty ) {
1661 return on(new Location(idProperty));
1662 }
1663
1664 public BatchConjunction on( Property firstIdProperty,
1665 Property... additionalIdProperties ) {
1666 return on(new Location(firstIdProperty, additionalIdProperties));
1667 }
1668
1669 public BatchConjunction on( UUID uuid ) {
1670 return on(new Location(uuid));
1671 }
1672 };
1673 }
1674
1675 /**
1676 * Remove properties from the node at the given location.
1677 *
1678 * @param propertyNames the names of the properties to be removed
1679 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1680 */
1681 public On<BatchConjunction> remove( final Name... propertyNames ) {
1682 return new On<BatchConjunction>() {
1683 public BatchConjunction on( Location location ) {
1684 RemovePropertiesRequest request = new RemovePropertiesRequest(location, propertyNames);
1685 queue().submit(request);
1686 return nextRequests;
1687 }
1688
1689 public BatchConjunction on( String path ) {
1690 return on(new Location(createPath(path)));
1691 }
1692
1693 public BatchConjunction on( Path path ) {
1694 return on(new Location(path));
1695 }
1696
1697 public BatchConjunction on( Property idProperty ) {
1698 return on(new Location(idProperty));
1699 }
1700
1701 public BatchConjunction on( Property firstIdProperty,
1702 Property... additionalIdProperties ) {
1703 return on(new Location(firstIdProperty, additionalIdProperties));
1704 }
1705
1706 public BatchConjunction on( UUID uuid ) {
1707 return on(new Location(uuid));
1708 }
1709 };
1710 }
1711
1712 /**
1713 * Remove properties from the node at the given location.
1714 *
1715 * @param propertyNames the names of the properties to be removed
1716 * @return the remove request object that should be used to specify the node from which the properties are to be removed.
1717 */
1718 public On<BatchConjunction> remove( String... propertyNames ) {
1719 NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
1720 final List<Name> names = new LinkedList<Name>();
1721 for (String propertyName : propertyNames) {
1722 names.add(nameFactory.create(propertyName));
1723 }
1724 return new On<BatchConjunction>() {
1725 public BatchConjunction on( Location location ) {
1726 RemovePropertiesRequest request = new RemovePropertiesRequest(location, names);
1727 queue().submit(request);
1728 return nextRequests;
1729 }
1730
1731 public BatchConjunction on( String path ) {
1732 return on(new Location(createPath(path)));
1733 }
1734
1735 public BatchConjunction on( Path path ) {
1736 return on(new Location(path));
1737 }
1738
1739 public BatchConjunction on( Property idProperty ) {
1740 return on(new Location(idProperty));
1741 }
1742
1743 public BatchConjunction on( Property firstIdProperty,
1744 Property... additionalIdProperties ) {
1745 return on(new Location(firstIdProperty, additionalIdProperties));
1746 }
1747
1748 public BatchConjunction on( UUID uuid ) {
1749 return on(new Location(uuid));
1750 }
1751 };
1752 }
1753
1754 /**
1755 * Request to read the node with the supplied UUID.
1756 * <p>
1757 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1758 * called.
1759 * </p>
1760 *
1761 * @param uuid the UUID of the node that is to be read
1762 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1763 */
1764 public BatchConjunction read( UUID uuid ) {
1765 return read(new Location(uuid));
1766 }
1767
1768 /**
1769 * Request to read the node at the supplied location.
1770 * <p>
1771 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1772 * called.
1773 * </p>
1774 *
1775 * @param location the location of the node that is to be read
1776 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1777 */
1778 public BatchConjunction read( Location location ) {
1779 assertNotExecuted();
1780 ReadNodeRequest request = new ReadNodeRequest(location);
1781 requestQueue.submit(request);
1782 return nextRequests;
1783 }
1784
1785 /**
1786 * Request to read the node at the supplied path.
1787 * <p>
1788 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1789 * called.
1790 * </p>
1791 *
1792 * @param path the path of the node that is to be read
1793 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1794 */
1795 public BatchConjunction read( String path ) {
1796 return read(new Location(createPath(path)));
1797 }
1798
1799 /**
1800 * Request to read the node at the supplied path.
1801 * <p>
1802 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1803 * called.
1804 * </p>
1805 *
1806 * @param path the path of the node that is to be read
1807 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1808 */
1809 public BatchConjunction read( Path path ) {
1810 return read(new Location(path));
1811 }
1812
1813 /**
1814 * Request to read the node with the supplied unique identifier property.
1815 * <p>
1816 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1817 * called.
1818 * </p>
1819 *
1820 * @param idProperty the identification property that is unique to the node that is to be read
1821 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1822 */
1823 public BatchConjunction read( Property idProperty ) {
1824 return read(new Location(idProperty));
1825 }
1826
1827 /**
1828 * Request to read the node with the supplied unique identifier properties.
1829 * <p>
1830 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1831 * called.
1832 * </p>
1833 *
1834 * @param firstIdProperty the first of the identification properties that uniquely identify the node that is to be read
1835 * @param additionalIdProperties the remaining identification properties that uniquely identify the node that is to be
1836 * read
1837 * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
1838 */
1839 public BatchConjunction read( Property firstIdProperty,
1840 Property... additionalIdProperties ) {
1841 return read(new Location(firstIdProperty, additionalIdProperties));
1842 }
1843
1844 /**
1845 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
1846 * returned {@link On} object.
1847 * <p>
1848 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1849 * called.
1850 * </p>
1851 *
1852 * @param propertyName the name of the property that is to be read
1853 * @return the object that is used to specified the node whose property is to be read
1854 */
1855 public On<BatchConjunction> readProperty( String propertyName ) {
1856 assertNotExecuted();
1857 Name name = Graph.this.getContext().getValueFactories().getNameFactory().create(propertyName);
1858 return readProperty(name);
1859 }
1860
1861 /**
1862 * Request that the property with the given name be read on the node defined via the <code>on(...)</code> method on the
1863 * returned {@link On} object.
1864 * <p>
1865 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1866 * called.
1867 * </p>
1868 *
1869 * @param name the name of the property that is to be read
1870 * @return the object that is used to specified the node whose property is to be read
1871 */
1872 public On<BatchConjunction> readProperty( final Name name ) {
1873 assertNotExecuted();
1874 return new On<BatchConjunction>() {
1875 public BatchConjunction on( String path ) {
1876 return on(new Location(createPath(path)));
1877 }
1878
1879 public BatchConjunction on( Path path ) {
1880 return on(new Location(path));
1881 }
1882
1883 public BatchConjunction on( Property idProperty ) {
1884 return on(new Location(idProperty));
1885 }
1886
1887 public BatchConjunction on( Property firstIdProperty,
1888 Property... additionalIdProperties ) {
1889 return on(new Location(firstIdProperty, additionalIdProperties));
1890 }
1891
1892 public BatchConjunction on( UUID uuid ) {
1893 return on(new Location(uuid));
1894 }
1895
1896 public BatchConjunction on( Location at ) {
1897 ReadPropertyRequest request = new ReadPropertyRequest(at, name);
1898 queue().submit(request);
1899 return Batch.this.nextRequests;
1900 }
1901 };
1902 }
1903
1904 /**
1905 * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
1906 * object.
1907 * <p>
1908 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1909 * called.
1910 * </p>
1911 *
1912 * @return the object that is used to specified the node whose properties are to be read,
1913 */
1914 public On<BatchConjunction> readProperties() {
1915 assertNotExecuted();
1916 return new On<BatchConjunction>() {
1917 public BatchConjunction on( Location location ) {
1918 ReadAllPropertiesRequest request = new ReadAllPropertiesRequest(location);
1919 queue().submit(request);
1920 return Batch.this.nextRequests;
1921 }
1922
1923 public BatchConjunction on( String path ) {
1924 return on(new Location(createPath(path)));
1925 }
1926
1927 public BatchConjunction on( Path path ) {
1928 return on(new Location(path));
1929 }
1930
1931 public BatchConjunction on( Property idProperty ) {
1932 return on(new Location(idProperty));
1933 }
1934
1935 public BatchConjunction on( Property firstIdProperty,
1936 Property... additionalIdProperties ) {
1937 return on(new Location(firstIdProperty, additionalIdProperties));
1938 }
1939
1940 public BatchConjunction on( UUID uuid ) {
1941 return on(new Location(uuid));
1942 }
1943 };
1944 }
1945
1946 /**
1947 * Request that the children be read on the node defined via the <code>of(...)</code> method on the returned {@link Of}
1948 * object.
1949 * <p>
1950 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1951 * called.
1952 * </p>
1953 *
1954 * @return the object that is used to specified the node whose children are to be read
1955 */
1956 public Of<BatchConjunction> readChildren() {
1957 assertNotExecuted();
1958 return new Of<BatchConjunction>() {
1959 public BatchConjunction of( String path ) {
1960 return of(new Location(createPath(path)));
1961 }
1962
1963 public BatchConjunction of( Path path ) {
1964 return of(new Location(path));
1965 }
1966
1967 public BatchConjunction of( Property idProperty ) {
1968 return of(new Location(idProperty));
1969 }
1970
1971 public BatchConjunction of( Property firstIdProperty,
1972 Property... additionalIdProperties ) {
1973 return of(new Location(firstIdProperty, additionalIdProperties));
1974 }
1975
1976 public BatchConjunction of( UUID uuid ) {
1977 return of(new Location(uuid));
1978 }
1979
1980 public BatchConjunction of( Location at ) {
1981 ReadAllChildrenRequest request = new ReadAllChildrenRequest(at);
1982 queue().submit(request);
1983 return Batch.this.nextRequests;
1984 }
1985 };
1986 }
1987
1988 /**
1989 * Request to read a subgraph of the specified depth, rooted at a location that will be specified via <code>at(...)</code>
1990 * in the resulting {@link At} object.
1991 * <p>
1992 * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
1993 * called.
1994 * </p>
1995 *
1996 * @param depth the maximum depth of the subgraph that should be read
1997 * @return the component that should be used to specify the location of the node that is the top of the subgraph
1998 */
1999 public At<BatchConjunction> readSubgraphOfDepth( final int depth ) {
2000 assertNotExecuted();
2001 return new At<BatchConjunction>() {
2002 public BatchConjunction at( Location location ) {
2003 ReadBranchRequest request = new ReadBranchRequest(location, depth);
2004 queue().submit(request);
2005 return Batch.this.nextRequests;
2006 }
2007
2008 public BatchConjunction at( String path ) {
2009 return at(new Location(createPath(path)));
2010 }
2011
2012 public BatchConjunction at( Path path ) {
2013 return at(new Location(path));
2014 }
2015
2016 public BatchConjunction at( UUID uuid ) {
2017 return at(new Location(uuid));
2018 }
2019
2020 public BatchConjunction at( Property idProperty ) {
2021 return at(new Location(idProperty));
2022 }
2023
2024 public BatchConjunction at( Property firstIdProperty,
2025 Property... additionalIdProperties ) {
2026 return at(new Location(firstIdProperty, additionalIdProperties));
2027 }
2028 };
2029 }
2030
2031 public Results execute() {
2032 return this.requestQueue.execute();
2033 }
2034 }
2035
2036 /**
2037 * A interface used to execute the accumulated {@link Batch requests}.
2038 *
2039 * @author Randall Hauch
2040 */
2041 public interface Executable {
2042 /**
2043 * Stop accumulating the requests, submit them to the repository source, and return the results.
2044 *
2045 * @return the results containing the requested information from the repository.
2046 */
2047 Results execute();
2048 }
2049
2050 /**
2051 * A interface that can be used to finish the current request and start another.
2052 *
2053 * @param <Next> the interface that will be used to start another request
2054 * @author Randall Hauch
2055 */
2056 public interface Conjunction<Next> {
2057 /**
2058 * Finish the request and prepare to start another.
2059 *
2060 * @return the interface that can be used to start another request; never null
2061 */
2062 Next and();
2063 }
2064
2065 /**
2066 * A component that defines the location into which a node should be copied or moved.
2067 *
2068 * @param <Next> The interface that is to be returned when this request is completed
2069 * @author Randall Hauch
2070 */
2071 public interface Into<Next> {
2072 /**
2073 * Finish the request by specifying the new location into which the node should be copied/moved.
2074 *
2075 * @param to the location of the new parent
2076 * @return the interface for additional requests or actions
2077 */
2078 Next into( Location to );
2079
2080 /**
2081 * Finish the request by specifying the new location into which the node should be copied/moved.
2082 *
2083 * @param toPath the path of the new parent
2084 * @return the interface for additional requests or actions
2085 */
2086 Next into( String toPath );
2087
2088 /**
2089 * Finish the request by specifying the new location into which the node should be copied/moved.
2090 *
2091 * @param to the path of the new parent
2092 * @return the interface for additional requests or actions
2093 */
2094 Next into( Path to );
2095
2096 /**
2097 * Finish the request by specifying the new location into which the node should be copied/moved.
2098 *
2099 * @param to the UUID of the new parent
2100 * @return the interface for additional requests or actions
2101 */
2102 Next into( UUID to );
2103
2104 /**
2105 * Finish the request by specifying the new location into which the node should be copied/moved.
2106 *
2107 * @param idProperty the property that uniquely identifies the new parent
2108 * @return the interface for additional requests or actions
2109 */
2110 Next into( Property idProperty );
2111
2112 /**
2113 * Finish the request by specifying the new location into which the node should be copied/moved.
2114 *
2115 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2116 * new parent
2117 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2118 * identifies the new parent
2119 * @return the interface for additional requests or actions
2120 */
2121 Next into( Property firstIdProperty,
2122 Property... additionalIdProperties );
2123 }
2124
2125 /**
2126 * A interface that is used to add more locations that are to be copied/moved.
2127 *
2128 * @param <Next> The interface that is to be returned when this request is completed
2129 * @author Randall Hauch
2130 */
2131 public interface And<Next> {
2132 /**
2133 * Specify that another node should also be copied or moved.
2134 *
2135 * @param from the location of the node to be copied or moved
2136 * @return the interface for finishing the request
2137 */
2138 Next and( Location from );
2139
2140 /**
2141 * Specify that another node should also be copied or moved.
2142 *
2143 * @param fromPath the path of the node to be copied or moved
2144 * @return the interface for finishing the request
2145 */
2146 Next and( String fromPath );
2147
2148 /**
2149 * Specify that another node should also be copied or moved.
2150 *
2151 * @param from the path of the node to be copied or moved
2152 * @return the interface for finishing the request
2153 */
2154 Next and( Path from );
2155
2156 /**
2157 * Specify that another node should also be copied or moved.
2158 *
2159 * @param from the UUID of the node to be copied or moved
2160 * @return the interface for finishing the request
2161 */
2162 Next and( UUID from );
2163
2164 /**
2165 * Specify that another node should also be copied or moved.
2166 *
2167 * @param idProperty the property that uniquely identifies the node to be copied or moved
2168 * @return the interface for finishing the request
2169 */
2170 Next and( Property idProperty );
2171
2172 /**
2173 * Specify that another node should also be copied or moved.
2174 *
2175 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2176 * node to be copied or moved
2177 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2178 * identifies the node to be copied or moved
2179 * @return the interface for finishing the request
2180 */
2181 Next and( Property firstIdProperty,
2182 Property... additionalIdProperties );
2183 }
2184
2185 /**
2186 * The interface for defining additional nodes to be moved and the parent into which the node(s) are to be moved.
2187 *
2188 * @param <Next> The interface that is to be returned when this request is completed
2189 * @author Randall Hauch
2190 */
2191 public interface Move<Next> extends Into<Next>, And<Move<Next>> {
2192 }
2193
2194 /**
2195 * The interface for defining additional nodes to be copied and the parent into which the node(s) are to be copied. where the
2196 * node(s) are to be moved.
2197 *
2198 * @param <Next> The interface that is to be returned when this request is completed
2199 * @author Randall Hauch
2200 */
2201 public interface Copy<Next> extends Into<Next>, And<Copy<Next>> {
2202 }
2203
2204 /**
2205 * The interface for defining additional properties on a new node.
2206 *
2207 * @param <Next> The interface that is to be returned when this create request is completed
2208 * @author Randall Hauch
2209 */
2210 public interface Create<Next> extends Conjunction<Next>, Executable {
2211 /**
2212 * Specify the UUID that should the new node should have. This is an alias for {@link #and(UUID)}.
2213 *
2214 * @param uuid the UUID
2215 * @return this same interface so additional properties may be added
2216 */
2217 Create<Next> with( UUID uuid );
2218
2219 /**
2220 * Specify a property that should the new node should have. This is an alias for {@link #and(Property)}.
2221 *
2222 * @param property the property
2223 * @return this same interface so additional properties may be added
2224 */
2225 Create<Next> with( Property property );
2226
2227 /**
2228 * Specify a property that should the new node should have. This is an alias for {@link #and(String, Object...)}.
2229 *
2230 * @param propertyName the name of the property
2231 * @param values the property values
2232 * @return this same interface so additional properties may be added
2233 */
2234 Create<Next> with( String propertyName,
2235 Object... values );
2236
2237 /**
2238 * Specify a property that should the new node should have. This is an alias for {@link #and(Name, Object...)}.
2239 *
2240 * @param propertyName the name of the property
2241 * @param values the property values
2242 * @return this same interface so additional properties may be added
2243 */
2244 Create<Next> with( Name propertyName,
2245 Object... values );
2246
2247 /**
2248 * Specify properties that should the new node should have. This is an alias for {@link #and(Property, Property...)}.
2249 *
2250 * @param firstProperty the first property
2251 * @param additionalProperties the additional property
2252 * @return this same interface so additional properties may be added
2253 */
2254 Create<Next> with( Property firstProperty,
2255 Property... additionalProperties );
2256
2257 /**
2258 * Specify the UUID that should the new node should have.
2259 *
2260 * @param uuid the UUID
2261 * @return this same interface so additional properties may be added
2262 */
2263 Create<Next> and( UUID uuid );
2264
2265 /**
2266 * Specify a property that should the new node should have.
2267 *
2268 * @param property the property
2269 * @return this same interface so additional properties may be added
2270 */
2271 Create<Next> and( Property property );
2272
2273 /**
2274 * Specify a property that should the new node should have.
2275 *
2276 * @param propertyName the name of the property
2277 * @param values the property values
2278 * @return this same interface so additional properties may be added
2279 */
2280 Create<Next> and( String propertyName,
2281 Object... values );
2282
2283 /**
2284 * Specify a property that should the new node should have.
2285 *
2286 * @param propertyName the name of the property
2287 * @param values the property values
2288 * @return this same interface so additional properties may be added
2289 */
2290 Create<Next> and( Name propertyName,
2291 Object... values );
2292
2293 /**
2294 * Specify properties that should the new node should have.
2295 *
2296 * @param firstProperty the first property
2297 * @param additionalProperties the additional property
2298 * @return this same interface so additional properties may be added
2299 */
2300 Create<Next> and( Property firstProperty,
2301 Property... additionalProperties );
2302 }
2303
2304 /**
2305 * The interface for defining the node upon which a request operates.
2306 *
2307 * @param <Next> The interface that is to be returned when the request is completed
2308 * @author Randall Hauch
2309 */
2310 public interface On<Next> {
2311 /**
2312 * Specify the location of the node upon which the request is to operate.
2313 *
2314 * @param to the location of the new parent
2315 * @return the interface for additional requests or actions
2316 */
2317 Next on( Location to );
2318
2319 /**
2320 * Specify the path of the node upon which the request is to operate.
2321 *
2322 * @param toPath the path of the new parent
2323 * @return the interface for additional requests or actions
2324 */
2325 Next on( String toPath );
2326
2327 /**
2328 * Specify the path of the node upon which the request is to operate.
2329 *
2330 * @param to the path of the new parent
2331 * @return the interface for additional requests or actions
2332 */
2333 Next on( Path to );
2334
2335 /**
2336 * Specify the UUID of the node upon which the request is to operate.
2337 *
2338 * @param to the UUID of the new parent
2339 * @return the interface for additional requests or actions
2340 */
2341 Next on( UUID to );
2342
2343 /**
2344 * Specify the unique identification property that identifies the node upon which the request is to operate.
2345 *
2346 * @param idProperty the property that uniquely identifies the new parent
2347 * @return the interface for additional requests or actions
2348 */
2349 Next on( Property idProperty );
2350
2351 /**
2352 * Specify the unique identification properties that identify the node upon which the request is to operate.
2353 *
2354 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2355 * new parent
2356 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2357 * identifies the new parent
2358 * @return the interface for additional requests or actions
2359 */
2360 Next on( Property firstIdProperty,
2361 Property... additionalIdProperties );
2362 }
2363
2364 /**
2365 * The interface for defining the node upon which a request operates.
2366 *
2367 * @param <Next> The interface that is to be returned when the request is completed
2368 * @author Randall Hauch
2369 */
2370 public interface Of<Next> {
2371 /**
2372 * Specify the location of the node upon which the request is to operate.
2373 *
2374 * @param to the location of the new parent
2375 * @return the interface for additional requests or actions
2376 */
2377 Next of( Location to );
2378
2379 /**
2380 * Specify the path of the node upon which the request is to operate.
2381 *
2382 * @param toPath the path of the new parent
2383 * @return the interface for additional requests or actions
2384 */
2385 Next of( String toPath );
2386
2387 /**
2388 * Specify the path of the node upon which the request is to operate.
2389 *
2390 * @param to the path of the new parent
2391 * @return the interface for additional requests or actions
2392 */
2393 Next of( Path to );
2394
2395 /**
2396 * Specify the UUID of the node upon which the request is to operate.
2397 *
2398 * @param to the UUID of the new parent
2399 * @return the interface for additional requests or actions
2400 */
2401 Next of( UUID to );
2402
2403 /**
2404 * Specify the unique identification property that identifies the node upon which the request is to operate.
2405 *
2406 * @param idProperty the property that uniquely identifies the new parent
2407 * @return the interface for additional requests or actions
2408 */
2409 Next of( Property idProperty );
2410
2411 /**
2412 * Specify the unique identification properties that identify the node upon which the request is to operate.
2413 *
2414 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2415 * new parent
2416 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2417 * identifies the new parent
2418 * @return the interface for additional requests or actions
2419 */
2420 Next of( Property firstIdProperty,
2421 Property... additionalIdProperties );
2422 }
2423
2424 /**
2425 * The interface for defining the node upon which which a request operates.
2426 *
2427 * @param <Next> The interface that is to be returned when the request is completed
2428 * @author Randall Hauch
2429 */
2430 public interface At<Next> {
2431 /**
2432 * Specify the location of the node upon which the request is to operate.
2433 *
2434 * @param to the location of the new parent
2435 * @return the interface for additional requests or actions
2436 */
2437 Next at( Location to );
2438
2439 /**
2440 * Specify the path of the node upon which the request is to operate.
2441 *
2442 * @param toPath the path of the new parent
2443 * @return the interface for additional requests or actions
2444 */
2445 Next at( String toPath );
2446
2447 /**
2448 * Specify the path of the node upon which the request is to operate.
2449 *
2450 * @param to the path of the new parent
2451 * @return the interface for additional requests or actions
2452 */
2453 Next at( Path to );
2454
2455 /**
2456 * Specify the UUID of the node upon which the request is to operate.
2457 *
2458 * @param to the UUID of the new parent
2459 * @return the interface for additional requests or actions
2460 */
2461 Next at( UUID to );
2462
2463 /**
2464 * Specify the unique identification property that identifies the node upon which the request is to operate.
2465 *
2466 * @param idProperty the property that uniquely identifies the new parent
2467 * @return the interface for additional requests or actions
2468 */
2469 Next at( Property idProperty );
2470
2471 /**
2472 * Specify the unique identification properties that identify the node upon which the request is to operate.
2473 *
2474 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2475 * new parent
2476 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2477 * identifies the new parent
2478 * @return the interface for additional requests or actions
2479 */
2480 Next at( Property firstIdProperty,
2481 Property... additionalIdProperties );
2482 }
2483
2484 /**
2485 * A component that defines the location into which a node should be copied or moved.
2486 *
2487 * @param <Next> The interface that is to be returned when this request is completed
2488 * @author Randall Hauch
2489 */
2490 public interface ImportInto<Next> {
2491 /**
2492 * Specify whether the root element in the XML document should be skipped (that is, not be represented by a node). By
2493 * default, the root element is not skipped.
2494 *
2495 * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
2496 * @return the interface used to specify the location where the content should be placed
2497 */
2498 ImportInto<Next> skippingRootElement( boolean skip );
2499
2500 /**
2501 * Finish the import by specifying the new location into which the node should be copied/moved.
2502 *
2503 * @param to the location of the new parent
2504 * @return the interface for additional requests or actions
2505 * @throws IOException if there is a problem reading the content being imported
2506 * @throws SAXException if there is a problem with the SAX Parser
2507 */
2508 Next into( Location to ) throws IOException, SAXException;
2509
2510 /**
2511 * Finish the import by specifying the new location into which the node should be copied/moved.
2512 *
2513 * @param toPath the path of the new parent
2514 * @return the interface for additional requests or actions
2515 * @throws IOException if there is a problem reading the content being imported
2516 * @throws SAXException if there is a problem with the SAX Parser
2517 */
2518 Next into( String toPath ) throws IOException, SAXException;
2519
2520 /**
2521 * Finish the import by specifying the new location into which the node should be copied/moved.
2522 *
2523 * @param to the path of the new parent
2524 * @return the interface for additional requests or actions
2525 * @throws IOException if there is a problem reading the content being imported
2526 * @throws SAXException if there is a problem with the SAX Parser
2527 */
2528 Next into( Path to ) throws IOException, SAXException;
2529
2530 /**
2531 * Finish the import by specifying the new location into which the node should be copied/moved.
2532 *
2533 * @param to the UUID of the new parent
2534 * @return the interface for additional requests or actions
2535 * @throws IOException if there is a problem reading the content being imported
2536 * @throws SAXException if there is a problem with the SAX Parser
2537 */
2538 Next into( UUID to ) throws IOException, SAXException;
2539
2540 /**
2541 * Finish the import by specifying the new location into which the node should be copied/moved.
2542 *
2543 * @param idProperty the property that uniquely identifies the new parent
2544 * @return the interface for additional requests or actions
2545 * @throws IOException if there is a problem reading the content being imported
2546 * @throws SAXException if there is a problem with the SAX Parser
2547 */
2548 Next into( Property idProperty ) throws IOException, SAXException;
2549
2550 /**
2551 * Finish the import by specifying the new location into which the node should be copied/moved.
2552 *
2553 * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
2554 * new parent
2555 * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
2556 * identifies the new parent
2557 * @return the interface for additional requests or actions
2558 * @throws IOException if there is a problem reading the content being imported
2559 * @throws SAXException if there is a problem with the SAX Parser
2560 */
2561 Next into( Property firstIdProperty,
2562 Property... additionalIdProperties ) throws IOException, SAXException;
2563 }
2564
2565 public interface BatchConjunction extends Conjunction<Batch>, Executable {
2566 }
2567
2568 // ----------------------------------------------------------------------------------------------------------------
2569 // RequestQueue and the different implementations
2570 // ----------------------------------------------------------------------------------------------------------------
2571
2572 /**
2573 * A queue to which each each {@link AbstractAction} can submit its {@link Request} objects, either in single or multiple.
2574 * This interface abstracts away from the {@link AbstractAction} what it is to do with its {@link Request} objects, allowing
2575 * the same <code>AbstractAction</code> classes to be used by the {@link Graph} and {@link Graph.Batch} components.
2576 *
2577 * @author Randall Hauch
2578 */
2579 /*package*/interface RequestQueue extends Executable {
2580 Graph getGraph();
2581
2582 void submit( Request request );
2583
2584 void submit( List<Request> requests );
2585 }
2586
2587 /**
2588 * A RequestQueue that is used by the Graph instance to immediately execute the submitted requests.
2589 *
2590 * @author Randall Hauch
2591 */
2592 @NotThreadSafe
2593 /*package*/class GraphRequestQueue implements RequestQueue {
2594 public Graph getGraph() {
2595 return Graph.this;
2596 }
2597
2598 public void submit( Request request ) {
2599 // Execute the request immediately ...
2600 Graph.this.execute(request);
2601 }
2602
2603 public void submit( List<Request> requests ) {
2604 Request request = CompositeRequest.with(requests);
2605 // Execute the request immediately ...
2606 Graph.this.execute(request);
2607 }
2608
2609 public Results execute() {
2610 throw new UnsupportedOperationException();
2611 }
2612 }
2613
2614 /**
2615 * A RequestQueue that is used by the {@link Graph.Batch} component to enqueue {@link Request}s until they are to be submitted
2616 * to the repository connections.
2617 *
2618 * @author Randall Hauch
2619 */
2620 @NotThreadSafe
2621 /*package*/class CompositingRequestQueue implements RequestQueue {
2622 private final List<Request> requests = new LinkedList<Request>();
2623
2624 public Graph getGraph() {
2625 return Graph.this;
2626 }
2627
2628 public List<Request> getRequests() {
2629 return this.requests;
2630 }
2631
2632 public void submit( Request request ) {
2633 this.requests.add(request);
2634 }
2635
2636 public void submit( List<Request> requests ) {
2637 this.requests.addAll(requests);
2638 }
2639
2640 public Results execute() {
2641 if (!requests.isEmpty()) {
2642 // Execute the requests ...
2643 Request request = CompositeRequest.with(requests);
2644 Graph.this.execute(request);
2645 }
2646 return new BatchResults(requests);
2647 }
2648 }
2649
2650 // ----------------------------------------------------------------------------------------------------------------
2651 // Node Implementation
2652 // ----------------------------------------------------------------------------------------------------------------
2653 @Immutable
2654 protected class GraphNode implements Node {
2655 private final ReadNodeRequest request;
2656
2657 /*package*/GraphNode( ReadNodeRequest request ) {
2658 this.request = request;
2659 }
2660
2661 public Location getLocation() {
2662 return request.getActualLocationOfNode();
2663 }
2664
2665 public Graph getGraph() {
2666 return Graph.this;
2667 }
2668
2669 public Collection<Property> getProperties() {
2670 return request.getProperties();
2671 }
2672
2673 public Property getProperty( Name name ) {
2674 return getPropertiesByName().get(name);
2675 }
2676
2677 public Property getProperty( String nameStr ) {
2678 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
2679 return getPropertiesByName().get(name);
2680 }
2681
2682 public Map<Name, Property> getPropertiesByName() {
2683 return request.getPropertiesByName();
2684 }
2685
2686 public List<Location> getChildren() {
2687 return request.getChildren();
2688 }
2689
2690 public boolean hasChildren() {
2691 return request.getChildren().size() > 0;
2692 }
2693
2694 public List<Segment> getChildrenSegments() {
2695 return getSegments(getChildren());
2696 }
2697
2698 public Iterator<Location> iterator() {
2699 return request.getChildren().iterator();
2700 }
2701
2702 @Override
2703 public int hashCode() {
2704 return getLocation().hashCode();
2705 }
2706
2707 @Override
2708 public boolean equals( Object obj ) {
2709 if (obj instanceof Node) {
2710 Node that = (Node)obj;
2711 return this.getLocation().equals(that.getLocation());
2712 }
2713 return false;
2714 }
2715
2716 @Override
2717 public String toString() {
2718 return "Node " + getLocation().toString();
2719 }
2720 }
2721
2722 // ----------------------------------------------------------------------------------------------------------------
2723 // Results implementation for the batched requests
2724 // ----------------------------------------------------------------------------------------------------------------
2725 @Immutable
2726 class BatchResults implements Results {
2727 private final Map<Path, BatchResultsNode> nodes = new HashMap<Path, BatchResultsNode>();
2728
2729 /*package*/BatchResults( List<Request> requests ) {
2730 for (Request request : requests) {
2731 if (request instanceof ReadAllPropertiesRequest) {
2732 ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
2733 getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
2734 } else if (request instanceof ReadPropertyRequest) {
2735 ReadPropertyRequest read = (ReadPropertyRequest)request;
2736 getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
2737 } else if (request instanceof ReadNodeRequest) {
2738 ReadNodeRequest read = (ReadNodeRequest)request;
2739 BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
2740 node.setProperties(read.getPropertiesByName());
2741 node.setChildren(read.getChildren());
2742 } else if (request instanceof ReadBlockOfChildrenRequest) {
2743 throw new IllegalStateException();
2744 } else if (request instanceof ReadAllChildrenRequest) {
2745 ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
2746 getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
2747 } else if (request instanceof ReadBranchRequest) {
2748 ReadBranchRequest read = (ReadBranchRequest)request;
2749 for (Location location : read) {
2750 BatchResultsNode node = getOrCreateNode(location);
2751 node.setProperties(read.getPropertiesFor(location));
2752 node.setChildren(read.getChildren(location));
2753 }
2754 }
2755 }
2756 for (Map.Entry<Path, BatchResultsNode> entry : nodes.entrySet()) {
2757 entry.getValue().freeze();
2758 }
2759 }
2760
2761 private BatchResultsNode getOrCreateNode( Location location ) {
2762 BatchResultsNode node = nodes.get(location);
2763 if (node == null) {
2764 node = new BatchResultsNode(location);
2765 assert location.getPath() != null;
2766 nodes.put(location.getPath(), node);
2767 }
2768 return node;
2769 }
2770
2771 public Graph getGraph() {
2772 return Graph.this;
2773 }
2774
2775 protected void checkIsAbsolute( Path path ) {
2776 if (!path.isAbsolute()) {
2777 throw new IllegalArgumentException(GraphI18n.pathIsNotAbsolute.text(path));
2778 }
2779 }
2780
2781 public Node getNode( String pathStr ) {
2782 Path path = createPath(pathStr);
2783 checkIsAbsolute(path);
2784 return nodes.get(path);
2785 }
2786
2787 public Node getNode( Path path ) {
2788 CheckArg.isNotNull(path, "path");
2789 checkIsAbsolute(path);
2790 return nodes.get(path);
2791 }
2792
2793 public Node getNode( Location location ) {
2794 CheckArg.isNotNull(location, "location");
2795 CheckArg.isNotNull(location.getPath(), "location.getPath()");
2796 return nodes.get(location.getPath());
2797 }
2798
2799 public boolean includes( String path ) {
2800 return getNode(path) != null;
2801 }
2802
2803 public boolean includes( Path path ) {
2804 return getNode(path) != null;
2805 }
2806
2807 public boolean includes( Location location ) {
2808 return getNode(location) != null;
2809 }
2810
2811 public Iterator<Node> iterator() {
2812 List<Path> paths = new ArrayList<Path>(nodes.keySet());
2813 Collections.sort(paths);
2814 final Iterator<Path> pathIter = paths.iterator();
2815 return new Iterator<Node>() {
2816 public boolean hasNext() {
2817 return pathIter.hasNext();
2818 }
2819
2820 public Node next() {
2821 Path nextPath = pathIter.next();
2822 return getNode(nextPath);
2823 }
2824
2825 public void remove() {
2826 throw new UnsupportedOperationException();
2827 }
2828 };
2829 }
2830 }
2831
2832 @Immutable
2833 class BatchResultsNode implements Node {
2834 private final Location location;
2835 private Map<Name, Property> properties;
2836 private List<Location> children;
2837
2838 BatchResultsNode( Location location ) {
2839 this.location = location;
2840 }
2841
2842 void addProperty( Property property ) {
2843 if (this.properties == null) this.properties = new HashMap<Name, Property>();
2844 this.properties.put(property.getName(), property);
2845 }
2846
2847 void setProperties( Map<Name, Property> properties ) {
2848 this.properties = properties;
2849 }
2850
2851 void setChildren( List<Location> children ) {
2852 this.children = children;
2853 }
2854
2855 void freeze() {
2856 if (properties != null) properties = Collections.unmodifiableMap(properties);
2857 else properties = Collections.emptyMap();
2858 if (children != null) children = Collections.unmodifiableList(children);
2859 else children = Collections.emptyList();
2860 }
2861
2862 public List<Segment> getChildrenSegments() {
2863 return getSegments(getChildren());
2864 }
2865
2866 public Graph getGraph() {
2867 return Graph.this;
2868 }
2869
2870 public Location getLocation() {
2871 return location;
2872 }
2873
2874 public Collection<Property> getProperties() {
2875 return properties.values();
2876 }
2877
2878 public Map<Name, Property> getPropertiesByName() {
2879 return properties;
2880 }
2881
2882 public Property getProperty( Name name ) {
2883 return properties.get(name);
2884 }
2885
2886 public Property getProperty( String nameStr ) {
2887 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
2888 return properties.get(name);
2889 }
2890
2891 public List<Location> getChildren() {
2892 return children;
2893 }
2894
2895 public boolean hasChildren() {
2896 return children.size() != 0;
2897 }
2898
2899 public Iterator<Location> iterator() {
2900 return children.iterator();
2901 }
2902
2903 @Override
2904 public int hashCode() {
2905 return location.hashCode();
2906 }
2907
2908 @Override
2909 public boolean equals( Object obj ) {
2910 if (obj instanceof Node) {
2911 Node that = (Node)obj;
2912 return this.location.equals(that.getLocation());
2913 }
2914 return false;
2915 }
2916
2917 @Override
2918 public String toString() {
2919 return "Node " + getLocation().toString();
2920 }
2921
2922 }
2923
2924 // ----------------------------------------------------------------------------------------------------------------
2925 // Subgraph and SubgraphNode implementations
2926 // ----------------------------------------------------------------------------------------------------------------
2927 @Immutable
2928 class SubgraphResults implements Subgraph {
2929 private final ReadBranchRequest request;
2930
2931 SubgraphResults( ReadBranchRequest request ) {
2932 this.request = request;
2933 }
2934
2935 public Graph getGraph() {
2936 return Graph.this;
2937 }
2938
2939 public Location getLocation() {
2940 return request.getActualLocationOfNode();
2941 }
2942
2943 public Node getRoot() {
2944 return getNode(getLocation());
2945 }
2946
2947 public int getMaximumDepth() {
2948 return request.maximumDepth();
2949 }
2950
2951 public Iterator<Node> iterator() {
2952 final Iterator<Location> iter = request.iterator();
2953 return new Iterator<Node>() {
2954 public boolean hasNext() {
2955 return iter.hasNext();
2956 }
2957
2958 public Node next() {
2959 return getNode(iter.next());
2960 }
2961
2962 public void remove() {
2963 throw new UnsupportedOperationException();
2964 }
2965 };
2966 }
2967
2968 public boolean includes( Path path ) {
2969 CheckArg.isNotNull(path, "path");
2970 path = getAbsolutePath(path);
2971 return request.includes(path);
2972 }
2973
2974 public boolean includes( Location location ) {
2975 CheckArg.isNotNull(location, "location");
2976 return request.includes(location);
2977 }
2978
2979 public boolean includes( String pathStr ) {
2980 Path path = createPath(pathStr);
2981 path = getAbsolutePath(path);
2982 return includes(path);
2983 }
2984
2985 public Node getNode( Location location ) {
2986 if (!location.hasPath()) return null;
2987 Location actualLocation = request.getLocationFor(location.getPath());
2988 if (actualLocation == null) return null;
2989 return new SubgraphNode(actualLocation, request);
2990 }
2991
2992 public Node getNode( Path path ) {
2993 path = getAbsolutePath(path);
2994 if (!includes(path)) return null;
2995 Location location = request.getLocationFor(path);
2996 if (location == null) return null;
2997 return new SubgraphNode(location, request);
2998 }
2999
3000 public Node getNode( String pathStr ) {
3001 CheckArg.isNotEmpty(pathStr, "path");
3002 Path path = createPath(pathStr);
3003 path = getAbsolutePath(path);
3004 return getNode(path);
3005 }
3006
3007 protected Path getAbsolutePath( Path absoluteOrRelative ) {
3008 Path result = absoluteOrRelative;
3009 if (!result.isAbsolute()) {
3010 result = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), result);
3011 result = result.getNormalizedPath();
3012 }
3013 return result;
3014 }
3015
3016 @Override
3017 public int hashCode() {
3018 return getLocation().hashCode();
3019 }
3020
3021 @Override
3022 public String toString() {
3023 return "Subgraph " + getLocation().toString();
3024 }
3025 }
3026
3027 @Immutable
3028 class SubgraphNode implements Node {
3029 private final Location location;
3030 private final ReadBranchRequest request;
3031
3032 SubgraphNode( Location location,
3033 ReadBranchRequest request ) {
3034 this.location = location;
3035 this.request = request;
3036 }
3037
3038 public List<Location> getChildren() {
3039 return request.getChildren(location);
3040 }
3041
3042 public Graph getGraph() {
3043 return Graph.this;
3044 }
3045
3046 public Location getLocation() {
3047 return location;
3048 }
3049
3050 public Collection<Property> getProperties() {
3051 return getPropertiesByName().values();
3052 }
3053
3054 public Map<Name, Property> getPropertiesByName() {
3055 return request.getPropertiesFor(location);
3056 }
3057
3058 public Property getProperty( Name name ) {
3059 return getPropertiesByName().get(name);
3060 }
3061
3062 public Property getProperty( String nameStr ) {
3063 Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
3064 return getPropertiesByName().get(name);
3065 }
3066
3067 public boolean hasChildren() {
3068 return getChildren().size() != 0;
3069 }
3070
3071 public List<Segment> getChildrenSegments() {
3072 return getSegments(getChildren());
3073 }
3074
3075 public Iterator<Location> iterator() {
3076 return getChildren().iterator();
3077 }
3078
3079 @Override
3080 public int hashCode() {
3081 return location.hashCode();
3082 }
3083
3084 @Override
3085 public boolean equals( Object obj ) {
3086 if (obj instanceof Node) {
3087 Node that = (Node)obj;
3088 return this.location.equals(that.getLocation());
3089 }
3090 return false;
3091 }
3092
3093 @Override
3094 public String toString() {
3095 return "Node " + getLocation().toString();
3096 }
3097 }
3098
3099 // ----------------------------------------------------------------------------------------------------------------
3100 // Action Implementations
3101 // ----------------------------------------------------------------------------------------------------------------
3102 @Immutable
3103 static abstract class AbstractAction<T> implements Conjunction<T>, Executable {
3104 private final RequestQueue queue;
3105 private final T afterConjunction;
3106
3107 /*package*/AbstractAction( T afterConjunction,
3108 RequestQueue queue ) {
3109 this.queue = queue;
3110 this.afterConjunction = afterConjunction;
3111 }
3112
3113 /*package*/RequestQueue queue() {
3114 return this.queue;
3115 }
3116
3117 public T and() {
3118 return this.afterConjunction;
3119 }
3120
3121 /*package*/Path createPath( String path ) {
3122 return queue.getGraph().getContext().getValueFactories().getPathFactory().create(path);
3123 }
3124
3125 public Results execute() {
3126 return queue.execute();
3127 }
3128 }
3129
3130 @NotThreadSafe
3131 static class MoveAction<T> extends AbstractAction<T> implements Move<T> {
3132 private final Locations from;
3133
3134 /*package*/MoveAction( T afterConjunction,
3135 RequestQueue queue,
3136 Location from ) {
3137 super(afterConjunction, queue);
3138 this.from = new Locations(from);
3139 }
3140
3141 public Move<T> and( Location from ) {
3142 this.from.add(from);
3143 return this;
3144 }
3145
3146 public Move<T> and( String from ) {
3147 this.from.add(new Location(createPath(from)));
3148 return this;
3149 }
3150
3151 public Move<T> and( Path from ) {
3152 this.from.add(new Location(from));
3153 return this;
3154 }
3155
3156 public Move<T> and( Property firstFrom,
3157 Property... additionalFroms ) {
3158 this.from.add(new Location(firstFrom, additionalFroms));
3159 return this;
3160 }
3161
3162 public Move<T> and( Property from ) {
3163 this.from.add(new Location(from));
3164 return this;
3165 }
3166
3167 public Move<T> and( UUID from ) {
3168 this.from.add(new Location(from));
3169 return this;
3170 }
3171
3172 /**
3173 * Submit any requests to move the targets into the supplied parent location
3174 *
3175 * @param into the parent location
3176 * @return this object, for method chaining
3177 */
3178 private T submit( Location into ) {
3179 if (this.from.hasNext()) {
3180 List<Request> requests = new LinkedList<Request>();
3181 Locations locations = this.from;
3182 while (locations.hasNext()) {
3183 Location location = locations.getLocation();
3184 requests.add(new MoveBranchRequest(location, into));
3185 locations = locations.next();
3186 }
3187 queue().submit(requests);
3188 } else {
3189 queue().submit(new MoveBranchRequest(this.from.getLocation(), into));
3190 }
3191 return and();
3192 }
3193
3194 public T into( Location into ) {
3195 return submit(into);
3196 }
3197
3198 public T into( Path into ) {
3199 return submit(new Location(into));
3200 }
3201
3202 public T into( UUID into ) {
3203 return submit(new Location(into));
3204 }
3205
3206 public T into( Property firstIdProperty,
3207 Property... additionalIdProperties ) {
3208 return submit(new Location(firstIdProperty, additionalIdProperties));
3209 }
3210
3211 public T into( Property into ) {
3212 return submit(new Location(into));
3213 }
3214
3215 public T into( String into ) {
3216 return submit(new Location(createPath(into)));
3217 }
3218
3219 @Override
3220 public Results execute() {
3221 return queue().execute();
3222 }
3223 }
3224
3225 @NotThreadSafe
3226 static class CopyAction<T> extends AbstractAction<T> implements Copy<T> {
3227 private final Locations from;
3228
3229 /*package*/CopyAction( T afterConjunction,
3230 RequestQueue queue,
3231 Location from ) {
3232 super(afterConjunction, queue);
3233 this.from = new Locations(from);
3234 }
3235
3236 public Copy<T> and( Location from ) {
3237 this.from.add(from);
3238 return this;
3239 }
3240
3241 public Copy<T> and( String from ) {
3242 this.from.add(new Location(createPath(from)));
3243 return this;
3244 }
3245
3246 public Copy<T> and( Path from ) {
3247 this.from.add(new Location(from));
3248 return this;
3249 }
3250
3251 public Copy<T> and( Property firstFrom,
3252 Property... additionalFroms ) {
3253 this.from.add(new Location(firstFrom, additionalFroms));
3254 return this;
3255 }
3256
3257 public Copy<T> and( Property from ) {
3258 this.from.add(new Location(from));
3259 return this;
3260 }
3261
3262 public Copy<T> and( UUID from ) {
3263 this.from.add(new Location(from));
3264 return this;
3265 }
3266
3267 /**
3268 * Submit any requests to move the targets into the supplied parent location
3269 *
3270 * @param into the parent location
3271 * @return this object, for method chaining
3272 */
3273 private T submit( Location into ) {
3274 if (this.from.hasNext()) {
3275 List<Request> requests = new LinkedList<Request>();
3276 Locations locations = this.from;
3277 while (locations.hasNext()) {
3278 Location location = locations.getLocation();
3279 requests.add(new CopyBranchRequest(location, into));
3280 locations = locations.next();
3281 }
3282 queue().submit(requests);
3283 } else {
3284 queue().submit(new CopyBranchRequest(this.from.getLocation(), into));
3285 }
3286 return and();
3287 }
3288
3289 public T into( Location into ) {
3290 return submit(into);
3291 }
3292
3293 public T into( Path into ) {
3294 return submit(new Location(into));
3295 }
3296
3297 public T into( UUID into ) {
3298 return submit(new Location(into));
3299 }
3300
3301 public T into( Property firstIdProperty,
3302 Property... additionalIdProperties ) {
3303 return submit(new Location(firstIdProperty, additionalIdProperties));
3304 }
3305
3306 public T into( Property into ) {
3307 return submit(new Location(into));
3308 }
3309
3310 public T into( String into ) {
3311 return submit(new Location(createPath(into)));
3312 }
3313
3314 @Override
3315 public Results execute() {
3316 return queue().execute();
3317 }
3318 }
3319
3320 @NotThreadSafe
3321 static class CreateAction<T> extends AbstractAction<T> implements Create<T> {
3322 private final Location at;
3323 private final List<Property> properties = new LinkedList<Property>();
3324
3325 /*package*/CreateAction( T afterConjunction,
3326 RequestQueue queue,
3327 Location at ) {
3328 super(afterConjunction, queue);
3329 this.at = at;
3330 }
3331
3332 public Create<T> and( UUID uuid ) {
3333 PropertyFactory factory = queue().getGraph().getContext().getPropertyFactory();
3334 properties.add(factory.create(DnaLexicon.UUID, uuid));
3335 return this;
3336 }
3337
3338 public Create<T> and( Property property ) {
3339 properties.add(property);
3340 return this;
3341 }
3342
3343 public Create<T> and( String name,
3344 Object... values ) {
3345 ExecutionContext context = queue().getGraph().getContext();
3346 PropertyFactory factory = context.getPropertyFactory();
3347 NameFactory nameFactory = context.getValueFactories().getNameFactory();
3348 properties.add(factory.create(nameFactory.create(name), values));
3349 return this;
3350 }
3351
3352 public Create<T> and( Name name,
3353 Object... values ) {
3354 ExecutionContext context = queue().getGraph().getContext();
3355 PropertyFactory factory = context.getPropertyFactory();
3356 properties.add(factory.create(name, values));
3357 return this;
3358 }
3359
3360 public Create<T> and( Property property,
3361 Property... additionalProperties ) {
3362 properties.add(property);
3363 for (Property additionalProperty : additionalProperties) {
3364 properties.add(additionalProperty);
3365 }
3366 return this;
3367 }
3368
3369 public Create<T> with( UUID uuid ) {
3370 return and(uuid);
3371 }
3372
3373 public Create<T> with( Property property ) {
3374 return and(property);
3375 }
3376
3377 public Create<T> with( Property property,
3378 Property... additionalProperties ) {
3379 return and(property, additionalProperties);
3380 }
3381
3382 public Create<T> with( String name,
3383 Object... values ) {
3384 return and(name, values);
3385 }
3386
3387 public Create<T> with( Name name,
3388 Object... values ) {
3389 return and(name, values);
3390 }
3391
3392 @Override
3393 public T and() {
3394 this.queue().submit(new CreateNodeRequest(this.at, this.properties));
3395 return super.and();
3396 }
3397
3398 @Override
3399 public Results execute() {
3400 return queue().execute();
3401 }
3402 }
3403
3404 }