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 */ 017package org.apache.camel.model; 018 019import java.util.ArrayList; 020import java.util.List; 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlRootElement; 024import javax.xml.bind.annotation.XmlTransient; 025 026import org.apache.camel.CamelContext; 027import org.apache.camel.Predicate; 028import org.apache.camel.Processor; 029import org.apache.camel.processor.Pipeline; 030import org.apache.camel.spi.InterceptStrategy; 031import org.apache.camel.spi.Metadata; 032import org.apache.camel.spi.RouteContext; 033 034/** 035 * Intercepts a message at each step in the route 036 * 037 * @version 038 */ 039@Metadata(label = "configuration") 040@XmlRootElement(name = "intercept") 041@XmlAccessorType(XmlAccessType.FIELD) 042public class InterceptDefinition extends OutputDefinition<InterceptDefinition> { 043 @XmlTransient 044 protected Processor output; 045 @XmlTransient 046 protected final List<Processor> intercepted = new ArrayList<Processor>(); 047 048 public InterceptDefinition() { 049 } 050 051 @Override 052 public String toString() { 053 return "Intercept[" + getOutputs() + "]"; 054 } 055 056 @Override 057 public String getLabel() { 058 return "intercept"; 059 } 060 061 @Override 062 public boolean isAbstract() { 063 return true; 064 } 065 066 @Override 067 public boolean isTopLevelOnly() { 068 return true; 069 } 070 071 @Override 072 public Processor createProcessor(final RouteContext routeContext) throws Exception { 073 // create the output processor 074 output = this.createChildProcessor(routeContext, true); 075 076 // add the output as a intercept strategy to the route context so its invoked on each processing step 077 routeContext.getInterceptStrategies().add(new InterceptStrategy() { 078 private Processor interceptedTarget; 079 080 public Processor wrapProcessorInInterceptors(CamelContext context, ProcessorDefinition<?> definition, 081 Processor target, Processor nextTarget) throws Exception { 082 // store the target we are intercepting 083 this.interceptedTarget = target; 084 085 // remember the target that was intercepted 086 intercepted.add(interceptedTarget); 087 088 if (interceptedTarget != null) { 089 // wrap in a pipeline so we continue routing to the next 090 List<Processor> list = new ArrayList<Processor>(2); 091 list.add(output); 092 list.add(interceptedTarget); 093 return new Pipeline(context, list); 094 } else { 095 return output; 096 } 097 } 098 099 @Override 100 public String toString() { 101 return "intercept[" + (interceptedTarget != null ? interceptedTarget : output) + "]"; 102 } 103 }); 104 105 // remove me from the route so I am not invoked in a regular route path 106 routeContext.getRoute().getOutputs().remove(this); 107 // and return no processor to invoke next from me 108 return null; 109 } 110 111 /** 112 * Applies this interceptor only if the given predicate is true 113 * 114 * @param predicate the predicate 115 * @return the builder 116 */ 117 public InterceptDefinition when(Predicate predicate) { 118 WhenDefinition when = new WhenDefinition(predicate); 119 addOutput(when); 120 return this; 121 } 122 123 /** 124 * This method is <b>only</b> for handling some post configuration 125 * that is needed since this is an interceptor, and we have to do 126 * a bit of magic logic to fixup to handle predicates 127 * with or without proceed/stop set as well. 128 */ 129 public void afterPropertiesSet() { 130 if (getOutputs().size() == 0) { 131 // no outputs 132 return; 133 } 134 135 ProcessorDefinition<?> first = getOutputs().get(0); 136 if (first instanceof WhenDefinition) { 137 WhenDefinition when = (WhenDefinition) first; 138 // move this outputs to the when, expect the first one 139 // as the first one is the interceptor itself 140 for (int i = 1; i < outputs.size(); i++) { 141 ProcessorDefinition<?> out = outputs.get(i); 142 when.addOutput(out); 143 } 144 // remove the moved from the original output, by just keeping the first one 145 ProcessorDefinition<?> keep = outputs.get(0); 146 clearOutput(); 147 outputs.add(keep); 148 } 149 } 150 151 public Processor getInterceptedProcessor(int index) { 152 // avoid out of bounds 153 if (index <= intercepted.size() - 1) { 154 return intercepted.get(index); 155 } else { 156 return null; 157 } 158 } 159}