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.Arrays;
025    import java.util.Collection;
026    import java.util.Collections;
027    import java.util.Iterator;
028    import java.util.LinkedList;
029    import java.util.List;
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.properties.Property;
034    
035    /**
036     * Instruction to update the properties on the node at the specified location. Any property with no values will be removed.
037     * 
038     * @author Randall Hauch
039     */
040    public class UpdatePropertiesRequest extends Request implements Iterable<Property> {
041    
042        private static final long serialVersionUID = 1L;
043    
044        private final Location on;
045        private final List<Property> properties;
046        private Location actualLocation;
047    
048        /**
049         * Create a request to update the properties on the node at the supplied location.
050         * 
051         * @param on the location of the node to be read
052         * @param properties the new properties on the node
053         * @throws IllegalArgumentException if the location is null or if there are no properties to update
054         */
055        public UpdatePropertiesRequest( Location on,
056                                        Property... properties ) {
057            CheckArg.isNotNull(on, "on");
058            CheckArg.isNotEmpty(properties, "properties");
059            this.on = on;
060            this.properties = Collections.unmodifiableList(Arrays.asList(properties));
061        }
062    
063        /**
064         * Create a request to update the properties on the node at the supplied location.
065         * 
066         * @param on the location of the node to be read
067         * @param properties the new properties on the node
068         * @throws IllegalArgumentException if the location is null or if there are no properties to update
069         */
070        public UpdatePropertiesRequest( Location on,
071                                        Iterable<Property> properties ) {
072            CheckArg.isNotNull(on, "on");
073            CheckArg.isNotNull(properties, "properties");
074            this.on = on;
075            List<Property> props = new LinkedList<Property>();
076            for (Property property : properties) {
077                if (property != null) props.add(property);
078            }
079            this.properties = Collections.unmodifiableList(props);
080            CheckArg.isNotEmpty(this.properties, "properties");
081        }
082    
083        /**
084         * Create a request to update the properties on the node at the supplied location.
085         * 
086         * @param on the location of the node to be read
087         * @param properties the new properties on the node
088         * @throws IllegalArgumentException if the location is null or if there are no properties to update
089         */
090        public UpdatePropertiesRequest( Location on,
091                                        Iterator<Property> properties ) {
092            CheckArg.isNotNull(on, "on");
093            CheckArg.isNotNull(properties, "properties");
094            this.on = on;
095            List<Property> props = new LinkedList<Property>();
096            while (properties.hasNext()) {
097                Property property = properties.next();
098                if (property != null) props.add(property);
099            }
100            this.properties = Collections.unmodifiableList(props);
101            CheckArg.isNotEmpty(this.properties, "properties");
102        }
103    
104        /**
105         * {@inheritDoc}
106         * 
107         * @see org.jboss.dna.graph.requests.Request#isReadOnly()
108         */
109        @Override
110        public boolean isReadOnly() {
111            return false;
112        }
113    
114        /**
115         * Get the location defining the node that is to be updated.
116         * 
117         * @return the location of the node; never null
118         */
119        public Location on() {
120            return on;
121        }
122    
123        /**
124         * {@inheritDoc}
125         * 
126         * @see java.lang.Iterable#iterator()
127         */
128        public Iterator<Property> iterator() {
129            return this.properties.iterator();
130        }
131    
132        /**
133         * Get the properties for the node.
134         * 
135         * @return the collection of properties; never null and never empty
136         */
137        public Collection<Property> properties() {
138            return properties;
139        }
140    
141        /**
142         * Sets the actual and complete location of the node being updated. This method must be called when processing the request,
143         * and the actual location must have a {@link Location#getPath() path}.
144         * 
145         * @param actual the actual location of the node being updated, or null if the {@link #on() current location} should be used
146         * @throws IllegalArgumentException if the actual location does represent the {@link Location#isSame(Location) same location}
147         *         as the {@link #on() current location}, or if the actual location does not have a path.
148         */
149        public void setActualLocationOfNode( Location actual ) {
150            if (!on.isSame(actual)) { // not same if actual is null
151                throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, on));
152            }
153            assert actual != null;
154            if (!actual.hasPath()) {
155                throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
156            }
157            this.actualLocation = actual;
158        }
159    
160        /**
161         * Get the actual location of the node that was updated.
162         * 
163         * @return the actual location, or null if the actual location was not set
164         */
165        public Location getActualLocationOfNode() {
166            return actualLocation;
167        }
168    
169        /**
170         * {@inheritDoc}
171         * 
172         * @see java.lang.Object#equals(java.lang.Object)
173         */
174        @Override
175        public boolean equals( Object obj ) {
176            if (this.getClass().isInstance(obj)) {
177                UpdatePropertiesRequest that = (UpdatePropertiesRequest)obj;
178                if (!this.on().equals(that.on())) return false;
179                if (!this.properties().equals(that.properties())) return false;
180                return true;
181            }
182            return false;
183        }
184    
185        /**
186         * {@inheritDoc}
187         * 
188         * @see java.lang.Object#toString()
189         */
190        @Override
191        public String toString() {
192            return "update properties on " + on() + " to " + properties();
193        }
194    
195    }