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 }