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.camel.processor.interceptor;
018    
019    import java.util.List;
020    
021    import org.apache.camel.Exchange;
022    import org.apache.camel.Message;
023    import org.apache.camel.Predicate;
024    import org.apache.camel.Processor;
025    import org.apache.camel.model.ProcessorType;
026    import org.apache.camel.processor.DelegateProcessor;
027    
028    /**
029     * An interceptor for debugging and tracing routes
030     *
031     * @version $Revision: 972 $
032     */
033    public class DebugInterceptor extends DelegateProcessor {
034        private final ProcessorType node;
035        private final List<Exchange> exchanges;
036        private final List<ExceptionEvent> exceptions;
037        private Predicate traceFilter;
038        private Breakpoint breakpoint = new Breakpoint();
039        private boolean traceExceptions = true;
040        private boolean enabled = true;
041    
042        public DebugInterceptor(ProcessorType node, Processor target, List<Exchange> exchanges, List<ExceptionEvent> exceptions) {
043            super(target);
044            this.node = node;
045            this.exchanges = exchanges;
046            this.exceptions = exceptions;
047        }
048    
049        @Override
050        public String toString() {
051            return "DebugInterceptor[" + node + "]";
052        }
053    
054        public void process(Exchange exchange) throws Exception {
055            if (isEnabled()) {
056                checkForBreakpoint(exchange);
057                addTraceExchange(exchange);
058            }
059            try {
060                super.proceed(exchange);
061            } catch (Exception e) {
062                onException(exchange, e);
063                throw e;
064            } catch (Error e) {
065                onException(exchange, e);
066                throw e;
067            }
068        }
069    
070        public ProcessorType getNode() {
071            return node;
072        }
073    
074        public boolean isEnabled() {
075            return enabled;
076        }
077    
078        public void setEnabled(boolean flag) {
079            enabled = flag;
080        }
081    
082        public List<Exchange> getExchanges() {
083            return exchanges;
084        }
085    
086        public List<ExceptionEvent> getExceptions() {
087            return exceptions;
088        }
089    
090        public Breakpoint getBreakpoint() {
091            return breakpoint;
092        }
093    
094        public Predicate getTraceFilter() {
095            return traceFilter;
096        }
097    
098        public void setTraceFilter(Predicate traceFilter) {
099            this.traceFilter = traceFilter;
100        }
101    
102        public boolean isTraceExceptions() {
103            return traceExceptions;
104        }
105    
106        public void setTraceExceptions(boolean traceExceptions) {
107            this.traceExceptions = traceExceptions;
108        }
109    
110        /**
111         * Stategy method to wait for a breakpoint if one is set
112         */
113        protected void checkForBreakpoint(Exchange exchange) {
114            breakpoint.waitForBreakpoint(exchange);
115        }
116    
117        /**
118         * Fired when an exception is thrown when processing the underlying processor
119         */
120        protected void onException(Exchange exchange, Throwable e) {
121            if (shouldTraceExceptionEvents(exchange, e))  {
122                exceptions.add(new ExceptionEvent(this, exchange, e));
123            }
124    
125        }
126    
127        private boolean shouldTraceExceptionEvents(Exchange exchange, Throwable e) {
128            return isTraceExceptions() && isEnabled();
129        }
130    
131        /**
132         * Strategy method to store the exchange in a trace log if it is enabled
133         */
134        protected void addTraceExchange(Exchange exchange) {
135            if (shouldTraceExchange(exchange)) {
136                exchanges.add(copyExchange(exchange));
137            }
138        }
139    
140        protected Exchange copyExchange(Exchange previousExchange) {
141            Exchange answer = previousExchange.newInstance();
142            answer.getProperties().putAll(previousExchange.getProperties());
143            answer.getIn().copyFrom(previousExchange.getIn());
144    
145            // only copy the out if its defined
146            Message previousOut = previousExchange.getOut(false);
147            if (previousOut != null) {
148                answer.getOut().copyFrom(previousOut);
149            }
150            return answer;
151        }
152    
153        /**
154         * Returns true if the given exchange should be logged in the trace list
155         */
156        protected boolean shouldTraceExchange(Exchange exchange) {
157            return traceFilter == null || traceFilter.matches(exchange);
158        }
159    }