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 }