Home » apache-cxf-2.1.1-src » org.apache » cxf » phase » [javadoc | source]
    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   }

Save This Page
Home » apache-cxf-2.1.1-src » org.apache » cxf » phase » [javadoc | source]