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.commands.basic;
023    
024    import java.util.ArrayList;
025    import java.util.Collections;
026    import java.util.Iterator;
027    import java.util.LinkedList;
028    import java.util.List;
029    import net.jcip.annotations.NotThreadSafe;
030    import org.jboss.dna.graph.commands.CreateNodeCommand;
031    import org.jboss.dna.graph.commands.NodeConflictBehavior;
032    import org.jboss.dna.graph.commands.RecordBranchCommand;
033    import org.jboss.dna.graph.properties.Path;
034    import org.jboss.dna.graph.properties.Property;
035    
036    /**
037     * @author Randall Hauch
038     */
039    @NotThreadSafe
040    public class BasicRecordBranchCommand extends BasicGraphCommand implements RecordBranchCommand {
041    
042        private final int maxDepth;
043        private final Path topOfBranch;
044        private final List<CreateNodeCommand> commands;
045        private final NodeConflictBehavior conflictBehavior;
046    
047        /**
048         * @param topOfBranch the top node in the branch that is to be recorded; may not be null
049         * @param conflictBehavior the desired behavior when a node exists at the <code>path</code>; may not be null
050         */
051        public BasicRecordBranchCommand( Path topOfBranch,
052                                         NodeConflictBehavior conflictBehavior ) {
053            this(topOfBranch, conflictBehavior, null, Integer.MAX_VALUE);
054        }
055    
056        /**
057         * @param topOfBranch the top node in the branch that is to be recorded; may not be null
058         * @param conflictBehavior the desired behavior when a node exists at the <code>path</code>; may not be null
059         * @param commands the list into which the {@link CreateNodeCommand}s should be place; may be null
060         */
061        public BasicRecordBranchCommand( Path topOfBranch,
062                                         NodeConflictBehavior conflictBehavior,
063                                         List<CreateNodeCommand> commands ) {
064            this(topOfBranch, conflictBehavior, commands, Integer.MAX_VALUE);
065        }
066    
067        /**
068         * @param topOfBranch the top node in the branch that is to be recorded; may not be null
069         * @param conflictBehavior the desired behavior when a node exists at the <code>path</code>; may not be null
070         * @param commands the list into which the {@link CreateNodeCommand}s should be place; may be null
071         * @param maxDepthOfBranch the maximum depth of the branch that should be recorded, or {@link Integer#MAX_VALUE} if there is
072         *        no limit
073         */
074        public BasicRecordBranchCommand( Path topOfBranch,
075                                         NodeConflictBehavior conflictBehavior,
076                                         List<CreateNodeCommand> commands,
077                                         int maxDepthOfBranch ) {
078            super();
079            assert topOfBranch != null;
080            assert conflictBehavior != null;
081            assert maxDepthOfBranch > 0;
082            this.topOfBranch = topOfBranch;
083            this.maxDepth = maxDepthOfBranch;
084            this.conflictBehavior = conflictBehavior;
085            this.commands = commands != null ? commands : new LinkedList<CreateNodeCommand>();
086        }
087    
088        /**
089         * {@inheritDoc}
090         */
091        public Path getPath() {
092            return topOfBranch;
093        }
094    
095        /**
096         * {@inheritDoc}
097         */
098        public boolean record( Path path,
099                               Iterable<Property> properties ) {
100            // Determine the relative path for this node ...
101            if (path.isAbsolute()) {
102                if (!path.isDecendantOf(this.topOfBranch)) return false;
103                path = path.relativeTo(this.topOfBranch);
104            }
105            int numberOfLevelsLeft = maxDepth - path.size();
106            if (numberOfLevelsLeft < 0) return false;
107            List<Property> propertyList = Collections.emptyList();
108            if (properties != null) {
109                if (properties instanceof List) {
110                    propertyList = (List<Property>)properties;
111                } else {
112                    propertyList = new LinkedList<Property>();
113                    for (Property property : properties) {
114                        propertyList.add(property);
115                    }
116                }
117            }
118            record(new BasicCreateNodeCommand(path, propertyList, this.conflictBehavior));
119            return numberOfLevelsLeft > 0;
120        }
121    
122        /**
123         * {@inheritDoc}
124         */
125        public boolean record( Path path,
126                               Iterator<Property> properties ) {
127            int numberOfLevelsLeft = maxDepth - path.size();
128            if (numberOfLevelsLeft < 0) return false;
129            List<Property> propertyList = Collections.emptyList();
130            if (properties != null) {
131                propertyList = new LinkedList<Property>();
132                while (properties.hasNext()) {
133                    Property property = properties.next();
134                    propertyList.add(property);
135                }
136            }
137            record(new BasicCreateNodeCommand(path, propertyList, this.conflictBehavior));
138            return numberOfLevelsLeft > 0;
139        }
140    
141        /**
142         * {@inheritDoc}
143         */
144        public boolean record( Path path,
145                               Property... properties ) {
146            int numberOfLevelsLeft = maxDepth - path.size();
147            if (numberOfLevelsLeft < 0) return false;
148            List<Property> propertyList = Collections.emptyList();
149            if (properties != null) {
150                propertyList = new ArrayList<Property>(properties.length);
151                for (Property property : properties) {
152                    propertyList.add(property);
153                }
154            }
155            record(new BasicCreateNodeCommand(path, propertyList, this.conflictBehavior));
156            return numberOfLevelsLeft > 0;
157        }
158    
159        /**
160         * @return maxDepth
161         */
162        public int getMaxDepth() {
163            return this.maxDepth;
164        }
165    
166        /**
167         * Method that is called whenver a node is recorded by the recipient of this command. This implementation simply records it,
168         * but subclasses can override this method to respond immediately.
169         * 
170         * @param command the command containing the node information; never null and always above the {@link #getMaxDepth() maximum
171         *        depth}.
172         */
173        protected void record( CreateNodeCommand command ) {
174            commands.add(command);
175        }
176    
177        /**
178         * Return the commands to create the nodes, in the order they were recorded.
179         * 
180         * @return the mutable list of {@link CreateNodeCommand create node commands}; never null
181         */
182        public List<CreateNodeCommand> getCreateNodeCommands() {
183            return this.commands;
184        }
185    
186        /**
187         * {@inheritDoc}
188         * 
189         * @see java.lang.Object#toString()
190         */
191        @Override
192        public String toString() {
193            return this.getClass().getSimpleName() + " at " + this.getPath();
194        }
195    
196    }