001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.graph.requests;
023
024 import java.util.ArrayList;
025 import java.util.Collection;
026 import java.util.Collections;
027 import java.util.Iterator;
028 import java.util.LinkedList;
029 import java.util.List;
030 import org.jboss.dna.common.util.CheckArg;
031 import org.jboss.dna.graph.GraphI18n;
032 import org.jboss.dna.graph.Location;
033 import org.jboss.dna.graph.NodeConflictBehavior;
034 import org.jboss.dna.graph.properties.Property;
035
036 /**
037 * Instruction to create the node at the specified location. This command will create the node and set the initial properties.
038 *
039 * @author Randall Hauch
040 */
041 public class CreateNodeRequest extends Request implements Iterable<Property> {
042
043 private static final long serialVersionUID = 1L;
044
045 public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
046
047 private final Location at;
048 private final List<Property> properties;
049 private final NodeConflictBehavior conflictBehavior;
050 private Location actualLocation;
051
052 /**
053 * Create a request to create a node with the given properties at the supplied location.
054 *
055 * @param at the location of the node to be read
056 * @param properties the properties of the new node, which should not include the location's
057 * {@link Location#getIdProperties() identification properties}
058 * @throws IllegalArgumentException if the location is null
059 */
060 public CreateNodeRequest( Location at,
061 Property... properties ) {
062 this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
063 }
064
065 /**
066 * Create a request to create a node with the given properties at the supplied location.
067 *
068 * @param at the location of the node to be read
069 * @param properties the properties of the new node, which should not include the location's
070 * {@link Location#getIdProperties() identification properties}
071 * @throws IllegalArgumentException if the location is null
072 */
073 public CreateNodeRequest( Location at,
074 Iterable<Property> properties ) {
075 this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
076 }
077
078 /**
079 * Create a request to create a node with the given properties at the supplied location.
080 *
081 * @param at the location of the node to be read
082 * @param properties the properties of the new node, which should not include the location's
083 * {@link Location#getIdProperties() identification properties}
084 * @throws IllegalArgumentException if the location is null
085 */
086 public CreateNodeRequest( Location at,
087 Iterator<Property> properties ) {
088 this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
089 }
090
091 /**
092 * Create a request to create a node with the given properties at the supplied location.
093 *
094 * @param at the location of the node to be read
095 * @param properties the properties of the new node, which should not include the location's
096 * {@link Location#getIdProperties() identification properties}
097 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
098 * location
099 * @throws IllegalArgumentException if the location or the conflict behavior is null
100 */
101 public CreateNodeRequest( Location at,
102 NodeConflictBehavior conflictBehavior,
103 Property... properties ) {
104 CheckArg.isNotNull(at, "at");
105 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
106 this.at = at;
107 this.conflictBehavior = conflictBehavior;
108 int number = properties.length + (at.hasIdProperties() ? at.getIdProperties().size() : 0);
109 List<Property> props = new ArrayList<Property>(number);
110 for (Property property : properties) {
111 if (property != null) props.add(property);
112 }
113 // Add in the location properties ...
114 if (at.hasIdProperties()) {
115 for (Property property : at.getIdProperties()) {
116 if (property != null) props.add(property);
117 }
118 }
119 this.properties = Collections.unmodifiableList(props);
120 }
121
122 /**
123 * Create a request to create a node with the given properties at the supplied location.
124 *
125 * @param at the location of the node to be read
126 * @param properties the properties of the new node, which should not include the location's
127 * {@link Location#getIdProperties() identification properties}
128 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
129 * location
130 * @throws IllegalArgumentException if the location or the conflict behavior is null
131 */
132 public CreateNodeRequest( Location at,
133 NodeConflictBehavior conflictBehavior,
134 Iterable<Property> properties ) {
135 CheckArg.isNotNull(at, "at");
136 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
137 this.at = at;
138 this.conflictBehavior = conflictBehavior;
139 List<Property> props = new LinkedList<Property>();
140 for (Property property : properties) {
141 if (property != null) props.add(property);
142 }
143 // Add in the location properties ...
144 if (at.hasIdProperties()) {
145 for (Property property : at.getIdProperties()) {
146 if (property != null) props.add(property);
147 }
148 }
149 this.properties = Collections.unmodifiableList(props);
150 }
151
152 /**
153 * Create a request to create a node with the given properties at the supplied location.
154 *
155 * @param at the location of the node to be read
156 * @param properties the properties of the new node, which should not include the location's
157 * {@link Location#getIdProperties() identification properties}
158 * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
159 * location
160 * @throws IllegalArgumentException if the location or the conflict behavior is null
161 */
162 public CreateNodeRequest( Location at,
163 NodeConflictBehavior conflictBehavior,
164 Iterator<Property> properties ) {
165 CheckArg.isNotNull(at, "at");
166 CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
167 this.at = at;
168 this.conflictBehavior = conflictBehavior;
169 List<Property> props = new LinkedList<Property>();
170 while (properties.hasNext()) {
171 Property property = properties.next();
172 if (property != null) props.add(property);
173 }
174 // Add in the location properties ...
175 if (at.hasIdProperties()) {
176 for (Property property : at.getIdProperties()) {
177 if (property != null) props.add(property);
178 }
179 }
180 this.properties = Collections.unmodifiableList(props);
181 }
182
183 /**
184 * Get the location defining the node that is to be created.
185 *
186 * @return the location of the node; never null
187 */
188 public Location at() {
189 return at;
190 }
191
192 /**
193 * {@inheritDoc}
194 *
195 * @see java.lang.Iterable#iterator()
196 */
197 public Iterator<Property> iterator() {
198 return this.properties.iterator();
199 }
200
201 /**
202 * Get the properties for the node. If the node's {@link #at() location} has identification properties, the resulting
203 * properties will include the {@link Location#getIdProperties() identification properties}.
204 *
205 * @return the collection of properties; never null
206 */
207 public Collection<Property> properties() {
208 return properties;
209 }
210
211 /**
212 * Get the expected behavior when copying the branch and the {@link #at() destination} already has a node with the same name.
213 *
214 * @return the behavior specification
215 */
216 public NodeConflictBehavior conflictBehavior() {
217 return conflictBehavior;
218 }
219
220 /**
221 * {@inheritDoc}
222 *
223 * @see org.jboss.dna.graph.requests.Request#isReadOnly()
224 */
225 @Override
226 public boolean isReadOnly() {
227 return false;
228 }
229
230 /**
231 * Sets the actual and complete location of the node being created. This method must be called when processing the request,
232 * and the actual location must have a {@link Location#getPath() path}.
233 *
234 * @param actual the actual location of the node being created, or null if the {@link #at() current location} should be used
235 * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
236 * location} as the {@link #at() current location}, or if the actual location does not have a path.
237 */
238 public void setActualLocationOfNode( Location actual ) {
239 if (!at.isSame(actual, false)) { // not same if actual is null
240 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
241 }
242 assert actual != null;
243 if (!actual.hasPath()) {
244 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
245 }
246 this.actualLocation = actual;
247 }
248
249 /**
250 * Get the actual location of the node that was created.
251 *
252 * @return the actual location, or null if the actual location was not set
253 */
254 public Location getActualLocationOfNode() {
255 return actualLocation;
256 }
257
258 /**
259 * {@inheritDoc}
260 *
261 * @see java.lang.Object#equals(java.lang.Object)
262 */
263 @Override
264 public boolean equals( Object obj ) {
265 if (this.getClass().isInstance(obj)) {
266 CreateNodeRequest that = (CreateNodeRequest)obj;
267 if (!this.at().equals(that.at())) return false;
268 if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
269 if (!this.properties().equals(that.properties())) return false;
270 return true;
271 }
272 return false;
273 }
274
275 /**
276 * {@inheritDoc}
277 *
278 * @see java.lang.Object#toString()
279 */
280 @Override
281 public String toString() {
282 return "create node at " + at() + " with properties " + properties();
283 }
284
285 }