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