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