001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.chain.impl; 018 019 020 import java.util.Collection; 021 import java.util.Iterator; 022 import org.apache.commons.chain.Chain; 023 import org.apache.commons.chain.Command; 024 import org.apache.commons.chain.Context; 025 import org.apache.commons.chain.Filter; 026 027 028 /** 029 * <p>Convenience base class for {@link Chain} implementations.</p> 030 * 031 * @author Craig R. McClanahan 032 * @version $Revision: 480477 $ $Date: 2006-11-29 08:34:52 +0000 (Wed, 29 Nov 2006) $ 033 */ 034 035 public class ChainBase implements Chain { 036 037 038 // ----------------------------------------------------------- Constructors 039 040 041 /** 042 * <p>Construct a {@link Chain} with no configured {@link Command}s.</p> 043 */ 044 public ChainBase() { 045 046 } 047 048 049 /** 050 * <p>Construct a {@link Chain} configured with the specified 051 * {@link Command}.</p> 052 * 053 * @param command The {@link Command} to be configured 054 * 055 * @exception IllegalArgumentException if <code>command</code> 056 * is <code>null</code> 057 */ 058 public ChainBase(Command command) { 059 060 addCommand(command); 061 062 } 063 064 065 /** 066 * <p>Construct a {@link Chain} configured with the specified 067 * {@link Command}s.</p> 068 * 069 * @param commands The {@link Command}s to be configured 070 * 071 * @exception IllegalArgumentException if <code>commands</code>, 072 * or one of the individual {@link Command} elements, 073 * is <code>null</code> 074 */ 075 public ChainBase(Command[] commands) { 076 077 if (commands == null) { 078 throw new IllegalArgumentException(); 079 } 080 for (int i = 0; i < commands.length; i++) { 081 addCommand(commands[i]); 082 } 083 084 } 085 086 087 /** 088 * <p>Construct a {@link Chain} configured with the specified 089 * {@link Command}s.</p> 090 * 091 * @param commands The {@link Command}s to be configured 092 * 093 * @exception IllegalArgumentException if <code>commands</code>, 094 * or one of the individual {@link Command} elements, 095 * is <code>null</code> 096 */ 097 public ChainBase(Collection commands) { 098 099 if (commands == null) { 100 throw new IllegalArgumentException(); 101 } 102 Iterator elements = commands.iterator(); 103 while (elements.hasNext()) { 104 addCommand((Command) elements.next()); 105 } 106 107 } 108 109 110 // ----------------------------------------------------- Instance Variables 111 112 113 /** 114 * <p>The list of {@link Command}s configured for this {@link Chain}, in 115 * the order in which they may delegate processing to the remainder of 116 * the {@link Chain}.</p> 117 */ 118 protected Command[] commands = new Command[0]; 119 120 121 /** 122 * <p>Flag indicating whether the configuration of our commands list 123 * has been frozen by a call to the <code>execute()</code> method.</p> 124 */ 125 protected boolean frozen = false; 126 127 128 // ---------------------------------------------------------- Chain Methods 129 130 131 /** 132 * See the {@link Chain} JavaDoc. 133 * 134 * @param command The {@link Command} to be added 135 * 136 * @exception IllegalArgumentException if <code>command</code> 137 * is <code>null</code> 138 * @exception IllegalStateException if no further configuration is allowed 139 */ 140 public void addCommand(Command command) { 141 142 if (command == null) { 143 throw new IllegalArgumentException(); 144 } 145 if (frozen) { 146 throw new IllegalStateException(); 147 } 148 Command[] results = new Command[commands.length + 1]; 149 System.arraycopy(commands, 0, results, 0, commands.length); 150 results[commands.length] = command; 151 commands = results; 152 153 } 154 155 156 /** 157 * See the {@link Chain} JavaDoc. 158 * 159 * @param context The {@link Context} to be processed by this 160 * {@link Chain} 161 * 162 * @throws Exception if thrown by one of the {@link Command}s 163 * in this {@link Chain} but not handled by a <code>postprocess()</code> 164 * method of a {@link Filter} 165 * @throws IllegalArgumentException if <code>context</code> 166 * is <code>null</code> 167 * 168 * @return <code>true</code> if the processing of this {@link Context} 169 * has been completed, or <code>false</code> if the processing 170 * of this {@link Context} should be delegated to a subsequent 171 * {@link Command} in an enclosing {@link Chain} 172 */ 173 public boolean execute(Context context) throws Exception { 174 175 // Verify our parameters 176 if (context == null) { 177 throw new IllegalArgumentException(); 178 } 179 180 // Freeze the configuration of the command list 181 frozen = true; 182 183 // Execute the commands in this list until one returns true 184 // or throws an exception 185 boolean saveResult = false; 186 Exception saveException = null; 187 int i = 0; 188 int n = commands.length; 189 for (i = 0; i < n; i++) { 190 try { 191 saveResult = commands[i].execute(context); 192 if (saveResult) { 193 break; 194 } 195 } catch (Exception e) { 196 saveException = e; 197 break; 198 } 199 } 200 201 // Call postprocess methods on Filters in reverse order 202 if (i >= n) { // Fell off the end of the chain 203 i--; 204 } 205 boolean handled = false; 206 boolean result = false; 207 for (int j = i; j >= 0; j--) { 208 if (commands[j] instanceof Filter) { 209 try { 210 result = 211 ((Filter) commands[j]).postprocess(context, 212 saveException); 213 if (result) { 214 handled = true; 215 } 216 } catch (Exception e) { 217 // Silently ignore 218 } 219 } 220 } 221 222 // Return the exception or result state from the last execute() 223 if ((saveException != null) && !handled) { 224 throw saveException; 225 } else { 226 return (saveResult); 227 } 228 229 } 230 231 232 // -------------------------------------------------------- Package Methods 233 234 235 /** 236 * <p>Return an array of the configured {@link Command}s for this 237 * {@link Chain}. This method is package private, and is used only 238 * for the unit tests.</p> 239 */ 240 Command[] getCommands() { 241 242 return (commands); 243 244 } 245 246 247 }