001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.phase;
019:
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.ListIterator;
024: import java.util.Map;
025: import java.util.NoSuchElementException;
026: import java.util.Set;
027: import java.util.SortedSet;
028: import java.util.logging.Level;
029: import java.util.logging.Logger;
030:
031: import org.apache.cxf.common.logging.LogUtils;
032: import org.apache.cxf.interceptor.Interceptor;
033: import org.apache.cxf.interceptor.InterceptorChain;
034: import org.apache.cxf.message.Message;
035: import org.apache.cxf.transport.MessageObserver;
036:
037: /**
038: * A PhaseInterceptorChain orders Interceptors according to the phase they
039: * participate in and also according to the before & after properties on an
040: * Interceptor.
041: * <p>
042: * A List of phases is supplied to the PhaseInterceptorChain in the constructor.
043: * Interceptors that are added to the chain are ordered by phase. Within a
044: * phase, interceptors can order themselves. Each PhaseInterceptor has an ID.
045: * PhaseInterceptors can supply a Collection of IDs which they should run before
046: * or after, supplying fine grained ordering.
047: * <p>
048: *
049: */
050: public class PhaseInterceptorChain implements InterceptorChain {
051:
052: private static final Logger LOG = Logger
053: .getLogger(PhaseInterceptorChain.class.getName());
054:
055: private final Map<String, Integer> nameMap;
056: private final Phase phases[];
057:
058: private InterceptorHolder heads[];
059: private InterceptorHolder tails[];
060: private boolean hasAfters[];
061:
062: private State state;
063: private Message pausedMessage;
064: private MessageObserver faultObserver;
065: private PhaseInterceptorIterator iterator;
066:
067: // currently one chain for one request/response, use below as signal to avoid duplicate fault processing
068: // on nested calling of doIntercept(), which will throw same fault multi-times
069: private boolean faultOccurred;
070:
071: private PhaseInterceptorChain(PhaseInterceptorChain src) {
072: //only used for clone
073: state = State.EXECUTING;
074:
075: //immutable, just repoint
076: nameMap = src.nameMap;
077: phases = src.phases;
078:
079: int length = phases.length;
080: hasAfters = new boolean[length];
081: System.arraycopy(src.hasAfters, 0, hasAfters, 0, length);
082:
083: heads = new InterceptorHolder[length];
084: tails = new InterceptorHolder[length];
085:
086: InterceptorHolder last = null;
087: for (int x = 0; x < length; x++) {
088: InterceptorHolder ih = src.heads[x];
089: while (ih != null && ih.phaseIdx == x) {
090: InterceptorHolder ih2 = new InterceptorHolder(ih);
091: ih2.prev = last;
092: if (last != null) {
093: last.next = ih2;
094: }
095: if (heads[x] == null) {
096: heads[x] = ih2;
097: }
098: tails[x] = ih2;
099: last = ih2;
100: ih = ih.next;
101: }
102: }
103: }
104:
105: public PhaseInterceptorChain(SortedSet<Phase> ps) {
106: state = State.EXECUTING;
107:
108: int numPhases = ps.size();
109: phases = new Phase[numPhases];
110: nameMap = new HashMap<String, Integer>();
111:
112: heads = new InterceptorHolder[numPhases];
113: tails = new InterceptorHolder[numPhases];
114: hasAfters = new boolean[numPhases];
115:
116: int idx = 0;
117: for (Phase phase : ps) {
118: phases[idx] = phase;
119: nameMap.put(phase.getName(), idx);
120: ++idx;
121: }
122: }
123:
124: public PhaseInterceptorChain cloneChain() {
125: return new PhaseInterceptorChain(this );
126: }
127:
128: private void updateIterator() {
129: if (iterator == null) {
130: iterator = new PhaseInterceptorIterator(heads);
131: outputChainToLog(false);
132: //System.out.println(toString());
133: }
134: }
135:
136: public void add(Collection<Interceptor> newhandlers) {
137: add(newhandlers, false);
138: }
139:
140: public void add(Collection<Interceptor> newhandlers, boolean force) {
141: if (newhandlers == null) {
142: return;
143: }
144:
145: for (Interceptor handler : newhandlers) {
146: add(handler, force);
147: }
148: }
149:
150: public void add(Interceptor i) {
151: add(i, false);
152: }
153:
154: public void add(Interceptor i, boolean force) {
155: PhaseInterceptor pi = (PhaseInterceptor) i;
156:
157: if (LOG.isLoggable(Level.FINE)) {
158: LOG.fine("Adding interceptor " + i + " to phase "
159: + pi.getPhase());
160: }
161:
162: String phaseName = pi.getPhase();
163:
164: Integer phase = nameMap.get(phaseName);
165: if (phase == null) {
166: LOG.fine("Phase " + phaseName
167: + " does not exist. Skipping handler "
168: + i.getClass().getName());
169: } else {
170: insertInterceptor(phase, pi, force);
171: }
172: }
173:
174: public synchronized void pause() {
175: state = State.PAUSED;
176: }
177:
178: public synchronized void resume() {
179: if (state == State.PAUSED) {
180: state = State.EXECUTING;
181: doIntercept(pausedMessage);
182: }
183: }
184:
185: /**
186: * Intercept a message, invoking each phase's handlers in turn.
187: *
188: * @param message the message
189: * @throws Exception
190: */
191: @SuppressWarnings("unchecked")
192: public synchronized boolean doIntercept(Message message) {
193: updateIterator();
194:
195: pausedMessage = message;
196: while (state == State.EXECUTING && iterator.hasNext()) {
197: try {
198: Interceptor currentInterceptor = iterator.next();
199:
200: if (LOG.isLoggable(Level.FINE)) {
201: LOG.fine("Invoking handleMessage on interceptor "
202: + currentInterceptor);
203: }
204: //System.out.println("-----------" + currentInterceptor);
205: currentInterceptor.handleMessage(message);
206:
207: } catch (RuntimeException ex) {
208: if (!faultOccurred) {
209:
210: faultOccurred = true;
211: if (LOG.isLoggable(Level.INFO)) {
212: LogUtils
213: .log(
214: LOG,
215: Level.INFO,
216: "Interceptor has thrown exception, unwinding now",
217: ex);
218: }
219:
220: message.setContent(Exception.class, ex);
221: if (message.getExchange() != null) {
222: message.getExchange().put(Exception.class, ex);
223: }
224: unwind(message);
225:
226: if (faultObserver != null) {
227: faultObserver.onMessage(message);
228: }
229: }
230: state = State.ABORTED;
231: }
232: }
233: if (state == State.EXECUTING) {
234: state = State.COMPLETE;
235: }
236: return state == State.COMPLETE;
237: }
238:
239: /**
240: * Intercept a message, invoking each phase's handlers in turn,
241: * starting after the specified interceptor.
242: *
243: * @param message the message
244: * @param startingAfterInterceptorID the id of the interceptor
245: * @throws Exception
246: */
247: @SuppressWarnings("unchecked")
248: public synchronized boolean doInterceptStartingAfter(
249: Message message, String startingAfterInterceptorID) {
250: updateIterator();
251: while (state == State.EXECUTING && iterator.hasNext()) {
252: PhaseInterceptor currentInterceptor = (PhaseInterceptor) iterator
253: .next();
254: if (currentInterceptor.getId().equals(
255: startingAfterInterceptorID)) {
256: break;
257: }
258: }
259: return doIntercept(message);
260: }
261:
262: /**
263: * Intercept a message, invoking each phase's handlers in turn,
264: * starting at the specified interceptor.
265: *
266: * @param message the message
267: * @param startingAtInterceptorID the id of the interceptor
268: * @throws Exception
269: */
270: @SuppressWarnings("unchecked")
271: public synchronized boolean doInterceptStartingAt(Message message,
272: String startingAtInterceptorID) {
273: updateIterator();
274: while (state == State.EXECUTING && iterator.hasNext()) {
275: PhaseInterceptor currentInterceptor = (PhaseInterceptor) iterator
276: .next();
277: if (currentInterceptor.getId().equals(
278: startingAtInterceptorID)) {
279: iterator.previous();
280: break;
281: }
282: }
283: return doIntercept(message);
284: }
285:
286: public synchronized void reset() {
287: updateIterator();
288: if (state == State.COMPLETE) {
289: state = State.EXECUTING;
290: iterator.reset();
291: } else {
292: iterator.reset();
293: }
294: }
295:
296: @SuppressWarnings("unchecked")
297: private void unwind(Message message) {
298: while (iterator.hasPrevious()) {
299: Interceptor currentInterceptor = iterator.previous();
300: if (LOG.isLoggable(Level.FINE)) {
301: LOG.fine("Invoking handleFault on interceptor "
302: + currentInterceptor);
303: }
304: currentInterceptor.handleFault(message);
305: }
306: }
307:
308: public void remove(Interceptor i) {
309: PhaseInterceptorIterator it = new PhaseInterceptorIterator(
310: heads);
311: while (it.hasNext()) {
312: InterceptorHolder holder = it.nextInterceptorHolder();
313: if (holder.interceptor == i) {
314: remove(holder);
315: return;
316: }
317: }
318: }
319:
320: public synchronized void abort() {
321: this .state = InterceptorChain.State.ABORTED;
322: }
323:
324: public Iterator<Interceptor<? extends Message>> iterator() {
325: return getIterator();
326: }
327:
328: public ListIterator<Interceptor<? extends Message>> getIterator() {
329: return new PhaseInterceptorIterator(heads);
330: }
331:
332: private void remove(InterceptorHolder i) {
333: if (i.prev != null) {
334: i.prev.next = i.next;
335: }
336: if (i.next != null) {
337: i.next.prev = i.prev;
338: }
339: int ph = i.phaseIdx;
340: if (heads[ph] == i) {
341: if (i.next != null && i.next.phaseIdx == ph) {
342: heads[ph] = i.next;
343: } else {
344: heads[ph] = null;
345: tails[ph] = null;
346: }
347: }
348: if (tails[ph] == i) {
349: if (i.prev != null && i.prev.phaseIdx == ph) {
350: tails[ph] = i.prev;
351: } else {
352: heads[ph] = null;
353: tails[ph] = null;
354: }
355: }
356: }
357:
358: private void insertInterceptor(int phase, PhaseInterceptor interc,
359: boolean force) {
360: InterceptorHolder ih = new InterceptorHolder(interc, phase);
361: if (heads[phase] == null) {
362: heads[phase] = ih;
363: tails[phase] = ih;
364:
365: int idx = phase - 1;
366: while (idx >= 0) {
367: if (tails[idx] != null) {
368: break;
369: }
370: --idx;
371: }
372: if (idx >= 0) {
373: //found something before us
374: ih.prev = tails[idx];
375: ih.next = tails[idx].next;
376: if (ih.next != null) {
377: ih.next.prev = ih;
378: }
379: tails[idx].next = ih;
380: } else {
381: //did not find something before us, try after
382: idx = phase + 1;
383: while (idx < heads.length) {
384: if (heads[idx] != null) {
385: break;
386: }
387: ++idx;
388: }
389:
390: if (idx != heads.length) {
391: //found something after us
392: ih.next = heads[idx];
393: heads[idx].prev = ih;
394: }
395: }
396: hasAfters[phase] = !interc.getAfter().isEmpty();
397: } else {
398:
399: Set beforeList = interc.getBefore();
400: Set afterList = interc.getAfter();
401: InterceptorHolder before = null;
402: InterceptorHolder after = null;
403:
404: String id = interc.getId();
405: if (hasAfters[phase] || !beforeList.isEmpty()) {
406:
407: InterceptorHolder ih2 = heads[phase];
408: while (ih2 != tails[phase].next) {
409: PhaseInterceptor cmp = ih2.interceptor;
410: String cmpId = cmp.getId();
411: if (cmpId != null
412: && before == null
413: && (beforeList.contains(cmpId) || cmp
414: .getAfter().contains(id))) {
415: //first one we need to be before
416: before = ih2;
417: }
418: if (cmpId != null && afterList.contains(cmpId)) {
419: after = ih2;
420: }
421: if (!force && cmpId.equals(id)) {
422: return;
423: }
424: ih2 = ih2.next;
425: }
426: if (after == null && beforeList.contains("*")) {
427: before = heads[phase];
428: }
429: //System.out.print("Didn't skip: " + phase.toString());
430: //System.out.println(" " + interc.getId());
431: } else if (!force) {
432: InterceptorHolder ih2 = heads[phase];
433: while (ih2 != tails[phase].next) {
434: if (ih2.interceptor.getId().equals(id)) {
435: return;
436: }
437: ih2 = ih2.next;
438: }
439:
440: //System.out.print("Skipped: " + phase.toString());
441: //System.out.println(" " + interc.getId());
442: }
443: hasAfters[phase] |= !afterList.isEmpty();
444:
445: if (before == null) {
446: //just add at the end
447: ih.prev = tails[phase];
448: if (tails[phase] != null) {
449: ih.next = tails[phase].next;
450: tails[phase].next = ih;
451: }
452: if (ih.next != null) {
453: ih.next.prev = ih;
454: }
455: tails[phase] = ih;
456: } else {
457: ih.prev = before.prev;
458: if (ih.prev != null) {
459: ih.prev.next = ih;
460: }
461: ih.next = before;
462: before.prev = ih;
463:
464: if (heads[phase] == before) {
465: heads[phase] = ih;
466: }
467: }
468: }
469: if (iterator != null) {
470: outputChainToLog(true);
471: }
472: }
473:
474: public String toString() {
475: return toString("");
476: }
477:
478: private String toString(String message) {
479: StringBuilder chain = new StringBuilder();
480:
481: chain.append("Chain ").append(super .toString()).append(message)
482: .append(". Current flow:\n");
483:
484: for (int x = 0; x < phases.length; x++) {
485: if (heads[x] != null) {
486: chain.append(" ");
487: printPhase(x, chain);
488: }
489: }
490: return chain.toString();
491: }
492:
493: private void printPhase(int ph, StringBuilder chain) {
494:
495: chain.append(phases[ph].getName()).append(" [");
496: InterceptorHolder i = heads[ph];
497: boolean first = true;
498: while (i != tails[ph].next) {
499: if (first) {
500: first = false;
501: } else {
502: chain.append(", ");
503: }
504: chain.append(i.interceptor.getClass().getSimpleName());
505: i = i.next;
506: }
507: chain.append("]\n");
508: }
509:
510: private void outputChainToLog(boolean modified) {
511: if (LOG.isLoggable(Level.FINE)) {
512: if (modified) {
513: LOG.fine(toString(" was modified"));
514: } else {
515: LOG.fine(toString(" was created"));
516: }
517: }
518: }
519:
520: public MessageObserver getFaultObserver() {
521: return faultObserver;
522: }
523:
524: public void setFaultObserver(MessageObserver faultObserver) {
525: this .faultObserver = faultObserver;
526: }
527:
528: static final class PhaseInterceptorIterator implements
529: ListIterator<Interceptor<? extends Message>> {
530: InterceptorHolder heads[];
531: InterceptorHolder prev;
532: InterceptorHolder first;
533:
534: public PhaseInterceptorIterator(InterceptorHolder h[]) {
535: heads = h;
536: first = findFirst();
537: }
538:
539: public void reset() {
540: prev = null;
541: first = findFirst();
542: }
543:
544: private InterceptorHolder findFirst() {
545: for (int x = 0; x < heads.length; x++) {
546: if (heads[x] != null) {
547: return heads[x];
548: }
549: }
550: return null;
551: }
552:
553: public boolean hasNext() {
554: if (prev == null) {
555: return first != null;
556: }
557: return prev.next != null;
558: }
559:
560: @SuppressWarnings("unchecked")
561: public Interceptor<? extends Message> next() {
562: if (prev == null) {
563: if (first == null) {
564: throw new NoSuchElementException();
565: }
566: prev = first;
567: } else {
568: if (prev.next == null) {
569: throw new NoSuchElementException();
570: }
571: prev = prev.next;
572: }
573: return prev.interceptor;
574: }
575:
576: public InterceptorHolder nextInterceptorHolder() {
577: if (prev == null) {
578: if (first == null) {
579: throw new NoSuchElementException();
580: }
581: prev = first;
582: } else {
583: if (prev.next == null) {
584: throw new NoSuchElementException();
585: }
586: prev = prev.next;
587: }
588: return prev;
589: }
590:
591: public boolean hasPrevious() {
592: return prev != null;
593: }
594:
595: @SuppressWarnings("unchecked")
596: public Interceptor<? extends Message> previous() {
597: if (prev == null) {
598: throw new NoSuchElementException();
599: }
600: InterceptorHolder tmp = prev;
601: prev = prev.prev;
602: return tmp.interceptor;
603: }
604:
605: public int nextIndex() {
606: throw new UnsupportedOperationException();
607: }
608:
609: public int previousIndex() {
610: throw new UnsupportedOperationException();
611: }
612:
613: public void add(Interceptor o) {
614: throw new UnsupportedOperationException();
615: }
616:
617: public void set(Interceptor o) {
618: throw new UnsupportedOperationException();
619: }
620:
621: public void remove() {
622: throw new UnsupportedOperationException();
623: }
624: }
625:
626: static final class InterceptorHolder {
627: PhaseInterceptor interceptor;
628: InterceptorHolder next;
629: InterceptorHolder prev;
630: int phaseIdx;
631:
632: InterceptorHolder(PhaseInterceptor i, int p) {
633: interceptor = i;
634: phaseIdx = p;
635: }
636:
637: InterceptorHolder(InterceptorHolder p) {
638: interceptor = p.interceptor;
639: phaseIdx = p.phaseIdx;
640: }
641: }
642:
643: }
|