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 if (property == null) continue; 471 pendingRequest.pendingProperties.put(property.getName(), property); 472 } 473 return this; 474 } 475 476 /** 477 * Add a request to remove the property with the supplied name from the given node. Supplying a name for a property that does 478 * not exist will not cause an error. 479 * 480 * @param on the location of the node to be read 481 * @param workspaceName the name of the workspace containing the node 482 * @param propertyName the name of the property that is to be removed 483 * @return this builder for method chaining; never null 484 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to remove 485 */ 486 public BatchRequestBuilder removeProperty( Location on, 487 String workspaceName, 488 Name propertyName ) { 489 // If there's a pending request ... 490 if (pendingRequest != null) { 491 // Compare the supplied location with that of the pending request 492 if (pendingRequest.location.equals(on)) { 493 // They are the same location, so we can add the properties to the pending request ... 494 pendingRequest.pendingProperties.put(propertyName, null); 495 return this; 496 } 497 // Not the exact same location, so push the existing pending request ... 498 addPending(); 499 } 500 501 // Record this operation as a pending change ... 502 pendingRequest = new NodeChange(on, workspaceName); 503 pendingRequest.pendingProperties.put(propertyName, null); 504 return this; 505 } 506 507 /** 508 * Add a request to remove from the node the properties with the supplied names. Supplying a name for a property that does not 509 * exist will not cause an error. 510 * 511 * @param on the location of the node to be read 512 * @param workspaceName the name of the workspace containing the node 513 * @param propertyNames the names of the properties that are to be removed 514 * @return this builder for method chaining; never null 515 * @throws IllegalArgumentException if the location or workspace name is null or if there are no properties to remove 516 */ 517 public BatchRequestBuilder removeProperties( Location on, 518 String workspaceName, 519 Name... propertyNames ) { 520 // If there's a pending request ... 521 if (pendingRequest != null) { 522 // Compare the supplied location with that of the pending request 523 if (pendingRequest.location.equals(on)) { 524 // They are the same location, so we can add the properties to the pending request ... 525 for (Name propertyName : propertyNames) { 526 pendingRequest.pendingProperties.put(propertyName, null); 527 } 528 return this; 529 } 530 // Not the exact same location, so push the existing pending request ... 531 addPending(); 532 } 533 534 // Record this operation as a pending change ... 535 pendingRequest = new NodeChange(on, workspaceName); 536 for (Name propertyName : propertyNames) { 537 pendingRequest.pendingProperties.put(propertyName, null); 538 } 539 return this; 540 } 541 542 /** 543 * Add a request to rename the node at the supplied location. 544 * 545 * @param at the location of the node to be read 546 * @param workspaceName the name of the workspace containing the node 547 * @param newName the new name for the node 548 * @return this builder for method chaining; never null 549 * @throws IllegalArgumentException if the location or workspace name is null 550 */ 551 public BatchRequestBuilder renameNode( Location at, 552 String workspaceName, 553 Name newName ) { 554 return add(new RenameNodeRequest(at, workspaceName, newName)); 555 } 556 557 /** 558 * Add a request to copy a branch to another. 559 * 560 * @param from the location of the top node in the existing branch that is to be copied 561 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists 562 * @param into the location of the existing node into which the copy should be placed 563 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied 564 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be 565 * used 566 * @return this builder for method chaining; never null 567 * @throws IllegalArgumentException if either of the locations or workspace names are null 568 */ 569 public BatchRequestBuilder copyBranch( Location from, 570 String fromWorkspace, 571 Location into, 572 String intoWorkspace, 573 Name nameForCopy ) { 574 return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, 575 CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 576 } 577 578 /** 579 * Add a request to copy a branch to another. 580 * 581 * @param from the location of the top node in the existing branch that is to be copied 582 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists 583 * @param into the location of the existing node into which the copy should be placed 584 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied 585 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be 586 * used 587 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code> 588 * location, or null if the default conflict behavior should be used 589 * @return this builder for method chaining; never null 590 * @throws IllegalArgumentException if either of the locations or workspace names are null 591 */ 592 public BatchRequestBuilder copyBranch( Location from, 593 String fromWorkspace, 594 Location into, 595 String intoWorkspace, 596 Name nameForCopy, 597 NodeConflictBehavior conflictBehavior ) { 598 if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR; 599 return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior)); 600 } 601 602 /** 603 * Create a request to move a branch from one location into another. 604 * 605 * @param from the location of the top node in the existing branch that is to be moved 606 * @param into the location of the existing node into which the branch should be moved 607 * @param workspaceName the name of the workspace 608 * @return this builder for method chaining; never null 609 * @throws IllegalArgumentException if any of the parameters are null 610 */ 611 public BatchRequestBuilder moveBranch( Location from, 612 Location into, 613 String workspaceName ) { 614 return add(new MoveBranchRequest(from, into, workspaceName, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 615 } 616 617 /** 618 * Create a request to move a branch from one location into another. 619 * 620 * @param from the location of the top node in the existing branch that is to be moved 621 * @param into the location of the existing node into which the branch should be moved 622 * @param workspaceName the name of the workspace 623 * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used 624 * @return this builder for method chaining; never null 625 * @throws IllegalArgumentException if any of the parameters are null 626 */ 627 public BatchRequestBuilder moveBranch( Location from, 628 Location into, 629 String workspaceName, 630 Name newNameForNode ) { 631 return add(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 632 } 633 634 /** 635 * Create a request to move a branch from one location into another. 636 * 637 * @param from the location of the top node in the existing branch that is to be moved 638 * @param into the location of the existing node into which the branch should be moved 639 * @param before the location of the node before which the branch should be moved; may be null 640 * @param workspaceName the name of the workspace 641 * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used 642 * @return this builder for method chaining; never null 643 * @throws IllegalArgumentException if any of the parameters are null 644 */ 645 public BatchRequestBuilder moveBranch( Location from, 646 Location into, 647 Location before, 648 String workspaceName, 649 Name newNameForNode ) { 650 return add(new MoveBranchRequest(from, into, before, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR)); 651 } 652 653 /** 654 * Create a request to move a branch from one location into another. 655 * 656 * @param from the location of the top node in the existing branch that is to be moved 657 * @param into the location of the existing node into which the branch should be moved 658 * @param workspaceName the name of the workspace 659 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code> 660 * location 661 * @return this builder for method chaining; never null 662 * @throws IllegalArgumentException if any of the parameters are null 663 */ 664 public BatchRequestBuilder moveBranch( Location from, 665 Location into, 666 String workspaceName, 667 NodeConflictBehavior conflictBehavior ) { 668 if (conflictBehavior == null) conflictBehavior = MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR; 669 return add(new MoveBranchRequest(from, into, workspaceName, conflictBehavior)); 670 } 671 672 /** 673 * Add a request to delete a branch. 674 * 675 * @param at the location of the top node in the existing branch that is to be deleted 676 * @param workspaceName the name of the workspace containing the parent 677 * @return this builder for method chaining; never null 678 * @throws IllegalArgumentException if the location or workspace name is null 679 */ 680 public BatchRequestBuilder deleteBranch( Location at, 681 String workspaceName ) { 682 return add(new DeleteBranchRequest(at, workspaceName)); 683 } 684 685 /** 686 * {@inheritDoc} 687 * 688 * @see java.lang.Object#toString() 689 */ 690 @Override 691 public String toString() { 692 StringBuilder sb = new StringBuilder(); 693 for (Request request : requests) { 694 sb.append(request.toString()); 695 sb.append("\n"); 696 } 697 return sb.toString(); 698 } 699 700 protected class NodeChange { 701 protected final Location location; 702 protected final String workspaceName; 703 protected final Map<Name, Property> pendingProperties = new HashMap<Name, Property>(); 704 705 protected NodeChange( Location location, 706 String workspaceName ) { 707 this.location = location; 708 this.workspaceName = workspaceName; 709 } 710 711 protected Request toRequest() { 712 if (pendingProperties.size() == 1) { 713 Map.Entry<Name, Property> entry = pendingProperties.entrySet().iterator().next(); 714 Property property = entry.getValue(); 715 if (property == null) { 716 return new RemovePropertyRequest(location, workspaceName, entry.getKey()); 717 } 718 return new SetPropertyRequest(location, workspaceName, property); 719 } 720 return new UpdatePropertiesRequest(location, workspaceName, pendingProperties); 721 } 722 } 723 724 }