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.executor;
023    
024    import org.jboss.dna.graph.ExecutionContext;
025    import org.jboss.dna.graph.commands.CompositeCommand;
026    import org.jboss.dna.graph.commands.CopyBranchCommand;
027    import org.jboss.dna.graph.commands.CopyNodeCommand;
028    import org.jboss.dna.graph.commands.CreateNodeCommand;
029    import org.jboss.dna.graph.commands.DeleteBranchCommand;
030    import org.jboss.dna.graph.commands.GetChildrenCommand;
031    import org.jboss.dna.graph.commands.GetNodeCommand;
032    import org.jboss.dna.graph.commands.GetPropertiesCommand;
033    import org.jboss.dna.graph.commands.GraphCommand;
034    import org.jboss.dna.graph.commands.MoveBranchCommand;
035    import org.jboss.dna.graph.commands.RecordBranchCommand;
036    import org.jboss.dna.graph.commands.SetPropertiesCommand;
037    import org.jboss.dna.graph.connectors.RepositoryConnection;
038    import org.jboss.dna.graph.connectors.RepositorySourceException;
039    import org.jboss.dna.graph.properties.DateTime;
040    
041    /**
042     * Abstract implementation of the {@link CommandExecutor} interface that provides implementations for all methods, making this a
043     * useful base class for all {@link CommandExecutor} implementations. Because all methods are implemented, subclasses only need to
044     * override methods that are appropriate or applicable, and all other commands will be processed correctly (even if new command
045     * interfaces are added in later versions). In some cases, as with {@link CompositeCommand} and {@link GetNodeCommand}, these
046     * implementations attempt to process the command. In other cases (e.g., {@link GetPropertiesCommand}, and
047     * {@link DeleteBranchCommand}), the methods do nothing and should be overridden if the command is to be processed.
048     * <p>
049     * The implementation is also designed to be instantated as needed. This may be once per call to
050     * {@link RepositoryConnection#execute(ExecutionContext, GraphCommand...)}, or may be once per transaction. Either way, this class
051     * is designed to allow subclasses to store additional state that may otherwise be expensive or undesirable to obtain repeatedly.
052     * However, this state should be independent of the commands that are processed, meaning that implementations should generally not
053     * change state as a result of processing specific commands.
054     * </p>
055     * 
056     * @author Randall Hauch
057     */
058    public abstract class AbstractCommandExecutor implements CommandExecutor {
059    
060        private final ExecutionContext context;
061        private final String sourceName;
062        private final DateTime nowInUtc;
063    
064        protected AbstractCommandExecutor( ExecutionContext context,
065                                           String sourceName ) {
066            this(context, sourceName, null);
067        }
068    
069        protected AbstractCommandExecutor( ExecutionContext context,
070                                           String sourceName,
071                                           DateTime now ) {
072            assert context != null;
073            assert sourceName != null && sourceName.trim().length() != 0;
074            this.context = context;
075            this.sourceName = sourceName;
076            this.nowInUtc = now != null ? now.toUtcTimeZone() : context.getValueFactories().getDateFactory().createUtc();
077        }
078    
079        /**
080         * Get the environment in which these commands are being executed.
081         * 
082         * @return the execution context; never null
083         */
084        public ExecutionContext getExecutionContext() {
085            return context;
086        }
087    
088        /**
089         * Get the name of the repository source.
090         * 
091         * @return the source name; never null or empty
092         */
093        public String getSourceName() {
094            return sourceName;
095        }
096    
097        /**
098         * Get the current time associated with this executor. All calls to this method will result in the same time.
099         * 
100         * @return the current time expressed in UTC
101         */
102        public DateTime getCurrentTimeInUtc() {
103            return nowInUtc;
104        }
105    
106        /**
107         * {@inheritDoc}
108         * <p>
109         * This implementation examines the instance to see which {@link GraphCommand command interfaces} are implemented by the
110         * command, and delegates to the appropriate methods.
111         * 
112         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.GraphCommand)
113         */
114        public void execute( GraphCommand command ) throws RepositorySourceException {
115            if (command == null) return;
116            if (command instanceof CompositeCommand) {
117                execute((CompositeCommand)command);
118                // A composite command should only contain other commands and should not do anything on its own
119                return;
120            }
121            // The command could implement multiple "get" behaviors
122            if (command instanceof GetNodeCommand) {
123                execute((GetNodeCommand)command);
124            } else if (command instanceof GetPropertiesCommand) {
125                execute((GetPropertiesCommand)command);
126            } else if (command instanceof GetChildrenCommand) {
127                execute((GetChildrenCommand)command);
128            }
129            // The command could record the branch even if deleting or moving ...
130            if (command instanceof RecordBranchCommand) {
131                execute((RecordBranchCommand)command);
132            }
133            // If the command createa a node, it will have properties to set
134            if (command instanceof CreateNodeCommand) {
135                execute((CreateNodeCommand)command);
136            } else if (command instanceof SetPropertiesCommand) {
137                execute((SetPropertiesCommand)command);
138            }
139            // A copy command will either copy a branch or a node, but not both
140            if (command instanceof CopyBranchCommand) {
141                execute((CopyBranchCommand)command);
142            } else if (command instanceof CopyNodeCommand) {
143                execute((CopyNodeCommand)command);
144            }
145            // The command can either delete or move a branch, but a command can't do both (the move does delete)
146            if (command instanceof DeleteBranchCommand) {
147                execute((DeleteBranchCommand)command);
148            } else if (command instanceof MoveBranchCommand) {
149                execute((MoveBranchCommand)command);
150            }
151        }
152    
153        /**
154         * {@inheritDoc}
155         * 
156         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.CompositeCommand)
157         */
158        public void execute( CompositeCommand command ) throws RepositorySourceException {
159            assert command != null;
160            for (GraphCommand nestedCommand : command) {
161                execute(nestedCommand);
162            }
163        }
164    
165        /**
166         * {@inheritDoc}
167         * <p>
168         * This method implementation simply delegates to both the {@link #execute(GetPropertiesCommand)} and
169         * {@link #execute(GetChildrenCommand)} methods, and should be overridden by subclasses that can process
170         * {@link GetNodeCommand} more efficiently as a single command.
171         * </p>
172         * 
173         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.GetNodeCommand)
174         */
175        public void execute( GetNodeCommand command ) throws RepositorySourceException {
176            execute((GetPropertiesCommand)command);
177            execute((GetChildrenCommand)command);
178        }
179    
180        /**
181         * {@inheritDoc}
182         * 
183         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.GetPropertiesCommand)
184         */
185        public void execute( GetPropertiesCommand command ) throws RepositorySourceException {
186        }
187    
188        /**
189         * {@inheritDoc}
190         * 
191         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.GetChildrenCommand)
192         */
193        public void execute( GetChildrenCommand command ) throws RepositorySourceException {
194        }
195    
196        /**
197         * {@inheritDoc}
198         * 
199         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.CreateNodeCommand)
200         */
201        public void execute( CreateNodeCommand command ) throws RepositorySourceException {
202        }
203    
204        /**
205         * {@inheritDoc}
206         * 
207         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.SetPropertiesCommand)
208         */
209        public void execute( SetPropertiesCommand command ) throws RepositorySourceException {
210        }
211    
212        /**
213         * {@inheritDoc}
214         * 
215         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.CopyNodeCommand)
216         */
217        public void execute( CopyNodeCommand command ) throws RepositorySourceException {
218        }
219    
220        /**
221         * {@inheritDoc}
222         * 
223         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.CopyBranchCommand)
224         */
225        public void execute( CopyBranchCommand command ) throws RepositorySourceException {
226        }
227    
228        /**
229         * {@inheritDoc}
230         * 
231         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.DeleteBranchCommand)
232         */
233        public void execute( DeleteBranchCommand command ) throws RepositorySourceException {
234        }
235    
236        /**
237         * {@inheritDoc}
238         * 
239         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.MoveBranchCommand)
240         */
241        public void execute( MoveBranchCommand command ) throws RepositorySourceException {
242        }
243    
244        /**
245         * {@inheritDoc}
246         * 
247         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.graph.commands.RecordBranchCommand)
248         */
249        public void execute( RecordBranchCommand command ) throws RepositorySourceException {
250        }
251    
252        /**
253         * {@inheritDoc}
254         * 
255         * @see org.jboss.dna.graph.commands.executor.CommandExecutor#close()
256         */
257        public void close() {
258        }
259    
260    }