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 }