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 (at 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.Iterator;
027    import java.util.LinkedList;
028    import java.util.List;
029    import org.jboss.dna.common.util.CheckArg;
030    import org.jboss.dna.common.util.HashCode;
031    import org.jboss.dna.graph.GraphI18n;
032    import org.jboss.dna.graph.Location;
033    import org.jboss.dna.graph.connector.RepositoryConnection;
034    import org.jboss.dna.graph.property.Path;
035    import org.jboss.dna.graph.property.Property;
036    
037    /**
038     * Instruction to read all of the children of a node at a specific location.
039     * 
040     * @author Randall Hauch
041     */
042    public class ReadAllChildrenRequest extends CacheableRequest implements Iterable<Location> {
043    
044        private static final long serialVersionUID = 1L;
045    
046        private final Location of;
047        private final String workspaceName;
048        private final List<Location> children = new LinkedList<Location>();
049        private Location actualOf;
050    
051        /**
052         * Create a request to read the children of a node at the supplied location in the designated workspace.
053         * 
054         * @param of the location of the node whose children are to be read
055         * @param workspaceName the name of the workspace
056         * @throws IllegalArgumentException if the location or workspace name is null
057         */
058        public ReadAllChildrenRequest( Location of,
059                                       String workspaceName ) {
060            CheckArg.isNotNull(of, "of");
061            CheckArg.isNotNull(workspaceName, "workspaceName");
062            this.of = of;
063            this.workspaceName = workspaceName;
064        }
065    
066        /**
067         * {@inheritDoc}
068         * 
069         * @see org.jboss.dna.graph.request.Request#isReadOnly()
070         */
071        @Override
072        public boolean isReadOnly() {
073            return true;
074        }
075    
076        /**
077         * Get the location defining the node whose children are to be read.
078         * 
079         * @return the location of the parent node; never null
080         */
081        public Location of() {
082            return of;
083        }
084    
085        /**
086         * Get the name of the workspace in which the parent and children exist.
087         * 
088         * @return the name of the workspace; never null
089         */
090        public String inWorkspace() {
091            return workspaceName;
092        }
093    
094        /**
095         * Get the children that were read from the {@link RepositoryConnection} after the request was processed. Each child is
096         * represented by a location.
097         * 
098         * @return the children that were read; never null
099         */
100        public List<Location> getChildren() {
101            return children;
102        }
103    
104        /**
105         * {@inheritDoc}
106         * 
107         * @see java.lang.Iterable#iterator()
108         */
109        public Iterator<Location> iterator() {
110            return children.iterator();
111        }
112    
113        /**
114         * Add to the list of children that has been read the supplied children with the given path and identification properties. The
115         * children are added in order.
116         * 
117         * @param children the locations of the children that were read
118         * @throws IllegalArgumentException if the parameter is null
119         * @throws IllegalStateException if the request is frozen
120         * @see #addChild(Location)
121         * @see #addChild(Path, Property)
122         * @see #addChild(Path, Property, Property...)
123         */
124        public void addChildren( Iterable<Location> children ) {
125            checkNotFrozen();
126            CheckArg.isNotNull(children, "children");
127            for (Location child : children) {
128                if (child != null) this.children.add(child);
129            }
130        }
131    
132        /**
133         * Add to the list of children that has been read the child with the given path and identification properties. The children
134         * should be added in order.
135         * 
136         * @param child the location of the child that was read
137         * @throws IllegalArgumentException if the location is null
138         * @throws IllegalStateException if the request is frozen
139         * @see #addChild(Path, Property)
140         * @see #addChild(Path, Property, Property...)
141         */
142        public void addChild( Location child ) {
143            checkNotFrozen();
144            CheckArg.isNotNull(child, "child");
145            this.children.add(child);
146        }
147    
148        /**
149         * Add to the list of children that has been read the child with the given path and identification properties. The children
150         * should be added in order.
151         * 
152         * @param pathToChild the path of the child that was just read
153         * @param firstIdProperty the first identification property of the child that was just read
154         * @param remainingIdProperties the remaining identification properties of the child that was just read
155         * @throws IllegalArgumentException if the path or identification properties are null
156         * @throws IllegalStateException if the request is frozen
157         * @see #addChild(Location)
158         * @see #addChild(Path, Property)
159         */
160        public void addChild( Path pathToChild,
161                              Property firstIdProperty,
162                              Property... remainingIdProperties ) {
163            checkNotFrozen();
164            Location child = Location.create(pathToChild, firstIdProperty, remainingIdProperties);
165            this.children.add(child);
166        }
167    
168        /**
169         * Add to the list of children that has been read the child with the given path and identification property. The children
170         * should be added in order.
171         * 
172         * @param pathToChild the path of the child that was just read
173         * @param idProperty the identification property of the child that was just read
174         * @throws IllegalArgumentException if the path or identification properties are null
175         * @throws IllegalStateException if the request is frozen
176         * @see #addChild(Location)
177         * @see #addChild(Path, Property, Property...)
178         */
179        public void addChild( Path pathToChild,
180                              Property idProperty ) {
181            checkNotFrozen();
182            Location child = Location.create(pathToChild, idProperty);
183            this.children.add(child);
184        }
185    
186        /**
187         * Sets the actual and complete location of the node whose children have been read. This method must be called when processing
188         * the request, and the actual location must have a {@link Location#getPath() path}.
189         * 
190         * @param actualLocation the actual location of the node being read, or null if the {@link #of() current location} should be
191         *        used
192         * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
193         *         location} as the {@link #of() current location}; if the actual location does not have a path; or if the actual
194         *         workspace name is null
195         * @throws IllegalStateException if the request is frozen
196         */
197        public void setActualLocationOfNode( Location actualLocation ) {
198            checkNotFrozen();
199            if (!this.of.isSame(actualLocation)) { // not same if actualLocation is null
200                throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actualLocation, of));
201            }
202            assert actualLocation != null;
203            if (!actualLocation.hasPath()) {
204                throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actualLocation));
205            }
206            this.actualOf = actualLocation;
207        }
208    
209        /**
210         * Get the actual location of the node whose children were read.
211         * 
212         * @return the actual location, or null if the actual location was not set
213         */
214        public Location getActualLocationOfNode() {
215            return actualOf;
216        }
217    
218        /**
219         * {@inheritDoc}
220         * 
221         * @see org.jboss.dna.graph.request.Request#cancel()
222         */
223        @Override
224        public void cancel() {
225            super.cancel();
226            this.actualOf = null;
227        }
228    
229        /**
230         * {@inheritDoc}
231         * 
232         * @see java.lang.Object#hashCode()
233         */
234        @Override
235        public int hashCode() {
236            return HashCode.compute(of, workspaceName);
237        }
238    
239        /**
240         * {@inheritDoc}
241         * 
242         * @see java.lang.Object#equals(java.lang.Object)
243         */
244        @Override
245        public boolean equals( Object obj ) {
246            if (obj == this) return true;
247            if (this.getClass().isInstance(obj)) {
248                ReadAllChildrenRequest that = (ReadAllChildrenRequest)obj;
249                if (!this.of().equals(that.of())) return false;
250                if (!this.inWorkspace().equals(that.inWorkspace())) return false;
251                return true;
252            }
253            return false;
254        }
255    
256        /**
257         * {@inheritDoc}
258         * 
259         * @see java.lang.Object#toString()
260         */
261        @Override
262        public String toString() {
263            String workspaceName = this.workspaceName != null ? "\"" + this.workspaceName + "\"" : "default";
264            return "read children of " + of() + " in the \"" + workspaceName + "\" workspace";
265        }
266    }