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 * Unless otherwise indicated, all code in JBoss DNA is licensed 010 * 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.request; 025 026 import java.util.HashMap; 027 import java.util.Iterator; 028 import java.util.LinkedList; 029 import java.util.Map; 030 import org.jboss.dna.graph.Location; 031 import org.jboss.dna.graph.NodeConflictBehavior; 032 import org.jboss.dna.graph.property.Name; 033 import org.jboss.dna.graph.property.Path; 034 import org.jboss.dna.graph.property.Property; 035 import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior; 036 import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior; 037 038 /** 039 * A component that can be used to build up a list of requests. This implementation does perform some simple optimizations, such 040 * as combining adjacent compatible requests. 041 * <p> 042 * This builder can be used to add multiple requests. When the enqueued requests are to be processed, calling {@link #pop()} will 043 * remove and return the enqueued requests (as a {@link CompositeRequest} if there is more than one enqueued request). 044 * </p> 045 */ 046 public class BatchRequestBuilder { 047 048 private LinkedList<Request> requests; 049 private NodeChange pendingRequest; 050 051 public BatchRequestBuilder() { 052 this.requests = new LinkedList<Request>(); 053 } 054 055 public BatchRequestBuilder( LinkedList<Request> requests ) { 056 this.requests = requests != null ? requests : new LinkedList<Request>(); 057 } 058 059 /** 060 * Determine whether this builder has built any requests. 061 * 062 * @return true if there are requests (i.e., {@link #pop()} will return a non-null request), or false if there are no requests 063 */ 064 public boolean hasRequests() { 065 return pendingRequest != null || !requests.isEmpty(); 066 } 067 068 /** 069 * Finish any pending request 070 */ 071 public void finishPendingRequest() { 072 if (pendingRequest != null) { 073 // There's a pending request, we need to build it ... 074 add(pendingRequest.toRequest()); 075 pendingRequest = null; 076 } 077 } 078 079 /** 080 * Remove and return any requests that have been built by this builder since the last call to this method. This method will 081 * return null if no requests have been built. If only one request was built, then it will be returned. If multiple requests 082 * have been built, then this method will return a {@link CompositeRequest} containing them. 083 * 084 * @return the request (or {@link CompositeRequest}) representing those requests that this builder has created since the last 085 * call to this method, or null if there are no requests to return 086 */ 087 public Request pop() { 088 int number = requests.size(); 089 if (pendingRequest != null) { 090 // There's a pending request, we need to build it ... 091 Request newRequest = pendingRequest.toRequest(); 092 if (number == 0) { 093 // There's no other request ... 094 return newRequest; 095 } 096 // We have at least one other request, so add the pending request ... 097 addPending(); 098 ++number; 099 } else { 100 // There is no pending request ... 101 if (number == 0) { 102 // And no enqueued request ... 103 return null; 104 } 105 if (number == 1) { 106 // There's only one request, so return just the one ... 107 Request result = requests.getFirst(); 108 requests.clear(); 109 return result; 110 } 111 } 112 assert number >= 2; 113 // Build a composite request (reusing the existing list), and then replace the list 114 Request result = CompositeRequest.with(requests); 115 requests = new LinkedList<Request>(); 116 return result; 117 } 118 119 protected final BatchRequestBuilder add( Request request ) { 120 addPending(); 121 requests.add(request); 122 return this; 123 } 124 125 protected final BatchRequestBuilder addPending() { 126 if (pendingRequest != null) { 127 requests.add(pendingRequest.toRequest()); 128 pendingRequest = null; 129 } 130 return this; 131 } 132 133 /** 134 * Add a request to obtain the information about the available workspaces. 135 * 136 * @return this builder for method chaining; never null 137 */ 138 public BatchRequestBuilder getWorkspaces() { 139 return add(new GetWorkspacesRequest()); 140 } 141 142 /** 143 * Add a request to verify the existance of the named workspace. 144 * 145 * @param workspaceName the desired name of the workspace, or null if the source's default workspace should be used 146 * @return this builder for method chaining; never null 147 */ 148 public BatchRequestBuilder verifyWorkspace( String workspaceName ) { 149 return add(new VerifyWorkspaceRequest(workspaceName)); 150 } 151 152 /** 153 * Add a request to create a new workspace, and specify the behavior should a workspace already exists with a name that 154 * matches the desired name for the new workspace. 155 * 156 * @param desiredNameOfNewWorkspace the desired name of the new workspace 157 * @param createConflictBehavior the behavior if a workspace already exists with the same name, or null if the default 158 * behavior should be used 159 * @return this builder for method chaining; never null 160 */ 161 public BatchRequestBuilder createWorkspace( String desiredNameOfNewWorkspace, 162 CreateConflictBehavior createConflictBehavior ) { 163 return add(new CreateWorkspaceRequest(desiredNameOfNewWorkspace, createConflictBehavior)); 164 } 165 166 /** 167 * Add a request to clone an existing workspace to create a new workspace, and specify the behavior should a workspace already 168 * exists with a name that matches the desired name for the new workspace. 169 * 170 * @param nameOfWorkspaceToBeCloned the name of the existing workspace that is to be cloned 171 * @param desiredNameOfTargetWorkspace the desired name of the target workspace 172 * @param createConflictBehavior the behavior if a workspace already exists with the same name 173 * @param cloneConflictBehavior the behavior if the workspace to be cloned does not exist 174 * @return this builder for method chaining; never null 175 * @throws IllegalArgumentException if the either workspace name is null 176 */ 177 public BatchRequestBuilder cloneWorkspace( String nameOfWorkspaceToBeCloned, 178 String desiredNameOfTargetWorkspace, 179 CreateConflictBehavior createConflictBehavior, 180 CloneConflictBehavior cloneConflictBehavior ) { 181 return add(new CloneWorkspaceRequest(nameOfWorkspaceToBeCloned, desiredNameOfTargetWorkspace, createConflictBehavior, 182 cloneConflictBehavior)); 183 } 184 185 /** 186 * Add a request to destroy an existing workspace. 187 * 188 * @param workspaceName the name of the workspace that is to be destroyed 189 * @return this builder for method chaining; never null 190 * @throws IllegalArgumentException if the workspace name is null 191 */ 192 public BatchRequestBuilder destroyWorkspace( String workspaceName ) { 193 return add(new DestroyWorkspaceRequest(workspaceName)); 194 } 195 196 /** 197 * Add a request to verify the existance and location of a node at the supplied location. 198 * 199 * @param at the location of the node to be verified 200 * @param workspaceName the name of the workspace containing the node 201 * @return this builder for method chaining; never null 202 * @throws IllegalArgumentException if the location or workspace name is null 203 */ 204 public BatchRequestBuilder verifyNodeExists( Location at, 205 String workspaceName ) { 206 return add(new VerifyNodeExistsRequest(at, workspaceName)); 207 } 208 209 /** 210 * Add a request to read the properties and number of children of a node at the supplied location. 211 * 212 * @param at the location of the node to be read 213 * @param workspaceName the name of the workspace containing the node 214 * @return this builder for method chaining; never null 215 * @throws IllegalArgumentException if the location or workspace name is null 216 */ 217 public BatchRequestBuilder readNode( Location at, 218 String workspaceName ) { 219 return add(new ReadNodeRequest(at, workspaceName)); 220 } 221 222 /** 223 * Add a request to read the children of a node at the supplied location in the designated workspace. 224 * 225 * @param of the location of the node whose children are to be read 226 * @param workspaceName the name of the workspace 227 * @return this builder for method chaining; never null 228 * @throws IllegalArgumentException if the location or workspace name is null 229 */ 230 public BatchRequestBuilder readAllChildren( Location of, 231 String workspaceName ) { 232 return add(new ReadAllChildrenRequest(of, workspaceName)); 233 } 234 235 /** 236 * Add a request to read the properties and number of children of a node at the supplied location. 237 * 238 * @param of the location of the node whose children are to be read 239 * @param workspaceName the name of the workspace 240 * @return this builder for method chaining; never null 241 * @throws IllegalArgumentException if the location or workspace name is null 242 */ 243 public BatchRequestBuilder readAllProperties( Location of, 244 String workspaceName ) { 245 return add(new ReadAllPropertiesRequest(of, workspaceName)); 246 } 247 248 /** 249 * Add a request to read the properties and number of children of a node at the supplied location. 250 * 251 * @param of the location of the node whose children are to be read 252 * @param workspaceName the name of the workspace 253 * @param propertyName the name of the property to read 254 * @return this builder for method chaining; never null 255 * @throws IllegalArgumentException if the location or workspace name is null 256 */ 257 public BatchRequestBuilder readProperty( Location of, 258 String workspaceName, 259 Name propertyName ) { 260 return add(new ReadPropertyRequest(of, workspaceName, propertyName)); 261 } 262 263 /** 264 * Add a request to read the branch at the supplied location, to a maximum depth of 2. 265 * 266 * @param at the location of the branch 267 * @param workspaceName the name of the workspace containing the branch 268 * @return this builder for method chaining; never null 269 * @throws IllegalArgumentException if the location or workspace name is null or if the maximum depth is not positive 270 */ 271 public BatchRequestBuilder readBranch( Location at, 272 String workspaceName ) { 273 return add(new ReadBranchRequest(at, workspaceName)); 274 } 275 276 /** 277 * Add a request to read the branch (of given depth) at the supplied location. 278 * 279 * @param at the location of the branch 280 * @param workspaceName the name of the workspace containing the branch 281 * @param maxDepth the maximum depth to read 282 * @return this builder for method chaining; never null 283 * @throws IllegalArgumentException if the location or workspace name is null or if the maximum depth is not positive 284 */ 285 public BatchRequestBuilder readBranch( Location at, 286 String workspaceName, 287 int maxDepth ) { 288 return add(new ReadBranchRequest(at, workspaceName, maxDepth)); 289 } 290 291 /** 292 * Add a request to read a block of the children of a node at the supplied location. The block is defined by the starting 293 * index of the first child and the number of children to include. Note that this index is <i>not</i> the 294 * {@link Path.Segment#getIndex() same-name-sibiling index}, but rather is the index of the child as if the children were in 295 * an array. 296 * 297 * @param of the location of the node whose children are to be read 298 * @param workspaceName the name of the workspace containing the parent 299 * @param startingIndex the zero-based index of the first child to be included in the block 300 * @param count the maximum number of children that should be included in the block 301 * @return this builder for method chaining; never null 302 * @throws IllegalArgumentException if the location or workspace name is null, if <code>startingIndex</code> is negative, or 303 * if <code>count</count> is less than 1. 304 */ 305 public BatchRequestBuilder readBlockOfChildren( Location of, 306 String workspaceName, 307 int startingIndex, 308 int count ) { 309 return add(new ReadBlockOfChildrenRequest(of, workspaceName, startingIndex, count)); 310 } 311 312 /** 313 * Add a request to read those children of a node that are immediately after a supplied sibling node. 314 * 315 * @param startingAfter the location of the previous sibling that was the last child of the previous block of children read 316 * @param workspaceName the name of the workspace containing the node 317 * @param count the maximum number of children that should be included in the block 318 * @return this builder for method chaining; never null 319 * @throws IllegalArgumentException if the workspace name or <code>startingAfter</code> location is null, or if 320 * <code>count</count> is less than 1. 321 */ 322 public BatchRequestBuilder readNextBlockOfChildren( Location startingAfter, 323 String workspaceName, 324 int count ) { 325 return add(new ReadNextBlockOfChildrenRequest(startingAfter, workspaceName, count)); 326 } 327 328 /** 329 * Add a request to create a node with the given properties under the supplied location. 330 * 331 * @param parentLocation the location of the existing parent node, under which the new child should be created 332 * @param workspaceName the name of the workspace containing the parent 333 * @param childName the name of the new child to create under the existing parent 334 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 335 * properties} for the new node 336 * @return this builder for method chaining; never null 337 * @throws IllegalArgumentException if the location, workspace name, or child name is null 338 */ 339 public BatchRequestBuilder createNode( Location parentLocation, 340 String workspaceName, 341 Name childName, 342 Iterator<Property> properties ) { 343 return add(new CreateNodeRequest(parentLocation, workspaceName, childName, CreateNodeRequest.DEFAULT_CONFLICT_BEHAVIOR, 344 properties)); 345 } 346 347 /** 348 * Add a request to create a node with the given properties under the supplied location. 349 * 350 * @param parentLocation the location of the existing parent node, under which the new child should be created 351 * @param workspaceName the name of the workspace containing the parent 352 * @param childName the name of the new child to create under the existing parent 353 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 354 * properties} for the new node 355 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code> 356 * location 357 * @return this builder for method chaining; never null 358 * @throws IllegalArgumentException if the location, workspace name, or child name is null 359 */ 360 public BatchRequestBuilder createNode( Location parentLocation, 361 String workspaceName, 362 Name childName, 363 Iterator<Property> properties, 364 NodeConflictBehavior conflictBehavior ) { 365 if (conflictBehavior == null) conflictBehavior = CreateNodeRequest.DEFAULT_CONFLICT_BEHAVIOR; 366 return add(new CreateNodeRequest(parentLocation, workspaceName, childName, conflictBehavior, properties)); 367 } 368 369 /** 370 * Add a request to create a node with the given properties under the supplied location. 371 * 372 * @param parentLocation the location of the existing parent node, under which the new child should be created 373 * @param workspaceName the name of the workspace containing the parent 374 * @param childName the name of the new child to create under the existing parent 375 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 376 * properties} for the new node 377 * @return this builder for method chaining; never null 378 * @throws IllegalArgumentException if the location, workspace name, or child name is null 379 */ 380 public BatchRequestBuilder createNode( Location parentLocation, 381 String workspaceName, 382 Name childName, 383 Property[] properties ) { 384 return add(new CreateNodeRequest(parentLocation, workspaceName, childName, CreateNodeRequest.DEFAULT_CONFLICT_BEHAVIOR, 385 properties)); 386 } 387 388 /** 389 * Add a request to create a node with the given properties under the supplied location. 390 * 391 * @param parentLocation the location of the existing parent node, under which the new child should be created 392 * @param workspaceName the name of the workspace containing the parent 393 * @param childName the name of the new child to create under the existing parent 394 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 395 * properties} for the new node 396 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code> 397 * location 398 * @return this builder for method chaining; never null 399 * @throws IllegalArgumentException if the location, workspace name, or child name is null 400 */ 401 public BatchRequestBuilder createNode( Location parentLocation, 402 String workspaceName, 403 Name childName, 404 Property[] properties, 405 NodeConflictBehavior conflictBehavior ) { 406 if (conflictBehavior == null) conflictBehavior = CreateNodeRequest.DEFAULT_CONFLICT_BEHAVIOR; 407 return add(new CreateNodeRequest(parentLocation, workspaceName, childName, conflictBehavior, properties)); 408 } 409 410 /** 411 * Add a request to update the property on the node at the supplied location. This request will create the property if it does 412 * not yet exist. 413 * 414 * @param on the location of the node to be read 415 * @param workspaceName the name of the workspace containing the node 416 * @param property the new property on the node 417 * @return this builder for method chaining; never null 418 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to update 419 */ 420 public BatchRequestBuilder setProperty( Location on, 421 String workspaceName, 422 Property property ) { 423 // If there's a pending request ... 424 if (pendingRequest != null) { 425 // Compare the supplied location with that of the pending request 426 if (pendingRequest.location.equals(on)) { 427 // They are the same location, so we can add the properties to the pending request ... 428 pendingRequest.pendingProperties.put(property.getName(), property); 429 return this; 430 } 431 // Not the exact same location, so push the existing pending request ... 432 addPending(); 433 } 434 435 // Record this operation as a pending change ... 436 pendingRequest = new NodeChange(on, workspaceName); 437 pendingRequest.pendingProperties.put(property.getName(), property); 438 return this; 439 } 440 441 /** 442 * Add a request to update the properties on the node at the supplied location. 443 * 444 * @param on the location of the node to be read 445 * @param workspaceName the name of the workspace containing the node 446 * @param properties the new properties on the node 447 * @return this builder for method chaining; never null 448 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to update 449 */ 450 public BatchRequestBuilder setProperties( Location on, 451 String workspaceName, 452 Property... properties ) { 453 // If there's a pending request ... 454 if (pendingRequest != null) { 455 // Compare the supplied location with that of the pending request 456 if (pendingRequest.location.equals(on)) { 457 // They are the same location, so we can add the properties to the pending request ... 458 for (Property property : properties) { 459 pendingRequest.pendingProperties.put(property.getName(), property); 460 } 461 return this; 462 } 463 // Not the exact same location, so push the existing pending request ... 464 addPending(); 465 } 466 467 // Record this operation as a pending change ... 468 pendingRequest = new NodeChange(on, workspaceName); 469 for (Property property : properties) { 470 pendingRequest.pendingProperties.put(property.getName(), property); 471 } 472 return this; 473 } 474 475 /** 476 * Add a request to remove the property with the supplied name from the given node. Supplying a name for a property that does 477 * not exist will not cause an error. 478 * 479 * @param on the location of the node to be read 480 * @param workspaceName the name of the workspace containing the node 481 * @param propertyName the name of the property that is to be removed 482 * @return this builder for method chaining; never null 483 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to remove 484 */ 485 public BatchRequestBuilder removeProperty( Location on, 486 String workspaceName, 487 Name propertyName ) { 488 // If there's a pending request ... 489 if (pendingRequest != null) { 490 // Compare the supplied location with that of the pending request 491 if (pendingRequest.location.equals(on)) { 492 // They are the same location, so we can add the properties to the pending request ... 493 pendingRequest.pendingProperties.put(propertyName, null); 494 return this; 495 } 496 // Not the exact same location, so push the existing pending request ... 497 addPending(); 498 } 499 500 // Record this operation as a pending change ... 501 pendingRequest = new NodeChange(on, workspaceName); 502 pendingRequest.pendingProperties.put(propertyName, null); 503 return this; 504 } 505 506 /** 507 * Add a request to remove from the node the properties with the supplied names. Supplying a name for a property that does not 508 * exist will not cause an error. 509 * 510 * @param on the location of the node to be read 511 * @param workspaceName the name of the workspace containing the node 512 * @param propertyNames the names of the properties that are to be removed 513 * @return this builder for method chaining; never null 514 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to remove 515 */ 516 public BatchRequestBuilder removeProperties( Location on, 517 String workspaceName, 518 Name... propertyNames ) { 519 // If there's a pending request ... 520 if (pendingRequest != null) { 521 // Compare the supplied location with that of the pending request 522 if (pendingRequest.location.equals(on)) { 523 // They are the same location, so we can add the properties to the pending request ... 524 for (Name propertyName : propertyNames) { 525 pendingRequest.pendingProperties.put(propertyName, null); 526 } 527 return this; 528 } 529 // Not the exact same location, so push the existing pending request ... 530 addPending(); 531 } 532 533 // Record this operation as a pending change ... 534 pendingRequest = new NodeChange(on, workspaceName); 535 for (Name propertyName : propertyNames) { 536 pendingRequest.pendingProperties.put(propertyName, null); 537 } 538 return this; 539 } 540 541 /** 542 * Add a request to rename the node at the supplied location. 543 * 544 * @param at the location of the node to be read 545 * @param workspaceName the name of the workspace containing the node 546 * @param newName the new name for the node 547 * @return this builder for method chaining; never null 548 * @throws IllegalArgumentException if the location or workspace name is null 549 */ 550 public BatchRequestBuilder renameNode( Location at, 551 String workspaceName, 552 Name newName ) { 553 return add(new RenameNodeRequest(at, workspaceName, newName)); 554 } 555 556 /** 557 * Add a request to copy a branch to another. 558 * 559 * @param from the location of the top node in the existing branch that is to be copied 560 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists 561 * @param into the location of the existing node into which the copy should be placed 562 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied 563 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be 564 * used 565 * @return this builder for method chaining; never null 566 * @throws IllegalArgumentException if either of the locations or workspace names are null 567 */ 568 public BatchRequestBuilder copyBranch( Location from, 569 String fromWorkspace, 570 Location into, 571 String intoWorkspace, 572 Name nameForCopy ) { 573 return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, 574 CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 575 } 576 577 /** 578 * Add a request to copy a branch to another. 579 * 580 * @param from the location of the top node in the existing branch that is to be copied 581 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists 582 * @param into the location of the existing node into which the copy should be placed 583 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied 584 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be 585 * used 586 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code> 587 * location, or null if the default conflict behavior should be used 588 * @return this builder for method chaining; never null 589 * @throws IllegalArgumentException if either of the locations or workspace names are null 590 */ 591 public BatchRequestBuilder copyBranch( Location from, 592 String fromWorkspace, 593 Location into, 594 String intoWorkspace, 595 Name nameForCopy, 596 NodeConflictBehavior conflictBehavior ) { 597 if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR; 598 return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior)); 599 } 600 601 /** 602 * Create a request to move a branch from one location into another. 603 * 604 * @param from the location of the top node in the existing branch that is to be moved 605 * @param into the location of the existing node into which the branch should be moved 606 * @param workspaceName the name of the workspace 607 * @return this builder for method chaining; never null 608 * @throws IllegalArgumentException if any of the parameters are null 609 */ 610 public BatchRequestBuilder moveBranch( Location from, 611 Location into, 612 String workspaceName ) { 613 return add(new MoveBranchRequest(from, into, workspaceName, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 614 } 615 616 /** 617 * Create a request to move a branch from one location into another. 618 * 619 * @param from the location of the top node in the existing branch that is to be moved 620 * @param into the location of the existing node into which the branch should be moved 621 * @param workspaceName the name of the workspace 622 * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used 623 * @return this builder for method chaining; never null 624 * @throws IllegalArgumentException if any of the parameters are null 625 */ 626 public BatchRequestBuilder moveBranch( Location from, 627 Location into, 628 String workspaceName, 629 Name newNameForNode ) { 630 return add(new MoveBranchRequest(from, into, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 631 } 632 633 /** 634 * Create a request to move a branch from one location into another. 635 * 636 * @param from the location of the top node in the existing branch that is to be moved 637 * @param into the location of the existing node into which the branch should be moved 638 * @param workspaceName the name of the workspace 639 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code> 640 * location 641 * @return this builder for method chaining; never null 642 * @throws IllegalArgumentException if any of the parameters are null 643 */ 644 public BatchRequestBuilder moveBranch( Location from, 645 Location into, 646 String workspaceName, 647 NodeConflictBehavior conflictBehavior ) { 648 if (conflictBehavior == null) conflictBehavior = MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR; 649 return add(new MoveBranchRequest(from, into, workspaceName, conflictBehavior)); 650 } 651 652 /** 653 * Add a request to delete a branch. 654 * 655 * @param at the location of the top node in the existing branch that is to be deleted 656 * @param workspaceName the name of the workspace containing the parent 657 * @return this builder for method chaining; never null 658 * @throws IllegalArgumentException if the location or workspace name is null 659 */ 660 public BatchRequestBuilder deleteBranch( Location at, 661 String workspaceName ) { 662 return add(new DeleteBranchRequest(at, workspaceName)); 663 } 664 665 protected class NodeChange { 666 protected final Location location; 667 protected final String workspaceName; 668 protected final Map<Name, Property> pendingProperties = new HashMap<Name, Property>(); 669 670 protected NodeChange( Location location, 671 String workspaceName ) { 672 this.location = location; 673 this.workspaceName = workspaceName; 674 } 675 676 protected Request toRequest() { 677 if (pendingProperties.size() == 1) { 678 Map.Entry<Name, Property> entry = pendingProperties.entrySet().iterator().next(); 679 Property property = entry.getValue(); 680 if (property == null) { 681 return new RemovePropertyRequest(location, workspaceName, entry.getKey()); 682 } 683 return new SetPropertyRequest(location, workspaceName, property); 684 } 685 return new UpdatePropertiesRequest(location, workspaceName, pendingProperties); 686 } 687 } 688 689 }