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