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