View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.request;
25  
26  import org.modeshape.common.util.CheckArg;
27  import org.modeshape.common.util.HashCode;
28  import org.modeshape.graph.GraphI18n;
29  import org.modeshape.graph.Location;
30  import org.modeshape.graph.NodeConflictBehavior;
31  import org.modeshape.graph.property.Name;
32  import org.modeshape.graph.property.Path;
33  
34  /**
35   * Instruction that a branch be copied from one location into another. This request can copy a branch in one workspace into
36   * another workspace, or it can copy a branch in the same workspace. Copying a branch always results in the generation of new
37   * UUIDs for the copied nodes. {@link CloneBranchRequest Cloning a branch} provides functionality similar to copy, but with the
38   * ability to preserve UUIDs in the move.
39   * 
40   * @see CloneBranchRequest
41   */
42  public class CopyBranchRequest extends ChangeRequest {
43  
44      private static final long serialVersionUID = 1L;
45  
46      public static final NodeConflictBehavior DEFAULT_NODE_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
47  
48      private final Location from;
49      private final Location into;
50      private final String fromWorkspace;
51      private final String intoWorkspace;
52      private final Name desiredNameForCopy;
53      private final NodeConflictBehavior nodeConflictBehavior;
54      private Location actualFromLocation;
55      private Location actualIntoLocation;
56  
57      /**
58       * Create a request to copy a branch to another.
59       * 
60       * @param from the location of the top node in the existing branch that is to be copied
61       * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
62       * @param into the location of the existing node into which the copy should be placed
63       * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied, or null if the source's
64       *        default workspace is to be used
65       * @throws IllegalArgumentException if any of the parameters are null
66       */
67      public CopyBranchRequest( Location from,
68                                String fromWorkspace,
69                                Location into,
70                                String intoWorkspace ) {
71          this(from, fromWorkspace, into, intoWorkspace, null, DEFAULT_NODE_CONFLICT_BEHAVIOR);
72      }
73  
74      /**
75       * Create a request to copy a branch to another.
76       * 
77       * @param from the location of the top node in the existing branch that is to be copied
78       * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
79       * @param into the location of the existing node into which the copy should be placed
80       * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied
81       * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
82       *        used
83       * @throws IllegalArgumentException if any of the parameters are null
84       */
85      public CopyBranchRequest( Location from,
86                                String fromWorkspace,
87                                Location into,
88                                String intoWorkspace,
89                                Name nameForCopy ) {
90          this(from, fromWorkspace, into, intoWorkspace, nameForCopy, DEFAULT_NODE_CONFLICT_BEHAVIOR);
91      }
92  
93      /**
94       * Create a request to copy a branch to another.
95       * 
96       * @param from the location of the top node in the existing branch that is to be copied
97       * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
98       * @param into the location of the existing node into which the copy should be placed
99       * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied
100      * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
101      *        used
102      * @param nodeConflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
103      *        location
104      * @throws IllegalArgumentException if any of the parameters are null
105      */
106     public CopyBranchRequest( Location from,
107                               String fromWorkspace,
108                               Location into,
109                               String intoWorkspace,
110                               Name nameForCopy,
111                               NodeConflictBehavior nodeConflictBehavior ) {
112         CheckArg.isNotNull(from, "from");
113         CheckArg.isNotNull(into, "into");
114         CheckArg.isNotNull(fromWorkspace, "fromWorkspace");
115         CheckArg.isNotNull(intoWorkspace, "intoWorkspace");
116         CheckArg.isNotNull(nodeConflictBehavior, "nodeConflictBehavior");
117         this.from = from;
118         this.into = into;
119         this.fromWorkspace = fromWorkspace;
120         this.intoWorkspace = intoWorkspace;
121         this.desiredNameForCopy = nameForCopy;
122         this.nodeConflictBehavior = nodeConflictBehavior;
123     }
124 
125     /**
126      * Get the location defining the top of the branch to be copied
127      * 
128      * @return the from location; never null
129      */
130     public Location from() {
131         return from;
132     }
133 
134     /**
135      * Get the location defining the parent where the new copy is to be placed
136      * 
137      * @return the to location; never null
138      */
139     public Location into() {
140         return into;
141     }
142 
143     /**
144      * Get the name of the workspace containing the branch to be copied.
145      * 
146      * @return the name of the workspace containing the branch to be copied; never null
147      */
148     public String fromWorkspace() {
149         return fromWorkspace;
150     }
151 
152     /**
153      * Get the name of the workspace where the copy is to be placed
154      * 
155      * @return the name of the workspace where the copy is to be placed; never null
156      */
157     public String intoWorkspace() {
158         return intoWorkspace;
159     }
160 
161     /**
162      * Determine whether this copy operation is within the same workspace.
163      * 
164      * @return true if this operation is to be performed within the same workspace, or false if the workspace of the
165      *         {@link #from() original} is different than that of the {@link #into() copy}
166      */
167     public boolean isSameWorkspace() {
168         return fromWorkspace.equals(intoWorkspace);
169     }
170 
171     /**
172      * Get the name of the copy if it is to be different than that of the original.
173      * 
174      * @return the desired name of the copy, or null if the name of the original is to be used
175      */
176     public Name desiredName() {
177         return desiredNameForCopy;
178     }
179 
180     /**
181      * {@inheritDoc}
182      * 
183      * @see org.modeshape.graph.request.Request#isReadOnly()
184      */
185     @Override
186     public boolean isReadOnly() {
187         return false;
188     }
189 
190     /**
191      * Get the expected behavior when copying the branch and the {@link #into() destination} already has a node with the same
192      * name.
193      * 
194      * @return the behavior specification
195      */
196     public NodeConflictBehavior nodeConflictBehavior() {
197         return nodeConflictBehavior;
198     }
199 
200     /**
201      * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
202      * processing the request, and the actual location must have a {@link Location#getPath() path}.
203      * 
204      * @param fromLocation the actual location of the node being copied
205      * @param intoLocation the actual location of the new copy of the node
206      * @throws IllegalArgumentException if the either location is null; or if the either location does not have a path
207      * @throws IllegalStateException if the request is frozen
208      */
209     public void setActualLocations( Location fromLocation,
210                                     Location intoLocation ) {
211         checkNotFrozen();
212         CheckArg.isNotNull(fromLocation, "intoLocation");
213         CheckArg.isNotNull(intoLocation, "intoLocation");
214         if (!fromLocation.hasPath()) {
215             throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(fromLocation));
216         }
217         if (!intoLocation.hasPath()) {
218             throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(intoLocation));
219         }
220         this.actualFromLocation = fromLocation;
221         this.actualIntoLocation = intoLocation;
222     }
223 
224     /**
225      * Get the actual location of the node before being copied.
226      * 
227      * @return the actual location of the node before being moved, or null if the actual location was not set
228      */
229     public Location getActualLocationBefore() {
230         return actualFromLocation;
231     }
232 
233     /**
234      * Get the actual location of the node after being copied.
235      * 
236      * @return the actual location of the node after being copied, or null if the actual location was not set
237      */
238     public Location getActualLocationAfter() {
239         return actualIntoLocation;
240     }
241 
242     /**
243      * {@inheritDoc}
244      * 
245      * @see org.modeshape.graph.request.ChangeRequest#changes(java.lang.String, org.modeshape.graph.property.Path)
246      */
247     @Override
248     public boolean changes( String workspace,
249                             Path path ) {
250         return this.intoWorkspace.equals(workspace) && into.hasPath() && into.getPath().isAtOrBelow(path);
251     }
252 
253     /**
254      * {@inheritDoc}
255      * 
256      * @see org.modeshape.graph.request.ChangeRequest#changedLocation()
257      */
258     @Override
259     public Location changedLocation() {
260         return actualIntoLocation != null ? actualIntoLocation : into;
261     }
262 
263     /**
264      * {@inheritDoc}
265      * 
266      * @see org.modeshape.graph.request.ChangeRequest#changedWorkspace()
267      */
268     @Override
269     public String changedWorkspace() {
270         return intoWorkspace();
271     }
272 
273     /**
274      * {@inheritDoc}
275      * 
276      * @see java.lang.Object#hashCode()
277      */
278     @Override
279     public int hashCode() {
280         return HashCode.compute(from, fromWorkspace, into, intoWorkspace);
281     }
282 
283     /**
284      * {@inheritDoc}
285      * 
286      * @see org.modeshape.graph.request.Request#cancel()
287      */
288     @Override
289     public void cancel() {
290         super.cancel();
291         this.actualFromLocation = null;
292         this.actualIntoLocation = null;
293     }
294 
295     /**
296      * {@inheritDoc}
297      * 
298      * @see java.lang.Object#equals(java.lang.Object)
299      */
300     @Override
301     public boolean equals( Object obj ) {
302         if (obj == this) return true;
303         if (this.getClass().isInstance(obj)) {
304             CopyBranchRequest that = (CopyBranchRequest)obj;
305             if (!this.from().isSame(that.from())) return false;
306             if (!this.into().isSame(that.into())) return false;
307             if (!this.nodeConflictBehavior().equals(that.nodeConflictBehavior())) return false;
308             if (!this.fromWorkspace.equals(that.fromWorkspace)) return false;
309             if (!this.intoWorkspace.equals(that.intoWorkspace)) return false;
310             return true;
311         }
312         return false;
313     }
314 
315     /**
316      * {@inheritDoc}
317      * 
318      * @see java.lang.Object#toString()
319      */
320     @Override
321     public String toString() {
322         if (fromWorkspace.equals(intoWorkspace)) {
323             if (desiredNameForCopy != null) {
324                 return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " with name "
325                        + desiredNameForCopy;
326             }
327             return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into();
328         }
329         if (desiredNameForCopy != null) {
330             return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " with name "
331                    + desiredNameForCopy + " in the \"" + intoWorkspace + "\" workspace";
332         }
333         return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " in the \""
334                + intoWorkspace + "\" workspace";
335     }
336 
337     /**
338      * {@inheritDoc}
339      * <p>
340      * This method does not clone the results.
341      * </p>
342      * 
343      * @see org.modeshape.graph.request.ChangeRequest#clone()
344      */
345     @Override
346     public CopyBranchRequest clone() {
347         CopyBranchRequest result = new CopyBranchRequest(actualFromLocation != null ? actualFromLocation : from, fromWorkspace,
348                                                          actualIntoLocation != null ? actualIntoLocation : into, intoWorkspace,
349                                                          desiredNameForCopy, nodeConflictBehavior);
350         result.setActualLocations(actualFromLocation, actualIntoLocation);
351         return result;
352     }
353 
354     @Override
355     public RequestType getType() {
356         return RequestType.COPY_BRANCH;
357     }
358 }