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 package org.apache.cxf.phase;
21
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.ListIterator;
26 import java.util.Map;
27 import java.util.NoSuchElementException;
28 import java.util.Set;
29 import java.util.SortedSet;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32
33 import org.apache.cxf.common.logging.LogUtils;
34 import org.apache.cxf.interceptor.Fault;
35 import org.apache.cxf.interceptor.Interceptor;
36 import org.apache.cxf.interceptor.InterceptorChain;
37 import org.apache.cxf.message.FaultMode;
38 import org.apache.cxf.message.Message;
39 import org.apache.cxf.transport.MessageObserver;
40
41 /**
42 * A PhaseInterceptorChain orders Interceptors according to the phase they
43 * participate in and also according to the before & after properties on an
44 * Interceptor.
45 * <p>
46 * A List of phases is supplied to the PhaseInterceptorChain in the constructor.
47 * This class is typically instantiated from the PhaseChainCache class in this
48 * package. Interceptors that are added to the chain are ordered by phase.
49 * Within a phase, interceptors can order themselves. Each PhaseInterceptor
50 * has an ID. PhaseInterceptors can supply a Collection of IDs which they
51 * should run before or after, supplying fine grained ordering.
52 * <p>
53 *
54 */
55 public class PhaseInterceptorChain implements InterceptorChain {
56
57 private static final Logger LOG = LogUtils.getL7dLogger(PhaseInterceptorChain.class);
58
59
60 private final Map<String, Integer> nameMap;
61 private final Phase phases[];
62
63 // heads[phase] refers to the first interceptor of the given phase
64 private InterceptorHolder heads[];
65 // tails[phase] refers to the last interceptor of the given phase
66 private InterceptorHolder tails[];
67 // hasAfters[phase] indicates that the given phase has already inserted
68 // interceptors that may need to be placed after future to-be-inserted
69 // interceptors. This flag is used to activate ordering of interceptors
70 // when new ones are added to the list for this phase.
71 // Note no hasBefores[] is needed because implementation adds subsequent
72 // interceptors to the end of the list by default.
73 private boolean hasAfters[];
74
75
76 private State state;
77 private Message pausedMessage;
78 private MessageObserver faultObserver;
79 private PhaseInterceptorIterator iterator;
80
81 // currently one chain for one request/response, use below as signal
82 // to avoid duplicate fault processing on nested calling of
83 // doIntercept(), which will throw same fault multi-times
84 private boolean faultOccurred;
85
86
87 private PhaseInterceptorChain(PhaseInterceptorChain src) {
88 //only used for clone
89 state = State.EXECUTING;
90
91 //immutable, just repoint
92 nameMap = src.nameMap;
93 phases = src.phases;
94
95 int length = phases.length;
96 hasAfters = new boolean[length];
97 System.arraycopy(src.hasAfters, 0, hasAfters, 0, length);
98
99 heads = new InterceptorHolder[length];
100 tails = new InterceptorHolder[length];
101
102 InterceptorHolder last = null;
103 for (int x = 0; x < length; x++) {
104 InterceptorHolder ih = src.heads[x];
105 while (ih != null
106 && ih.phaseIdx == x) {
107 InterceptorHolder ih2 = new InterceptorHolder(ih);
108 ih2.prev = last;
109 if (last != null) {
110 last.next = ih2;
111 }
112 if (heads[x] == null) {
113 heads[x] = ih2;
114 }
115 tails[x] = ih2;
116 last = ih2;
117 ih = ih.next;
118 }
119 }
120 }
121
122 public PhaseInterceptorChain(SortedSet<Phase> ps) {
123 state = State.EXECUTING;
124
125 int numPhases = ps.size();
126 phases = new Phase[numPhases];
127 nameMap = new HashMap<String, Integer>();
128
129 heads = new InterceptorHolder[numPhases];
130 tails = new InterceptorHolder[numPhases];
131 hasAfters = new boolean[numPhases];
132
133 int idx = 0;
134 for (Phase phase : ps) {
135 phases[idx] = phase;
136 nameMap.put(phase.getName(), idx);
137 ++idx;
138 }
139 }
140
141 public PhaseInterceptorChain cloneChain() {
142 return new PhaseInterceptorChain(this);
143 }
144
145 private void updateIterator() {
146 if (iterator == null) {
147 iterator = new PhaseInterceptorIterator(heads);
148 outputChainToLog(false);
149 //System.out.println(toString());
150 }
151 }
152
153 public void add(Collection<Interceptor> newhandlers) {
154 add(newhandlers, false);
155 }
156
157 public void add(Collection<Interceptor> newhandlers, boolean force) {
158 if (newhandlers == null) {
159 return;
160 }
161
162 for (Interceptor handler : newhandlers) {
163 add(handler, force);
164 }
165 }
166
167 public void add(Interceptor i) {
168 add(i, false);
169 }
170
171 public void add(Interceptor i, boolean force) {
172 PhaseInterceptor pi = (PhaseInterceptor)i;
173
174 String phaseName = pi.getPhase();
175 Integer phase = nameMap.get(phaseName);
176
177 if (phase == null) {
178 LOG.fine("Skipping interceptor " + i.getClass().getName()
179 + ((phaseName == null) ? ": Phase declaration is missing."
180 : ": Phase " + phaseName + " specified does not exist."));
181 } else {
182 if (LOG.isLoggable(Level.FINE)) {
183 LOG.fine("Adding interceptor " + i + " to phase " + phaseName);
184 }
185
186 insertInterceptor(phase, pi, force);
187 }
188 }
189
190
191 public synchronized void pause() {
192 state = State.PAUSED;
193 }
194
195 public synchronized void resume() {
196 if (state == State.PAUSED) {
197 state = State.EXECUTING;
198 doIntercept(pausedMessage);
199 }
200 }
201
202 /**
203 * Intercept a message, invoking each phase's handlers in turn.
204 *
205 * @param message the message
206 * @throws Exception
207 */
208 @SuppressWarnings("unchecked")
209 public synchronized boolean doIntercept(Message message) {
210 updateIterator();
211
212 pausedMessage = message;
213 while (state == State.EXECUTING && iterator.hasNext()) {
214 try {
215 Interceptor currentInterceptor = iterator.next();
216
217 if (LOG.isLoggable(Level.FINE)) {
218 LOG.fine("Invoking handleMessage on interceptor " + currentInterceptor);
219 }
220 //System.out.println("-----------" + currentInterceptor);
221 currentInterceptor.handleMessage(message);
222
223 } catch (RuntimeException ex) {
224 if (!faultOccurred) {
225
226 faultOccurred = true;
227
228 FaultMode mode = message.get(FaultMode.class);
229 if (mode == FaultMode.CHECKED_APPLICATION_FAULT) {
230 if (LOG.isLoggable(Level.FINE)) {
231 LogUtils.log(LOG, Level.FINE,
232 "Application has thrown exception, unwinding now", ex);
233 } else if (LOG.isLoggable(Level.INFO)) {
234 Throwable t = ex;
235 if (ex instanceof Fault
236 && ex.getCause() != null) {
237 t = ex.getCause();
238 }
239
240 LogUtils.log(LOG, Level.INFO,
241 "Application has thrown exception, unwinding now: "
242 + t.getClass().getName()
243 + ": " + ex.getMessage());
244 }
245 } else if (LOG.isLoggable(Level.INFO)) {
246 if (mode == FaultMode.UNCHECKED_APPLICATION_FAULT) {
247 LogUtils.log(LOG, Level.INFO,
248 "Application has thrown exception, unwinding now", ex);
249 } else {
250 LogUtils.log(LOG, Level.INFO,
251 "Interceptor has thrown exception, unwinding now", ex);
252 }
253 }
254
255 message.setContent(Exception.class, ex);
256 if (message.getExchange() != null) {
257 message.getExchange().put(Exception.class, ex);
258 }
259 unwind(message);
260
261 if (faultObserver != null) {
262 faultObserver.onMessage(message);
263 }
264 }
265 state = State.ABORTED;
266 }
267 }
268 if (state == State.EXECUTING) {
269 state = State.COMPLETE;
270 }
271 return state == State.COMPLETE;
272 }
273
274 /**
275 * Intercept a message, invoking each phase's handlers in turn,
276 * starting after the specified interceptor.
277 *
278 * @param message the message
279 * @param startingAfterInterceptorID the id of the interceptor
280 * @throws Exception
281 */
282 @SuppressWarnings("unchecked")
283 public synchronized boolean doInterceptStartingAfter(Message message,
284 String startingAfterInterceptorID) {
285 updateIterator();
286 while (state == State.EXECUTING && iterator.hasNext()) {
287 PhaseInterceptor currentInterceptor = (PhaseInterceptor)iterator.next();
288 if (currentInterceptor.getId().equals(startingAfterInterceptorID)) {
289 break;
290 }
291 }
292 return doIntercept(message);
293 }
294
295 /**
296 * Intercept a message, invoking each phase's handlers in turn,
297 * starting at the specified interceptor.
298 *
299 * @param message the message
300 * @param startingAtInterceptorID the id of the interceptor
301 * @throws Exception
302 */
303 @SuppressWarnings("unchecked")
304 public synchronized boolean doInterceptStartingAt(Message message,
305 String startingAtInterceptorID) {
306 updateIterator();
307 while (state == State.EXECUTING && iterator.hasNext()) {
308 PhaseInterceptor currentInterceptor = (PhaseInterceptor)iterator.next();
309 if (currentInterceptor.getId().equals(startingAtInterceptorID)) {
310 iterator.previous();
311 break;
312 }
313 }
314 return doIntercept(message);
315 }
316
317 public synchronized void reset() {
318 updateIterator();
319 if (state == State.COMPLETE) {
320 state = State.EXECUTING;
321 iterator.reset();
322 } else {
323 iterator.reset();
324 }
325 }
326
327 @SuppressWarnings("unchecked")
328 private void unwind(Message message) {
329 while (iterator.hasPrevious()) {
330 Interceptor currentInterceptor = iterator.previous();
331 if (LOG.isLoggable(Level.FINE)) {
332 LOG.fine("Invoking handleFault on interceptor " + currentInterceptor);
333 }
334 currentInterceptor.handleFault(message);
335 }
336 }
337
338 public void remove(Interceptor i) {
339 PhaseInterceptorIterator it = new PhaseInterceptorIterator(heads);
340 while (it.hasNext()) {
341 InterceptorHolder holder = it.nextInterceptorHolder();
342 if (holder.interceptor == i) {
343 remove(holder);
344 return;
345 }
346 }
347 }
348
349 public synchronized void abort() {
350 this.state = InterceptorChain.State.ABORTED;
351 }
352
353 public Iterator<Interceptor<? extends Message>> iterator() {
354 return getIterator();
355 }
356 public ListIterator<Interceptor<? extends Message>> getIterator() {
357 return new PhaseInterceptorIterator(heads);
358 }
359
360 private void remove(InterceptorHolder i) {
361 if (i.prev != null) {
362 i.prev.next = i.next;
363 }
364 if (i.next != null) {
365 i.next.prev = i.prev;
366 }
367 int ph = i.phaseIdx;
368 if (heads[ph] == i) {
369 if (i.next != null
370 && i.next.phaseIdx == ph) {
371 heads[ph] = i.next;
372 } else {
373 heads[ph] = null;
374 tails[ph] = null;
375 }
376 }
377 if (tails[ph] == i) {
378 if (i.prev != null
379 && i.prev.phaseIdx == ph) {
380 tails[ph] = i.prev;
381 } else {
382 heads[ph] = null;
383 tails[ph] = null;
384 }
385 }
386 }
387
388 private void insertInterceptor(int phase, PhaseInterceptor interc, boolean force) {
389 InterceptorHolder ih = new InterceptorHolder(interc, phase);
390 if (heads[phase] == null) {
391 // no interceptors yet in this phase
392 heads[phase] = ih;
393 tails[phase] = ih;
394 hasAfters[phase] = !interc.getAfter().isEmpty();
395
396 int idx = phase - 1;
397 while (idx >= 0) {
398 if (tails[idx] != null) {
399 break;
400 }
401 --idx;
402 }
403 if (idx >= 0) {
404 //found something before us, in an earlier phase
405 ih.prev = tails[idx];
406 ih.next = tails[idx].next;
407 if (ih.next != null) {
408 ih.next.prev = ih;
409 }
410 tails[idx].next = ih;
411 } else {
412 //did not find something before us, try after
413 idx = phase + 1;
414 while (idx < heads.length) {
415 if (heads[idx] != null) {
416 break;
417 }
418 ++idx;
419 }
420
421 if (idx != heads.length) {
422 //found something after us
423 ih.next = heads[idx];
424 heads[idx].prev = ih;
425 }
426 }
427 } else { // this phase already has interceptors attached
428
429 // list of interceptors that the new interceptor should precede
430 Set beforeList = interc.getBefore();
431
432 // list of interceptors that the new interceptor should be after
433 Set afterList = interc.getAfter();
434
435 // firstBefore will hold the first interceptor of a given phase
436 // that the interceptor to be added must precede
437 InterceptorHolder firstBefore = null;
438
439 // lastAfter will hold the last interceptor of a given phase
440 // that the interceptor to be added must come after
441 InterceptorHolder lastAfter = null;
442
443 String id = interc.getId();
444 if (hasAfters[phase] || !beforeList.isEmpty()) {
445
446 InterceptorHolder ih2 = heads[phase];
447 while (ih2 != tails[phase].next) {
448 PhaseInterceptor cmp = ih2.interceptor;
449 String cmpId = cmp.getId();
450 if (cmpId != null && firstBefore == null
451 && (beforeList.contains(cmpId)
452 || cmp.getAfter().contains(id))) {
453 firstBefore = ih2;
454 }
455 if (cmpId != null && afterList.contains(cmpId)) {
456 lastAfter = ih2;
457 }
458 if (!force && cmpId.equals(id)) {
459 // interceptor is already in chain
460 return;
461 }
462 ih2 = ih2.next;
463 }
464 if (lastAfter == null && beforeList.contains("*")) {
465 firstBefore = heads[phase];
466 }
467 //System.out.print("Didn't skip: " + phase.toString());
468 //System.out.println(" " + interc.getId());
469 } else if (!force) {
470 // skip interceptor if already in chain
471 InterceptorHolder ih2 = heads[phase];
472 while (ih2 != tails[phase].next) {
473 if (ih2.interceptor.getId().equals(id)) {
474 return;
475 }
476 ih2 = ih2.next;
477 }
478
479 //System.out.print("Skipped: " + phase.toString());
480 //System.out.println(" " + interc.getId());
481 }
482 hasAfters[phase] |= !afterList.isEmpty();
483
484 if (firstBefore == null) {
485 //just add new interceptor at the end
486 ih.prev = tails[phase];
487 ih.next = tails[phase].next;
488 tails[phase].next = ih;
489
490 if (ih.next != null) {
491 ih.next.prev = ih;
492 }
493 tails[phase] = ih;
494 } else {
495 ih.prev = firstBefore.prev;
496 if (ih.prev != null) {
497 ih.prev.next = ih;
498 }
499 ih.next = firstBefore;
500 firstBefore.prev = ih;
501
502 if (heads[phase] == firstBefore) {
503 heads[phase] = ih;
504 }
505 }
506 }
507 if (iterator != null) {
508 outputChainToLog(true);
509 }
510 }
511
512 public String toString() {
513 return toString("");
514 }
515 private String toString(String message) {
516 StringBuilder chain = new StringBuilder();
517
518 chain.append("Chain ")
519 .append(super.toString())
520 .append(message)
521 .append(". Current flow:\n");
522
523 for (int x = 0; x < phases.length; x++) {
524 if (heads[x] != null) {
525 chain.append(" ");
526 printPhase(x, chain);
527 }
528 }
529 return chain.toString();
530 }
531 private void printPhase(int ph, StringBuilder chain) {
532
533 chain.append(phases[ph].getName())
534 .append(" [");
535 InterceptorHolder i = heads[ph];
536 boolean first = true;
537 while (i != tails[ph].next) {
538 if (first) {
539 first = false;
540 } else {
541 chain.append(", ");
542 }
543 chain.append(i.interceptor.getClass().getSimpleName());
544 i = i.next;
545 }
546 chain.append("]\n");
547 }
548
549 private void outputChainToLog(boolean modified) {
550 if (LOG.isLoggable(Level.FINE)) {
551 if (modified) {
552 LOG.fine(toString(" was modified"));
553 } else {
554 LOG.fine(toString(" was created"));
555 }
556 }
557 }
558
559 public MessageObserver getFaultObserver() {
560 return faultObserver;
561 }
562
563 public void setFaultObserver(MessageObserver faultObserver) {
564 this.faultObserver = faultObserver;
565 }
566
567 static final class PhaseInterceptorIterator implements ListIterator<Interceptor<? extends Message>> {
568 InterceptorHolder heads[];
569 InterceptorHolder prev;
570 InterceptorHolder first;
571
572 public PhaseInterceptorIterator(InterceptorHolder h[]) {
573 heads = h;
574 first = findFirst();
575 }
576
577 public void reset() {
578 prev = null;
579 first = findFirst();
580 }
581
582 private InterceptorHolder findFirst() {
583 for (int x = 0; x < heads.length; x++) {
584 if (heads[x] != null) {
585 return heads[x];
586 }
587 }
588 return null;
589 }
590
591
592 public boolean hasNext() {
593 if (prev == null) {
594 return first != null;
595 }
596 return prev.next != null;
597 }
598
599 @SuppressWarnings("unchecked")
600 public Interceptor<? extends Message> next() {
601 if (prev == null) {
602 if (first == null) {
603 throw new NoSuchElementException();
604 }
605 prev = first;
606 } else {
607 if (prev.next == null) {
608 throw new NoSuchElementException();
609 }
610 prev = prev.next;
611 }
612 return prev.interceptor;
613 }
614 public InterceptorHolder nextInterceptorHolder() {
615 if (prev == null) {
616 if (first == null) {
617 throw new NoSuchElementException();
618 }
619 prev = first;
620 } else {
621 if (prev.next == null) {
622 throw new NoSuchElementException();
623 }
624 prev = prev.next;
625 }
626 return prev;
627 }
628
629 public boolean hasPrevious() {
630 return prev != null;
631 }
632 @SuppressWarnings("unchecked")
633 public Interceptor<? extends Message> previous() {
634 if (prev == null) {
635 throw new NoSuchElementException();
636 }
637 InterceptorHolder tmp = prev;
638 prev = prev.prev;
639 return tmp.interceptor;
640 }
641
642 public int nextIndex() {
643 throw new UnsupportedOperationException();
644 }
645 public int previousIndex() {
646 throw new UnsupportedOperationException();
647 }
648 public void add(Interceptor o) {
649 throw new UnsupportedOperationException();
650 }
651 public void set(Interceptor o) {
652 throw new UnsupportedOperationException();
653 }
654 public void remove() {
655 throw new UnsupportedOperationException();
656 }
657 }
658
659
660 static final class InterceptorHolder {
661 PhaseInterceptor interceptor;
662 InterceptorHolder next;
663 InterceptorHolder prev;
664 int phaseIdx;
665
666 InterceptorHolder(PhaseInterceptor i, int p) {
667 interceptor = i;
668 phaseIdx = p;
669 }
670 InterceptorHolder(InterceptorHolder p) {
671 interceptor = p.interceptor;
672 phaseIdx = p.phaseIdx;
673 }
674 }
675
676 }