1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20
21 package org.apache.axis2.engine;
22
23 import org.apache.axis2.AxisFault;
24 import org.apache.axis2.context.MessageContext;
25 import org.apache.axis2.description.HandlerDescription;
26 import org.apache.axis2.description.Parameter;
27 import org.apache.axis2.description.PhaseRule;
28 import org.apache.axis2.phaseresolver.PhaseException;
29 import org.apache.axis2.util.LoggingControl;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.concurrent.CopyOnWriteArrayList;
36
37 /**
38 * A Phase is an ordered collection of Handlers.
39 */
40 public class Phase implements Handler {
41
42 public static final String ALL_PHASES = "*";
43
44 /**
45 * Field log
46 */
47 private static final Log log = LogFactory.getLog(Phase.class);
48 private static boolean isDebugEnabled = LoggingControl.debugLoggingAllowed && log.isDebugEnabled();
49
50 /**
51 * Field handlers
52 */
53 private List<Handler> handlers;
54
55 /**
56 * A handler has been marked as present in both the first phase and the last phase
57 */
58 private boolean isOneHandler;
59
60 /**
61 * Field phaseName
62 */
63 private String phaseName;
64
65 /**
66 * Field phaseFirstSet
67 */
68 private boolean phaseFirstSet;
69
70 /**
71 * Field phaseLastSet
72 */
73 private boolean phaseLastSet;
74
75 /**
76 * Default constructor
77 */
78 public Phase() {
79 this(null);
80 }
81
82 /**
83 * Create a named Phase
84 *
85 * @param phaseName the name for this Phase
86 */
87 public Phase(String phaseName) {
88 handlers = new CopyOnWriteArrayList<Handler>();
89 this.phaseName = phaseName;
90 }
91
92 /**
93 * Add a handler to the Phase.
94 *
95 * @param handler the Handler to add
96 */
97 public void addHandler(Handler handler) {
98 log.debug("Handler " + handler.getName() + " added to Phase " + phaseName);
99
100 if (phaseLastSet) {
101 // handlers.size() can not be 0 , since when setting phase last it is always > 0
102 if (handlers.size() == 1) {
103 handlers.add(0, handler);
104 } else {
105 handlers.add(handlers.size() - 2, handler);
106 }
107 } else {
108 handlers.add(handler);
109 }
110 }
111
112 /**
113 * Add a HandlerDescription to the Phase
114 *
115 * @param handlerDesc the HandlerDescription to add
116 * @throws PhaseException if there is a problem
117 */
118 public void addHandler(HandlerDescription handlerDesc) throws PhaseException {
119 Iterator<Handler> handlers_itr = getHandlers().iterator();
120
121 while (handlers_itr.hasNext()) {
122 Handler hand = (Handler) handlers_itr.next();
123 HandlerDescription thisDesc = hand.getHandlerDesc();
124 if (handlerDesc.getName().equals(thisDesc.getName())) {
125 return;
126 }
127 }
128
129 if (isOneHandler) {
130 throw new PhaseException("Phase '" + this.getPhaseName()
131 + "' can only have one handler, since there is a "
132 + "handler with both phaseFirst and phaseLast true ");
133 }
134
135 if (handlerDesc.getRules().isPhaseFirst() && handlerDesc.getRules().isPhaseLast()) {
136 if (!handlers.isEmpty()) {
137 throw new PhaseException(this.getPhaseName()
138 + " already contains Handlers, and "
139 + handlerDesc.getName()
140 + " cannot therefore be both phaseFirst and phaseLast.");
141 } else {
142 handlers.add(handlerDesc.getHandler());
143 isOneHandler = true;
144 }
145 } else if (handlerDesc.getRules().isPhaseFirst()) {
146 setPhaseFirst(handlerDesc.getHandler());
147 } else if (handlerDesc.getRules().isPhaseLast()) {
148 setPhaseLast(handlerDesc.getHandler());
149 } else {
150 insertHandler(handlerDesc);
151 }
152 }
153
154 /**
155 * Add a Handler at a particular index within the Phase.
156 *
157 * If we have a Phase with (H1, H2), calling addHandler(H3, 1) will result in (H1, H3, H2)
158 *
159 * @param handler the Handler to add
160 * @param index the position in the Phase at which to place the Handler
161 */
162 public void addHandler(Handler handler, int index) {
163 if (log.isDebugEnabled()) {
164 log.debug("Handler " + handler.getName() + " inserted at position " + index +
165 " of Phase " + phaseName);
166 }
167 handlers.add(index, handler);
168 }
169
170 /**
171 * Confirm that all post-conditions of this Phase are met. After all Handlers in a
172 * Phase are invoke()d, this method will be called. Subclasses should override it in order
173 * to confirm that the purpose of the given Phase has been acheived.
174 *
175 * @param msgContext the active MessageContext
176 * @throws AxisFault if a post-condition has not been met, or other problems occur
177 */
178 public void checkPostConditions(MessageContext msgContext) throws AxisFault {
179 // Default version does nothing
180 }
181
182 /**
183 * Check the preconditions for a Phase. This method will be called when the Phase is
184 * invoked, BEFORE any Handlers are invoked. Subclasses should override it in order
185 * to confirm that necessary preconditions are met before the Phase does its work. They
186 * should throw an appropriate AxisFault if not.
187 *
188 * @param msgContext the active MessageContext
189 * @throws AxisFault if a precondition is not met, or in case of other problem
190 */
191 public void checkPreconditions(MessageContext msgContext) throws AxisFault {
192 // Default version does nothing
193 }
194
195 public void cleanup() {
196 // Default version does nothing
197 }
198
199 public void init(HandlerDescription handlerdesc) {
200 // Default version does nothing
201 }
202
203 private void insertHandler(HandlerDescription handlerDesc) throws PhaseException {
204 Handler handler = handlerDesc.getHandler();
205 PhaseRule rules = handler.getHandlerDesc().getRules();
206 String beforeName = rules.getBefore();
207 String afterName = rules.getAfter();
208
209 // If we don't care where it goes, tack it on at the end
210 if (beforeName == null && afterName == null) {
211 addHandler(handler);
212 return;
213 }
214
215 // Otherwise walk the list and find the right place to put it
216 int beforeIndex = -1, afterIndex = -1;
217
218 for (int i = 0; i < handlers.size(); i++) {
219 Handler tempHandler = (Handler) handlers.get(i);
220
221 if ((beforeName != null) && (beforeIndex == -1)) {
222 if (tempHandler.getName().equals(beforeName)) {
223 // Found the "before" handler
224 beforeIndex = i;
225 }
226 }
227
228 if ((afterName != null) && (afterIndex == -1)) {
229 if (tempHandler.getName().equals(afterName)) {
230 // Found the "after" handler
231 afterIndex = i;
232 }
233 }
234 }
235
236 if ((beforeIndex > -1) && (afterIndex >= beforeIndex)) {
237 throw new PhaseException("Can't insert handler because " + beforeName + " is before " +
238 afterName + " in Phase '" + phaseName + "'");
239 }
240
241 if (phaseFirstSet && beforeIndex == 0) {
242 throw new PhaseException("Can't insert handler before handler '"
243 + beforeName
244 + "', which is marked phaseFirst");
245 }
246
247 if (phaseLastSet && afterIndex == (handlers.size() - 1)) {
248 throw new PhaseException("Can't insert handler after handler '"
249 + afterName
250 + "', which is marked phaseLast");
251 }
252
253 if (beforeIndex > -1) {
254 handlers.add(beforeIndex, handler);
255 } else if (afterIndex > -1){
256 if (phaseLastSet){
257 if (handlers.size() ==1){
258 handlers.add(0,handler);
259 } else {
260 handlers.add(handlers.size() -2,handler);
261 }
262 } else {
263 if (afterIndex == (handlers.size() -1)) {
264 handlers.add(handler);
265 } else {
266 handlers.add(afterIndex +1,handler);
267 }
268 }
269 } else {
270 if (phaseLastSet) {
271 if (handlers.size() ==1){
272 handlers.add(0,handler);
273 } else {
274 handlers.add(handlers.size() -2,handler);
275 }
276 } else {
277 handlers.add(handler);
278 }
279 }
280 }
281
282 /**
283 * Invoke all the handlers in this Phase
284 *
285 * @param msgctx the current MessageContext
286 * @return An InvocationResponse that indicates what
287 * the next step in the message processing should be.
288 * @throws org.apache.axis2.AxisFault
289 */
290 public final InvocationResponse invoke(MessageContext msgctx) throws AxisFault {
291
292 if (isDebugEnabled) {
293 log.debug(msgctx.getLogIDString() + " Checking pre-condition for Phase \"" + phaseName +
294 "\"");
295 }
296
297 InvocationResponse pi = InvocationResponse.CONTINUE;
298
299 int currentIndex = msgctx.getCurrentPhaseIndex();
300
301 if (currentIndex == 0) {
302 checkPreconditions(msgctx);
303 }
304
305 if (isDebugEnabled) {
306 log.debug(msgctx.getLogIDString() + " Invoking phase \"" + phaseName + "\"");
307 }
308
309 int handlersSize = handlers.size();
310
311 while (currentIndex < handlersSize) {
312 Handler handler = (Handler) handlers.get(currentIndex);
313
314 if (isDebugEnabled) {
315 log.debug(msgctx.getLogIDString() + " Invoking Handler '" + handler.getName() +
316 "' in Phase '" + phaseName + "'");
317 }
318 pi = handler.invoke(msgctx);
319
320 if (!pi.equals(InvocationResponse.CONTINUE)) {
321 return pi;
322 }
323
324 currentIndex++;
325 msgctx.setCurrentPhaseIndex(currentIndex);
326 }
327
328 if (isDebugEnabled) {
329 log.debug(msgctx.getLogIDString() + " Checking post-conditions for phase \"" +
330 phaseName + "\"");
331 }
332
333 msgctx.setCurrentPhaseIndex(0);
334 checkPostConditions(msgctx);
335 return pi;
336 }
337
338 public void flowComplete(MessageContext msgContext) {
339 if (isDebugEnabled) {
340 log.debug(msgContext.getLogIDString() + " Invoking flowComplete() in Phase \"" +
341 phaseName + "\"");
342 }
343
344 // This will be non-zero if we failed during execution of one of the
345 // handlers in this phase
346 int currentHandlerIndex = msgContext.getCurrentPhaseIndex();
347 if (currentHandlerIndex == 0) {
348 currentHandlerIndex = handlers.size();
349 } else {
350 /*We need to set it to 0 so that any previous phases will execute all
351 * of their handlers.*/
352 msgContext.setCurrentPhaseIndex(0);
353 }
354
355 for (; currentHandlerIndex > 0; currentHandlerIndex--) {
356 Handler handler = (Handler) handlers.get(currentHandlerIndex - 1);
357
358 if (isDebugEnabled) {
359 log.debug(msgContext.getLogIDString() + " Invoking flowComplete() for Handler '" +
360 handler.getName() + "' in Phase '" + phaseName + "'");
361 }
362
363 handler.flowComplete(msgContext);
364 }
365 }
366
367 public String toString() {
368 return this.getPhaseName();
369 }
370
371 public int getHandlerCount() {
372 return handlers.size();
373 }
374
375 public HandlerDescription getHandlerDesc() {
376 return null;
377 }
378
379 /**
380 * Gets all the handlers in the phase.
381 *
382 * @return Returns an ArrayList of Handlers
383 */
384 public List<Handler> getHandlers() {
385 return handlers;
386 }
387
388 public String getName() {
389 return phaseName;
390 }
391
392 public Parameter getParameter(String name) {
393 return null;
394 }
395
396 /**
397 * @return Returns the name.
398 */
399 public String getPhaseName() {
400 return phaseName;
401 }
402
403 public void setName(String phaseName) {
404 this.phaseName = phaseName;
405 }
406
407 /**
408 * Add a Handler to the Phase in the very first position, and ensure no other Handler
409 * will come before it.
410 *
411 * @param handler the Handler to add
412 * @throws PhaseException if another Handler is already set as phaseFirst
413 */
414 public void setPhaseFirst(Handler handler) throws PhaseException {
415 if (phaseFirstSet) {
416 throw new PhaseException("PhaseFirst has been set already, cannot have two"
417 + " phaseFirst Handlers for Phase '" + this.getPhaseName() + "'");
418 }
419 handlers.add(0, handler);
420 phaseFirstSet = true;
421 }
422
423 /**
424 * Add a Handler to the Phase in the very last position, and ensure no other Handler
425 * will come after it.
426 *
427 * @param handler the Handler to add
428 * @throws PhaseException if another Handler is already set as phaseLast
429 */
430 public void setPhaseLast(Handler handler) throws PhaseException {
431 if (phaseLastSet) {
432 throw new PhaseException("PhaseLast already has been set,"
433 + " cannot have two PhaseLast Handler for same phase "
434 + this.getPhaseName());
435 }
436
437 handlers.add(handler);
438 phaseLastSet = true;
439 }
440
441 /**
442 * Remove a given Handler from a phase using a HandlerDescription
443 *
444 * @param handlerDesc the HandlerDescription to remove
445 */
446 public void removeHandler(HandlerDescription handlerDesc) {
447 if (handlers.remove(handlerDesc.getHandler())) {
448 PhaseRule rule = handlerDesc.getRules();
449 if (rule.isPhaseFirst()) {
450 phaseFirstSet = false;
451 }
452 if (rule.isPhaseLast()) {
453 phaseLastSet = false;
454 }
455 if (rule.isPhaseFirst() && rule.isPhaseLast()) {
456 isOneHandler = false;
457 }
458 log.debug("removed handler " + handlerDesc.getName()
459 + " from the phase " + phaseName);
460 } else {
461 log.debug("unable to remove handler " + handlerDesc.getName()
462 + " from the phase " + phaseName);
463 }
464 }
465
466 }