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.servicemix.soap.core;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.List;
022    import java.util.ListIterator;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.apache.servicemix.soap.api.Interceptor;
027    import org.apache.servicemix.soap.api.InterceptorChain;
028    import org.apache.servicemix.soap.api.Message;
029    
030    /**
031     * A PhaseInterceptorChain orders Interceptors according 
032     * to the before & after properties on an Interceptor.
033     *
034     * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
035     */
036    public class PhaseInterceptorChain implements InterceptorChain {
037    
038        private static final Log LOG = LogFactory.getLog(PhaseInterceptorChain.class);
039        
040        private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
041        
042        public PhaseInterceptorChain() {
043        }
044    
045        public void add(Iterable<? extends Interceptor> newhandlers) {
046            if (newhandlers == null) {
047                return;
048            }
049            for (Interceptor handler : newhandlers) {
050                add(handler);
051            }
052        }
053        
054        public Iterable<Interceptor> getInterceptors() {
055            return interceptors;
056        }
057    
058        public void add(Interceptor i) {
059            if (LOG.isDebugEnabled()) {
060                LOG.debug("Adding interceptor " + i.getId());
061            }
062            insertInterceptor(i);
063        }
064    
065        /**
066         * Invokes each phase's handler in turn.
067         * 
068         * @param context
069         * @throws Exception
070         */
071        public void doIntercept(Message message) {
072            ListIterator<Interceptor> iterator = getState(message);
073            
074            if (iterator == null) {
075                iterator = interceptors.listIterator();
076                setState(message, iterator);
077            }
078    
079            try {
080                while (iterator.hasNext()) {
081                    Interceptor currentInterceptor = iterator.next();
082                    if (LOG.isDebugEnabled()) {
083                        LOG.debug("Invoking handleMessage on interceptor " + currentInterceptor.getId());
084                    }
085                    currentInterceptor.handleMessage(message);
086                }
087            } catch (RuntimeException ex) {
088                if (LOG.isInfoEnabled()) {
089                    LOG.info("Interceptor has thrown exception, unwinding now", ex);
090                }
091                message.setContent(Exception.class, ex);
092                // Unwind
093                while (iterator.hasPrevious()) {
094                    Interceptor currentInterceptor = iterator.previous();
095                    if (LOG.isDebugEnabled()) {
096                        LOG.debug("Invoking handleFault on interceptor " + currentInterceptor.getId());
097                    }
098                    currentInterceptor.handleFault(message);
099                }
100                throw ex;
101            }
102        }
103        
104        @SuppressWarnings("unchecked")
105        protected ListIterator<Interceptor> getState(Message message) {
106            Object state = message.get(this.toString());
107            return (ListIterator<Interceptor>) state;
108        }
109        
110        protected void setState(Message message, ListIterator<Interceptor> state) {
111            message.put(this.toString(), state);
112            message.put(InterceptorChain.class, this);
113        }
114        
115        protected void insertInterceptor(Interceptor interc) {
116            if (interceptors.size() == 0) {
117                interceptors.add(interc);
118                return;
119            }
120            int begin = -1;
121            int end = interceptors.size();
122            Collection before = interc.getBefore();
123            Collection after = interc.getAfter();
124            for (int i = 0; i < interceptors.size(); i++) {
125                Interceptor cmp = interceptors.get(i);
126                if (cmp.getId() == null) {
127                    continue;
128                }
129                if (before.contains(cmp.getId()) && i < end) {
130                    end = i;
131                }
132                if (cmp.getBefore().contains(interc.getId()) && i > begin) {
133                    begin = i;
134                }
135                if (after.contains(cmp.getId()) && i > begin) {
136                    begin = i;
137                }
138                if (cmp.getAfter().contains(interc.getId()) && i < end) {
139                    end = i;
140                }
141            }
142            if (end < begin + 1) {
143                throw new IllegalStateException("Invalid ordering for interceptor " + interc.getId());
144            }
145            interceptors.add(end, interc);
146        }
147    
148        
149    }