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 }