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 (at 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.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
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.connector.RepositoryConnection;
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 read the properties and children of the node at the specifed location.
43 */
44 public class ReadNodeRequest extends CacheableRequest implements Iterable<Location> {
45
46 private static final long serialVersionUID = 1L;
47
48 private final Location at;
49 private final String workspaceName;
50 private final Map<Name, Property> properties = new HashMap<Name, Property>();
51 private final List<Location> children = new LinkedList<Location>();
52 private Location actualLocation;
53
54 /**
55 * Create a request to read the properties and number of children of a node at the supplied location.
56 *
57 * @param at the location of the node to be read
58 * @param workspaceName the name of the workspace containing the node
59 * @throws IllegalArgumentException if the location or workspace name is null
60 */
61 public ReadNodeRequest( Location at,
62 String workspaceName ) {
63 CheckArg.isNotNull(at, "at");
64 CheckArg.isNotNull(workspaceName, "workspaceName");
65 this.workspaceName = workspaceName;
66 this.at = at;
67 }
68
69 /**
70 * {@inheritDoc}
71 *
72 * @see org.modeshape.graph.request.Request#isReadOnly()
73 */
74 @Override
75 public boolean isReadOnly() {
76 return true;
77 }
78
79 /**
80 * Get the location defining the node that is to be read.
81 *
82 * @return the location of the node; never null
83 */
84 public Location at() {
85 return at;
86 }
87
88 /**
89 * Get the name of the workspace in which the node exists.
90 *
91 * @return the name of the workspace; never null
92 */
93 public String inWorkspace() {
94 return workspaceName;
95 }
96
97 /**
98 * Get the properties that were read from the {@link RepositoryConnection}.
99 *
100 * @return the properties, as a map of property name to property; never null
101 */
102 public Map<Name, Property> getPropertiesByName() {
103 return properties;
104 }
105
106 /**
107 * Get the properties that were read from the {@link RepositoryConnection}.
108 *
109 * @return the collection of properties; never null
110 */
111 public Collection<Property> getProperties() {
112 return properties.values();
113 }
114
115 /**
116 * Add a property that was read from the {@link RepositoryConnection}
117 *
118 * @param property the property that was read
119 * @return the previous property that had the same name, or null if there was no previously-recorded property with the same
120 * name
121 * @throws IllegalArgumentException if the property is null
122 * @throws IllegalStateException if the request is frozen
123 */
124 public Property addProperty( Property property ) {
125 checkNotFrozen();
126 return this.properties.put(property.getName(), property);
127 }
128
129 /**
130 * Add a property that was read from the {@link RepositoryConnection}
131 *
132 * @param properties the properties that were read
133 * @throws IllegalArgumentException if the properties array is null
134 * @throws IllegalStateException if the request is frozen
135 */
136 public void addProperties( Property... properties ) {
137 checkNotFrozen();
138 CheckArg.isNotNull(properties, "properties");
139 for (Property property : properties) {
140 this.properties.put(property.getName(), property);
141 }
142 }
143
144 /**
145 * Add a property that was read from the {@link RepositoryConnection}
146 *
147 * @param properties the properties that were read
148 * @throws IllegalArgumentException if the iterable reference is null
149 * @throws IllegalStateException if the request is frozen
150 */
151 public void addProperties( Iterable<Property> properties ) {
152 checkNotFrozen();
153 CheckArg.isNotNull(properties, "properties");
154 for (Property property : properties) {
155 this.properties.put(property.getName(), property);
156 }
157 }
158
159 /**
160 * Get the children that were read from the {@link RepositoryConnection} after the request was processed. Each child is
161 * represented by a location.
162 *
163 * @return the children that were read; never null
164 */
165 public List<Location> getChildren() {
166 return children;
167 }
168
169 /**
170 * {@inheritDoc}
171 *
172 * @see java.lang.Iterable#iterator()
173 */
174 public Iterator<Location> iterator() {
175 return children.iterator();
176 }
177
178 /**
179 * Add to the list of children that has been read the supplied children with the given path and identification properties. The
180 * children are added in order.
181 *
182 * @param children the locations of the children that were read
183 * @throws IllegalArgumentException if the parameter is null
184 * @throws IllegalStateException if the request is frozen
185 * @see #addChild(Location)
186 * @see #addChild(Path, Property)
187 * @see #addChild(Path, Property, Property...)
188 */
189 public void addChildren( Iterable<Location> children ) {
190 checkNotFrozen();
191 CheckArg.isNotNull(children, "children");
192 for (Location child : children) {
193 if (child != null) this.children.add(child);
194 }
195 }
196
197 /**
198 * Add to the list of children that has been read the child with the given path and identification properties. The children
199 * should be added in order.
200 *
201 * @param child the location of the child that was read
202 * @throws IllegalArgumentException if the location is null
203 * @throws IllegalStateException if the request is frozen
204 * @see #addChild(Path, Property)
205 * @see #addChild(Path, Property, Property...)
206 */
207 public void addChild( Location child ) {
208 checkNotFrozen();
209 CheckArg.isNotNull(child, "child");
210 this.children.add(child);
211 }
212
213 /**
214 * Add to the list of children that has been read the child with the given path and identification properties. The children
215 * should be added in order.
216 *
217 * @param pathToChild the path of the child that was just read
218 * @param firstIdProperty the first identification property of the child that was just read
219 * @param remainingIdProperties the remaining identification properties of the child that was just read
220 * @throws IllegalArgumentException if the path or identification properties are null
221 * @throws IllegalStateException if the request is frozen
222 * @see #addChild(Location)
223 * @see #addChild(Path, Property)
224 */
225 public void addChild( Path pathToChild,
226 Property firstIdProperty,
227 Property... remainingIdProperties ) {
228 checkNotFrozen();
229 Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
230 this.children.add(child);
231 }
232
233 /**
234 * Add to the list of children that has been read the child with the given path and identification property. The children
235 * should be added in order.
236 *
237 * @param pathToChild the path of the child that was just read
238 * @param idProperty the identification property of the child that was just read
239 * @throws IllegalArgumentException if the path or identification properties are null
240 * @throws IllegalStateException if the request is frozen
241 * @see #addChild(Location)
242 * @see #addChild(Path, Property, Property...)
243 */
244 public void addChild( Path pathToChild,
245 Property idProperty ) {
246 checkNotFrozen();
247 Location child = Location.create(pathToChild, idProperty);
248 this.children.add(child);
249 }
250
251 /**
252 * Sets the actual and complete location of the node whose children and properties have been read. This method must be called
253 * when processing the request, and the actual location must have a {@link Location#getPath() path}.
254 *
255 * @param actual the actual location of the node being read, or null if the {@link #at() current location} should be used
256 * @throws IllegalArgumentException if the actual location is null or does not have a path.
257 * @throws IllegalStateException if the request is frozen
258 */
259 public void setActualLocationOfNode( Location actual ) {
260 checkNotFrozen();
261 CheckArg.isNotNull(actual, "actual");
262 if (!actual.hasPath()) {
263 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
264 }
265 this.actualLocation = actual;
266 }
267
268 /**
269 * Get the actual location of the node whose children and properties were read.
270 *
271 * @return the actual location, or null if the actual location was not set
272 */
273 public Location getActualLocationOfNode() {
274 return actualLocation;
275 }
276
277 /**
278 * {@inheritDoc}
279 *
280 * @see org.modeshape.graph.request.Request#cancel()
281 */
282 @Override
283 public void cancel() {
284 super.cancel();
285 this.actualLocation = null;
286 this.children.clear();
287 this.properties.clear();
288 }
289
290 /**
291 * {@inheritDoc}
292 *
293 * @see java.lang.Object#hashCode()
294 */
295 @Override
296 public int hashCode() {
297 return HashCode.compute(at, workspaceName);
298 }
299
300 /**
301 * {@inheritDoc}
302 *
303 * @see java.lang.Object#equals(java.lang.Object)
304 */
305 @Override
306 public boolean equals( Object obj ) {
307 if (obj == this) return true;
308 if (this.getClass().isInstance(obj)) {
309 ReadNodeRequest that = (ReadNodeRequest)obj;
310 if (!this.at().isSame(that.at())) return false;
311 if (!this.inWorkspace().equals(that.inWorkspace())) return false;
312 return true;
313 }
314 return false;
315 }
316
317 /**
318 * {@inheritDoc}
319 *
320 * @see java.lang.Object#toString()
321 */
322 @Override
323 public String toString() {
324 return "read node at " + at() + " in the \"" + workspaceName + "\" workspace";
325 }
326
327 @Override
328 public RequestType getType() {
329 return RequestType.READ_NODE;
330 }
331 }