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 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed 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 org.jboss.dna.common.util.CheckArg;
027 import org.jboss.dna.graph.GraphI18n;
028 import org.jboss.dna.graph.Location;
029 import org.jboss.dna.graph.NodeConflictBehavior;
030 import org.jboss.dna.graph.property.Name;
031 import org.jboss.dna.graph.property.Path;
032
033 /**
034 * Instruction that a branch be copied from one location into another. This request can copy a branch in one workspace into
035 * another workspace, or it can copy a branch in the same workspace.
036 *
037 * @author Randall Hauch
038 */
039 public class CopyBranchRequest extends Request implements ChangeRequest {
040
041 private static final long serialVersionUID = 1L;
042
043 public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
044
045 private final Location from;
046 private final Location into;
047 private final String fromWorkspace;
048 private final String intoWorkspace;
049 private final Name desiredNameForCopy;
050 private final NodeConflictBehavior conflictBehavior;
051 private Location actualFromLocation;
052 private Location actualIntoLocation;
053
054 /**
055 * Create a request to copy a branch to another.
056 *
057 * @param from the location of the top node in the existing branch that is to be copied
058 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
059 * @param into the location of the existing node into which the copy should be placed
060 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied, or null if the source's
061 * default workspace is to be used
062 * @throws IllegalArgumentException if any of the parameters are null
063 */
064 public CopyBranchRequest( Location from,
065 String fromWorkspace,
066 Location into,
067 String intoWorkspace ) {
068 this(from, fromWorkspace, into, intoWorkspace, null, DEFAULT_CONFLICT_BEHAVIOR);
069 }
070
071 /**
072 * Create a request to copy a branch to another.
073 *
074 * @param from the location of the top node in the existing branch that is to be copied
075 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
076 * @param into the location of the existing node into which the copy should be placed
077 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied
078 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
079 * used
080 * @throws IllegalArgumentException if any of the parameters are null
081 */
082 public CopyBranchRequest( Location from,
083 String fromWorkspace,
084 Location into,
085 String intoWorkspace,
086 Name nameForCopy ) {
087 this(from, fromWorkspace, into, intoWorkspace, nameForCopy, DEFAULT_CONFLICT_BEHAVIOR);
088 }
089
090 /**
091 * Create a request to copy a branch to another.
092 *
093 * @param from the location of the top node in the existing branch that is to be copied
094 * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
095 * @param into the location of the existing node into which the copy should be placed
096 * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied
097 * @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
098 * used
099 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
100 * location
101 * @throws IllegalArgumentException if any of the parameters are null
102 */
103 public CopyBranchRequest( Location from,
104 String fromWorkspace,
105 Location into,
106 String intoWorkspace,
107 Name nameForCopy,
108 NodeConflictBehavior conflictBehavior ) {
109 CheckArg.isNotNull(from, "from");
110 CheckArg.isNotNull(into, "into");
111 CheckArg.isNotNull(fromWorkspace, "fromWorkspace");
112 CheckArg.isNotNull(intoWorkspace, "intoWorkspace");
113 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
114 this.from = from;
115 this.into = into;
116 this.fromWorkspace = fromWorkspace;
117 this.intoWorkspace = intoWorkspace;
118 this.desiredNameForCopy = nameForCopy;
119 this.conflictBehavior = conflictBehavior;
120 }
121
122 /**
123 * Get the location defining the top of the branch to be copied
124 *
125 * @return the from location; never null
126 */
127 public Location from() {
128 return from;
129 }
130
131 /**
132 * Get the location defining the parent where the new copy is to be placed
133 *
134 * @return the to location; never null
135 */
136 public Location into() {
137 return into;
138 }
139
140 /**
141 * Get the name of the workspace containing the branch to be copied.
142 *
143 * @return the name of the workspace containing the branch to be copied; never null
144 */
145 public String fromWorkspace() {
146 return fromWorkspace;
147 }
148
149 /**
150 * Get the name of the workspace where the copy is to be placed
151 *
152 * @return the name of the workspace where the copy is to be placed; never null
153 */
154 public String intoWorkspace() {
155 return intoWorkspace;
156 }
157
158 /**
159 * Determine whether this copy operation is within the same workspace.
160 *
161 * @return true if this operation is to be performed within the same workspace, or false if the workspace of the
162 * {@link #from() original} is different than that of the {@link #into() copy}
163 */
164 public boolean isSameWorkspace() {
165 return fromWorkspace.equals(intoWorkspace);
166 }
167
168 /**
169 * Get the name of the copy if it is to be different than that of the original.
170 *
171 * @return the desired name of the copy, or null if the name of the original is to be used
172 */
173 public Name desiredName() {
174 return desiredNameForCopy;
175 }
176
177 /**
178 * {@inheritDoc}
179 *
180 * @see org.jboss.dna.graph.request.Request#isReadOnly()
181 */
182 @Override
183 public boolean isReadOnly() {
184 return false;
185 }
186
187 /**
188 * Get the expected behavior when copying the branch and the {@link #into() destination} already has a node with the same
189 * name.
190 *
191 * @return the behavior specification
192 */
193 public NodeConflictBehavior conflictBehavior() {
194 return conflictBehavior;
195 }
196
197 /**
198 * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
199 * processing the request, and the actual location must have a {@link Location#getPath() path}.
200 *
201 * @param fromLocation the actual location of the node being copied
202 * @param intoLocation the actual location of the new copy of the node
203 * @throws IllegalArgumentException if the either location is null; if the old location does not represent the
204 * {@link Location#isSame(Location) same location} as the {@link #from() from location}; if the new location does not
205 * represent the {@link Location#isSame(Location) same location} as the {@link #into() into location}; if the either
206 * location does not have a path
207 */
208 public void setActualLocations( Location fromLocation,
209 Location intoLocation ) {
210 if (!from.isSame(fromLocation)) { // not same if actual is null
211 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(fromLocation, from));
212 }
213 CheckArg.isNotNull(intoLocation, "intoLocation");
214 assert fromLocation != null;
215 assert intoLocation != null;
216 if (!fromLocation.hasPath()) {
217 throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(fromLocation));
218 }
219 if (!intoLocation.hasPath()) {
220 throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(intoLocation));
221 }
222 // The 'into' should be the parent of the 'newLocation' ...
223 if (into.hasPath() && !intoLocation.getPath().getParent().equals(into.getPath())) {
224 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotChildOfInputLocation.text(intoLocation, into));
225 }
226 this.actualFromLocation = fromLocation;
227 this.actualIntoLocation = intoLocation;
228 }
229
230 /**
231 * Get the actual location of the node before being copied.
232 *
233 * @return the actual location of the node before being moved, or null if the actual location was not set
234 */
235 public Location getActualLocationBefore() {
236 return actualFromLocation;
237 }
238
239 /**
240 * Get the actual location of the node after being copied.
241 *
242 * @return the actual location of the node after being copied, or null if the actual location was not set
243 */
244 public Location getActualLocationAfter() {
245 return actualIntoLocation;
246 }
247
248 /**
249 * {@inheritDoc}
250 *
251 * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
252 */
253 public boolean changes( String workspace,
254 Path path ) {
255 return this.intoWorkspace.equals(workspace) && into.hasPath() && into.getPath().isAtOrBelow(path);
256 }
257
258 /**
259 * {@inheritDoc}
260 *
261 * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
262 */
263 public Location changedLocation() {
264 return into;
265 }
266
267 /**
268 * {@inheritDoc}
269 *
270 * @see java.lang.Object#equals(java.lang.Object)
271 */
272 @Override
273 public boolean equals( Object obj ) {
274 if (obj == this) return true;
275 if (this.getClass().isInstance(obj)) {
276 CopyBranchRequest that = (CopyBranchRequest)obj;
277 if (!this.from().equals(that.from())) return false;
278 if (!this.into().equals(that.into())) return false;
279 if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
280 if (!this.fromWorkspace.equals(that.fromWorkspace)) return false;
281 if (!this.intoWorkspace.equals(that.intoWorkspace)) return false;
282 return true;
283 }
284 return false;
285 }
286
287 /**
288 * {@inheritDoc}
289 *
290 * @see java.lang.Object#toString()
291 */
292 @Override
293 public String toString() {
294 if (fromWorkspace.equals(intoWorkspace)) {
295 if (desiredNameForCopy != null) {
296 return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " with name "
297 + desiredNameForCopy;
298 }
299 return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into();
300 }
301 if (desiredNameForCopy != null) {
302 return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " with name "
303 + desiredNameForCopy + " in the \"" + intoWorkspace + "\" workspace";
304 }
305 return "copy branch " + from() + " in the \"" + fromWorkspace + "\" workspace into " + into() + " in the \""
306 + intoWorkspace + "\" workspace";
307 }
308 }