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 }