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 (under 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.ArrayList;
027 import java.util.Collection;
028 import java.util.Collections;
029 import java.util.Iterator;
030 import java.util.LinkedList;
031 import java.util.List;
032 import org.jboss.dna.common.util.CheckArg;
033 import org.jboss.dna.graph.GraphI18n;
034 import org.jboss.dna.graph.Location;
035 import org.jboss.dna.graph.NodeConflictBehavior;
036 import org.jboss.dna.graph.property.Name;
037 import org.jboss.dna.graph.property.Path;
038 import org.jboss.dna.graph.property.Property;
039
040 /**
041 * Instruction to create the node under the specified location. This command will create the node and set the initial properties.
042 *
043 * @author Randall Hauch
044 */
045 public class CreateNodeRequest extends Request implements Iterable<Property>, ChangeRequest {
046
047 private static final long serialVersionUID = 1L;
048
049 public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
050
051 private final Location under;
052 private final String workspaceName;
053 private final Name childName;
054 private final List<Property> properties;
055 private final NodeConflictBehavior conflictBehavior;
056 private Location actualLocation;
057
058 /**
059 * Create a request to create a node with the given properties under the supplied location.
060 *
061 * @param parentLocation the location of the existing parent node, under which the new child should be created
062 * @param workspaceName the name of the workspace containing the parent
063 * @param childName the name of the new child to create under the existing parent
064 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
065 * properties} for the new node
066 * @throws IllegalArgumentException if the location, workspace name, or child name is null
067 */
068 public CreateNodeRequest( Location parentLocation,
069 String workspaceName,
070 Name childName,
071 Property... properties ) {
072 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
073 }
074
075 /**
076 * Create a request to create a node with the given properties under the supplied location.
077 *
078 * @param parentLocation the location of the existing parent node, under which the new child should be created
079 * @param workspaceName the name of the workspace containing the parent
080 * @param childName the name of the new child to create under the existing parent
081 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
082 * properties} for the new node
083 * @throws IllegalArgumentException if the location, workspace name, or child name is null
084 */
085 public CreateNodeRequest( Location parentLocation,
086 String workspaceName,
087 Name childName,
088 Iterable<Property> properties ) {
089 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
090 }
091
092 /**
093 * Create a request to create a node with the given properties under the supplied location.
094 *
095 * @param parentLocation the location of the existing parent node, under which the new child should be created
096 * @param workspaceName the name of the workspace containing the parent
097 * @param childName the name of the new child to create under the existing parent
098 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
099 * properties} for the new node
100 * @throws IllegalArgumentException if the location, workspace name, or child name is null
101 */
102 public CreateNodeRequest( Location parentLocation,
103 String workspaceName,
104 Name childName,
105 Iterator<Property> properties ) {
106 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties);
107 }
108
109 /**
110 * Create a request to create a node with the given properties under the supplied location.
111 *
112 * @param parentLocation the location of the existing parent node, under which the new child should be created
113 * @param workspaceName the name of the workspace containing the parent
114 * @param childName the name of the new child to create under the existing parent
115 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
116 * properties} for the new node
117 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
118 * location
119 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null
120 */
121 public CreateNodeRequest( Location parentLocation,
122 String workspaceName,
123 Name childName,
124 NodeConflictBehavior conflictBehavior,
125 Property... properties ) {
126 CheckArg.isNotNull(parentLocation, "parentLocation");
127 CheckArg.isNotNull(workspaceName, "workspaceName");
128 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
129 CheckArg.isNotNull(childName, "childName");
130 this.under = parentLocation;
131 this.workspaceName = workspaceName;
132 this.childName = childName;
133 this.conflictBehavior = conflictBehavior;
134 int number = properties.length + (under.hasIdProperties() ? under.getIdProperties().size() : 0);
135 List<Property> props = new ArrayList<Property>(number);
136 for (Property property : properties) {
137 if (property != null) props.add(property);
138 }
139 this.properties = Collections.unmodifiableList(props);
140 }
141
142 /**
143 * Create a request to create a node with the given properties under the supplied location.
144 *
145 * @param parentLocation the location of the existing parent node, under which the new child should be created
146 * @param workspaceName the name of the workspace containing the parent
147 * @param childName the name of the new child to create under the existing parent
148 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
149 * properties} for the new node
150 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
151 * location
152 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null
153 */
154 public CreateNodeRequest( Location parentLocation,
155 String workspaceName,
156 Name childName,
157 NodeConflictBehavior conflictBehavior,
158 Iterable<Property> properties ) {
159 CheckArg.isNotNull(parentLocation, "parentLocation");
160 CheckArg.isNotNull(workspaceName, "workspaceName");
161 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
162 CheckArg.isNotNull(childName, "childName");
163 this.under = parentLocation;
164 this.workspaceName = workspaceName;
165 this.childName = childName;
166 this.conflictBehavior = conflictBehavior;
167 List<Property> props = new LinkedList<Property>();
168 for (Property property : properties) {
169 if (property != null) props.add(property);
170 }
171 this.properties = Collections.unmodifiableList(props);
172 }
173
174 /**
175 * Create a request to create a node with the given properties under the supplied location.
176 *
177 * @param parentLocation the location of the existing parent node, under which the new child should be created
178 * @param workspaceName the name of the workspace containing the parent
179 * @param childName the name of the new child to create under the existing parent
180 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification
181 * properties} for the new node
182 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code>
183 * location
184 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null
185 */
186 public CreateNodeRequest( Location parentLocation,
187 String workspaceName,
188 Name childName,
189 NodeConflictBehavior conflictBehavior,
190 Iterator<Property> properties ) {
191 CheckArg.isNotNull(parentLocation, "parentLocation");
192 CheckArg.isNotNull(workspaceName, "workspaceName");
193 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
194 CheckArg.isNotNull(childName, "childName");
195 this.under = parentLocation;
196 this.workspaceName = workspaceName;
197 this.childName = childName;
198 this.conflictBehavior = conflictBehavior;
199 List<Property> props = new LinkedList<Property>();
200 while (properties.hasNext()) {
201 Property property = properties.next();
202 if (property != null) props.add(property);
203 }
204 this.properties = Collections.unmodifiableList(props);
205 }
206
207 /**
208 * Get the location defining the parent of the new node that is to be created.
209 *
210 * @return the location of the parent node; never null
211 */
212 public Location under() {
213 return under;
214 }
215
216 /**
217 * Get the name of the workspace in which the node is to be createde
218 *
219 * @return the name of the workspace; never null
220 */
221 public String inWorkspace() {
222 return workspaceName;
223 }
224
225 /**
226 * Get the name for the new child.
227 *
228 * @return the child's name; never null
229 */
230 public Name named() {
231 return childName;
232 }
233
234 /**
235 * {@inheritDoc}
236 *
237 * @see java.lang.Iterable#iterator()
238 */
239 public Iterator<Property> iterator() {
240 return this.properties.iterator();
241 }
242
243 /**
244 * Get the properties for the node. If the node's {@link #under() location} has identification properties, the resulting
245 * properties will include the {@link Location#getIdProperties() identification properties}.
246 *
247 * @return the collection of properties; never null
248 */
249 public Collection<Property> properties() {
250 return properties;
251 }
252
253 /**
254 * Get the expected behavior when copying the branch and the {@link #under() destination} already has a node with the same
255 * name.
256 *
257 * @return the behavior specification
258 */
259 public NodeConflictBehavior conflictBehavior() {
260 return conflictBehavior;
261 }
262
263 /**
264 * {@inheritDoc}
265 *
266 * @see org.jboss.dna.graph.request.Request#isReadOnly()
267 */
268 @Override
269 public boolean isReadOnly() {
270 return false;
271 }
272
273 /**
274 * Sets the actual and complete location of the node being created. This method must be called when processing the request,
275 * and the actual location must have a {@link Location#getPath() path}.
276 *
277 * @param actual the actual location of the node being created, or null if the {@link #under() current location} should be
278 * used
279 * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
280 * location} as the {@link #under() current location}, or if the actual location does not have a path.
281 */
282 public void setActualLocationOfNode( Location actual ) {
283 CheckArg.isNotNull(actual, "actual");
284 if (!under.isSame(actual, false)) { // not same if actual is null
285 }
286 assert actual != null;
287 if (!actual.hasPath()) {
288 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
289 }
290 assert actual.hasPath();
291 if (under.hasPath() && !under.getPath().equals(actual.getPath().getParent())) {
292 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, under));
293 }
294 this.actualLocation = actual;
295 }
296
297 /**
298 * Get the actual location of the node that was created.
299 *
300 * @return the actual location, or null if the actual location was not set
301 */
302 public Location getActualLocationOfNode() {
303 return actualLocation;
304 }
305
306 /**
307 * {@inheritDoc}
308 *
309 * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
310 */
311 public boolean changes( String workspace,
312 Path path ) {
313 return this.workspaceName.equals(workspace) && under.hasPath() && under.getPath().isAtOrBelow(path);
314 }
315
316 /**
317 * {@inheritDoc}
318 *
319 * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
320 */
321 public Location changedLocation() {
322 return under;
323 }
324
325 /**
326 * {@inheritDoc}
327 *
328 * @see java.lang.Object#equals(java.lang.Object)
329 */
330 @Override
331 public boolean equals( Object obj ) {
332 if (obj == this) return true;
333 if (this.getClass().isInstance(obj)) {
334 CreateNodeRequest that = (CreateNodeRequest)obj;
335 if (!this.under().equals(that.under())) return false;
336 if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
337 if (!this.inWorkspace().equals(that.conflictBehavior())) return false;
338 if (!this.properties().equals(that.properties())) return false;
339 return true;
340 }
341 return false;
342 }
343
344 /**
345 * {@inheritDoc}
346 *
347 * @see java.lang.Object#toString()
348 */
349 @Override
350 public String toString() {
351 String parent = under() + "/";
352 if (under.hasPath() && under.getPath().isRoot()) parent = "/";
353 return "create in the \"" + workspaceName + "\" workspace the node \"" + parent + childName + "\" with properties "
354 + properties();
355 }
356
357 }