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 (under 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 java.util.ArrayList; 27 import java.util.Collection; 28 import java.util.Collections; 29 import java.util.Iterator; 30 import java.util.LinkedList; 31 import java.util.List; 32 import org.modeshape.common.util.CheckArg; 33 import org.modeshape.common.util.HashCode; 34 import org.modeshape.graph.GraphI18n; 35 import org.modeshape.graph.Location; 36 import org.modeshape.graph.NodeConflictBehavior; 37 import org.modeshape.graph.property.Name; 38 import org.modeshape.graph.property.Path; 39 import org.modeshape.graph.property.Property; 40 41 /** 42 * Instruction to create the node under the specified location. This command will create the node and set the initial properties. 43 */ 44 public class CreateNodeRequest extends ChangeRequest implements Iterable<Property> { 45 46 private static final long serialVersionUID = 1L; 47 48 public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND; 49 50 private final Location under; 51 private final String workspaceName; 52 private final Name childName; 53 private final List<Property> properties; 54 private final NodeConflictBehavior conflictBehavior; 55 private Location actualLocation; 56 57 /** 58 * Create a request to create a node with the given properties under the supplied location. 59 * 60 * @param parentLocation the location of the existing parent node, under which the new child should be created 61 * @param workspaceName the name of the workspace containing the parent 62 * @param childName the name of the new child to create under the existing parent 63 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 64 * properties} for the new node 65 * @throws IllegalArgumentException if the location, workspace name, or child name is null 66 */ 67 public CreateNodeRequest( Location parentLocation, 68 String workspaceName, 69 Name childName, 70 Property... properties ) { 71 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties); 72 } 73 74 /** 75 * Create a request to create a node with the given properties under the supplied location. 76 * 77 * @param parentLocation the location of the existing parent node, under which the new child should be created 78 * @param workspaceName the name of the workspace containing the parent 79 * @param childName the name of the new child to create under the existing parent 80 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 81 * properties} for the new node 82 * @throws IllegalArgumentException if the location, workspace name, or child name is null 83 */ 84 public CreateNodeRequest( Location parentLocation, 85 String workspaceName, 86 Name childName, 87 Iterable<Property> properties ) { 88 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties); 89 } 90 91 /** 92 * Create a request to create a node with the given properties under the supplied location. 93 * 94 * @param parentLocation the location of the existing parent node, under which the new child should be created 95 * @param workspaceName the name of the workspace containing the parent 96 * @param childName the name of the new child to create under the existing parent 97 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 98 * properties} for the new node 99 * @throws IllegalArgumentException if the location, workspace name, or child name is null 100 */ 101 public CreateNodeRequest( Location parentLocation, 102 String workspaceName, 103 Name childName, 104 Iterator<Property> properties ) { 105 this(parentLocation, workspaceName, childName, DEFAULT_CONFLICT_BEHAVIOR, properties); 106 } 107 108 /** 109 * Create a request to create a node with the given properties under the supplied location. 110 * 111 * @param parentLocation the location of the existing parent node, under which the new child should be created 112 * @param workspaceName the name of the workspace containing the parent 113 * @param childName the name of the new child to create under the existing parent 114 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 115 * properties} for the new node 116 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code> 117 * location 118 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null 119 */ 120 public CreateNodeRequest( Location parentLocation, 121 String workspaceName, 122 Name childName, 123 NodeConflictBehavior conflictBehavior, 124 Property... properties ) { 125 CheckArg.isNotNull(parentLocation, "parentLocation"); 126 CheckArg.isNotNull(workspaceName, "workspaceName"); 127 CheckArg.isNotNull(conflictBehavior, "conflictBehavior"); 128 CheckArg.isNotNull(childName, "childName"); 129 this.under = parentLocation; 130 this.workspaceName = workspaceName; 131 this.childName = childName; 132 this.conflictBehavior = conflictBehavior; 133 int number = properties.length + (under.hasIdProperties() ? under.getIdProperties().size() : 0); 134 List<Property> props = new ArrayList<Property>(number); 135 for (Property property : properties) { 136 if (property != null) props.add(property); 137 } 138 this.properties = Collections.unmodifiableList(props); 139 } 140 141 /** 142 * Create a request to create a node with the given properties under the supplied location. 143 * 144 * @param parentLocation the location of the existing parent node, under which the new child should be created 145 * @param workspaceName the name of the workspace containing the parent 146 * @param childName the name of the new child to create under the existing parent 147 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 148 * properties} for the new node 149 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code> 150 * location 151 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null 152 */ 153 public CreateNodeRequest( Location parentLocation, 154 String workspaceName, 155 Name childName, 156 NodeConflictBehavior conflictBehavior, 157 Iterable<Property> properties ) { 158 CheckArg.isNotNull(parentLocation, "parentLocation"); 159 CheckArg.isNotNull(workspaceName, "workspaceName"); 160 CheckArg.isNotNull(conflictBehavior, "conflictBehavior"); 161 CheckArg.isNotNull(childName, "childName"); 162 this.under = parentLocation; 163 this.workspaceName = workspaceName; 164 this.childName = childName; 165 this.conflictBehavior = conflictBehavior; 166 List<Property> props = new LinkedList<Property>(); 167 for (Property property : properties) { 168 if (property != null) props.add(property); 169 } 170 this.properties = Collections.unmodifiableList(props); 171 } 172 173 /** 174 * Create a request to create a node with the given properties under the supplied location. 175 * 176 * @param parentLocation the location of the existing parent node, under which the new child should be created 177 * @param workspaceName the name of the workspace containing the parent 178 * @param childName the name of the new child to create under the existing parent 179 * @param properties the properties of the new node, which should include any {@link Location#getIdProperties() identification 180 * properties} for the new node 181 * @param conflictBehavior the expected behavior if an equivalently-named child already exists under the <code>into</code> 182 * location 183 * @throws IllegalArgumentException if the location, workspace name, child name, or the conflict behavior is null 184 */ 185 public CreateNodeRequest( Location parentLocation, 186 String workspaceName, 187 Name childName, 188 NodeConflictBehavior conflictBehavior, 189 Iterator<Property> properties ) { 190 CheckArg.isNotNull(parentLocation, "parentLocation"); 191 CheckArg.isNotNull(workspaceName, "workspaceName"); 192 CheckArg.isNotNull(conflictBehavior, "conflictBehavior"); 193 CheckArg.isNotNull(childName, "childName"); 194 this.under = parentLocation; 195 this.workspaceName = workspaceName; 196 this.childName = childName; 197 this.conflictBehavior = conflictBehavior; 198 List<Property> props = new LinkedList<Property>(); 199 while (properties.hasNext()) { 200 Property property = properties.next(); 201 if (property != null) props.add(property); 202 } 203 this.properties = Collections.unmodifiableList(props); 204 } 205 206 /** 207 * Get the location defining the parent of the new node that is to be created. 208 * 209 * @return the location of the parent node; never null 210 */ 211 public Location under() { 212 return under; 213 } 214 215 /** 216 * Get the name of the workspace in which the node is to be createde 217 * 218 * @return the name of the workspace; never null 219 */ 220 public String inWorkspace() { 221 return workspaceName; 222 } 223 224 /** 225 * Get the name for the new child. 226 * 227 * @return the child's name; never null 228 */ 229 public Name named() { 230 return childName; 231 } 232 233 /** 234 * {@inheritDoc} 235 * 236 * @see java.lang.Iterable#iterator() 237 */ 238 public Iterator<Property> iterator() { 239 return this.properties.iterator(); 240 } 241 242 /** 243 * Get the properties for the node. If the node's {@link #under() location} has identification properties, the resulting 244 * properties will include the {@link Location#getIdProperties() identification properties}. 245 * 246 * @return the collection of properties; never null 247 */ 248 public Collection<Property> properties() { 249 return properties; 250 } 251 252 /** 253 * Get the expected behavior when copying the branch and the {@link #under() destination} already has a node with the same 254 * name. 255 * 256 * @return the behavior specification 257 */ 258 public NodeConflictBehavior conflictBehavior() { 259 return conflictBehavior; 260 } 261 262 /** 263 * {@inheritDoc} 264 * 265 * @see org.modeshape.graph.request.Request#isReadOnly() 266 */ 267 @Override 268 public boolean isReadOnly() { 269 return false; 270 } 271 272 /** 273 * Sets the actual and complete location of the node being created. This method must be called when processing the request, 274 * and the actual location must have a {@link Location#getPath() path}. 275 * 276 * @param actual the actual location of the node being created, or null if the {@link #under() current location} should be 277 * used 278 * @throws IllegalArgumentException the actual location is null or does not have a path 279 * @throws IllegalStateException if the request is frozen 280 */ 281 public void setActualLocationOfNode( Location actual ) { 282 checkNotFrozen(); 283 CheckArg.isNotNull(actual, "actual"); 284 if (!actual.hasPath()) { 285 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual)); 286 } 287 assert actual.hasPath(); 288 this.actualLocation = actual; 289 } 290 291 /** 292 * Get the actual location of the node that was created. 293 * 294 * @return the actual location, or null if the actual location was not set 295 */ 296 public Location getActualLocationOfNode() { 297 return actualLocation; 298 } 299 300 /** 301 * {@inheritDoc} 302 * 303 * @see org.modeshape.graph.request.ChangeRequest#changes(java.lang.String, org.modeshape.graph.property.Path) 304 */ 305 @Override 306 public boolean changes( String workspace, 307 Path path ) { 308 return this.workspaceName.equals(workspace) && under.hasPath() && under.getPath().isAtOrBelow(path); 309 } 310 311 /** 312 * {@inheritDoc} 313 * 314 * @see org.modeshape.graph.request.ChangeRequest#changedLocation() 315 */ 316 @Override 317 public Location changedLocation() { 318 return actualLocation != null ? actualLocation : under; 319 } 320 321 /** 322 * {@inheritDoc} 323 * 324 * @see org.modeshape.graph.request.ChangeRequest#changedWorkspace() 325 */ 326 @Override 327 public String changedWorkspace() { 328 return workspaceName; 329 } 330 331 /** 332 * {@inheritDoc} 333 * 334 * @see org.modeshape.graph.request.Request#cancel() 335 */ 336 @Override 337 public void cancel() { 338 super.cancel(); 339 this.actualLocation = null; 340 } 341 342 /** 343 * {@inheritDoc} 344 * 345 * @see java.lang.Object#hashCode() 346 */ 347 @Override 348 public int hashCode() { 349 return HashCode.compute(under, childName, workspaceName); 350 } 351 352 /** 353 * {@inheritDoc} 354 * 355 * @see java.lang.Object#equals(java.lang.Object) 356 */ 357 @Override 358 public boolean equals( Object obj ) { 359 if (obj == this) return true; 360 if (this.getClass().isInstance(obj)) { 361 CreateNodeRequest that = (CreateNodeRequest)obj; 362 if (!this.under().isSame(that.under())) return false; 363 if (!this.conflictBehavior().equals(that.conflictBehavior())) return false; 364 if (!this.inWorkspace().equals(that.conflictBehavior())) return false; 365 if (!this.properties().equals(that.properties())) return false; 366 return true; 367 } 368 return false; 369 } 370 371 /** 372 * {@inheritDoc} 373 * 374 * @see java.lang.Object#toString() 375 */ 376 @Override 377 public String toString() { 378 String parent = under() + "/"; 379 if (under.hasPath() && under.getPath().isRoot()) parent = "/"; 380 return "create in the \"" + workspaceName + "\" workspace the node \"" + parent + childName + "\" with properties " 381 + properties(); 382 } 383 384 /** 385 * {@inheritDoc} 386 * <p> 387 * This method does not clone the results. 388 * </p> 389 * 390 * @see org.modeshape.graph.request.ChangeRequest#clone() 391 */ 392 @Override 393 public CreateNodeRequest clone() { 394 CreateNodeRequest request = new CreateNodeRequest(under, workspaceName, childName, conflictBehavior, properties); 395 request.setActualLocationOfNode(actualLocation); 396 return request; 397 } 398 399 @Override 400 public RequestType getType() { 401 return RequestType.CREATE_NODE; 402 } 403 }