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.Map;
028    import org.jboss.dna.common.util.CheckArg;
029    import org.jboss.dna.graph.GraphI18n;
030    import org.jboss.dna.graph.Location;
031    import org.jboss.dna.graph.connectors.RepositoryConnection;
032    import org.jboss.dna.graph.properties.Name;
033    import org.jboss.dna.graph.properties.Property;
034    
035    /**
036     * Instruction to read the properties and the number of children of the node at the specifed location.
037     * 
038     * @author Randall Hauch
039     */
040    public class ReadAllPropertiesRequest extends CacheableRequest implements Iterable<Property> {
041    
042        private static final long serialVersionUID = 1L;
043    
044        public static final int UNKNOWN_NUMBER_OF_CHILDREN = -1;
045    
046        private final Location at;
047        private final Map<Name, Property> properties = new HashMap<Name, Property>();
048        private int numberOfChildren = UNKNOWN_NUMBER_OF_CHILDREN;
049        private Location actualLocation;
050    
051        /**
052         * Create a request to read the properties and number of children of a node at the supplied location.
053         * 
054         * @param at the location of the node to be read
055         * @throws IllegalArgumentException if the location is null
056         */
057        public ReadAllPropertiesRequest( Location at ) {
058            CheckArg.isNotNull(at, "at");
059            this.at = at;
060        }
061    
062        /**
063         * {@inheritDoc}
064         * 
065         * @see org.jboss.dna.graph.requests.Request#isReadOnly()
066         */
067        @Override
068        public boolean isReadOnly() {
069            return true;
070        }
071    
072        /**
073         * Get the location defining the node that is to be read.
074         * 
075         * @return the location of the node; never null
076         */
077        public Location at() {
078            return at;
079        }
080    
081        /**
082         * Get the properties that were read from the {@link RepositoryConnection}.
083         * 
084         * @return the properties, as a map of property name to property; never null
085         */
086        public Map<Name, Property> getPropertiesByName() {
087            return properties;
088        }
089    
090        /**
091         * Get the properties that were read from the {@link RepositoryConnection}.
092         * 
093         * @return the collection of properties; never null
094         */
095        public Collection<Property> getProperties() {
096            return properties.values();
097        }
098    
099        /**
100         * {@inheritDoc}
101         * 
102         * @see java.lang.Iterable#iterator()
103         */
104        public Iterator<Property> iterator() {
105            return getProperties().iterator();
106        }
107    
108        /**
109         * Add a property that was read from the {@link RepositoryConnection}
110         * 
111         * @param property the property that was read
112         * @return the previous property that had the same name, or null if there was no previously-recorded property with the same
113         *         name
114         * @throws IllegalArgumentException if the property is null
115         */
116        public Property addProperty( Property property ) {
117            return this.properties.put(property.getName(), property);
118        }
119    
120        /**
121         * Add a property that was read from the {@link RepositoryConnection}
122         * 
123         * @param properties the properties that were read
124         * @throws IllegalArgumentException if the property is null
125         */
126        public void addProperties( Property... properties ) {
127            for (Property property : properties) {
128                this.properties.put(property.getName(), property);
129            }
130        }
131    
132        /**
133         * Get the number of children for this node.
134         * 
135         * @return the number of children, or {@link #UNKNOWN_NUMBER_OF_CHILDREN} if the number of children was not yet read
136         */
137        public int getNumberOfChildren() {
138            return numberOfChildren;
139        }
140    
141        /**
142         * Set the number of children for this node
143         * 
144         * @param numberOfChildren the number of children
145         * @throws IllegalArgumentException if the number of childre is negative
146         */
147        public void setNumberOfChildren( int numberOfChildren ) {
148            CheckArg.isNonNegative(numberOfChildren, "numberOfChildren");
149            this.numberOfChildren = numberOfChildren;
150        }
151    
152        /**
153         * Sets the actual and complete location of the node whose properties have been read. This method must be called when
154         * processing the request, and the actual location must have a {@link Location#getPath() path}.
155         * 
156         * @param actual the actual location of the node being read, or null if the {@link #at() current location} should be used
157         * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
158         *         location} as the {@link #at() current location}, or if the actual location does not have a path.
159         */
160        public void setActualLocationOfNode( Location actual ) {
161            if (!at.isSame(actual)) { // not same if actual is null
162                throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
163            }
164            assert actual != null;
165            if (!actual.hasPath()) {
166                throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
167            }
168            this.actualLocation = actual;
169        }
170    
171        /**
172         * Get the actual location of the node whose properties were read.
173         * 
174         * @return the actual location, or null if the actual location was not set
175         */
176        public Location getActualLocationOfNode() {
177            return actualLocation;
178        }
179    
180        /**
181         * {@inheritDoc}
182         * 
183         * @see java.lang.Object#equals(java.lang.Object)
184         */
185        @Override
186        public boolean equals( Object obj ) {
187            if (this.getClass().isInstance(obj)) {
188                ReadAllPropertiesRequest that = (ReadAllPropertiesRequest)obj;
189                if (!this.at().equals(that.at())) return false;
190                return true;
191            }
192            return false;
193        }
194    
195        /**
196         * {@inheritDoc}
197         * 
198         * @see java.lang.Object#toString()
199         */
200        @Override
201        public String toString() {
202            return "read properties of " + at();
203        }
204    
205    }