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.model; 018 019 import java.util.ArrayList; 020 import java.util.List; 021 import javax.xml.bind.annotation.XmlAccessType; 022 import javax.xml.bind.annotation.XmlAccessorType; 023 import javax.xml.bind.annotation.XmlRootElement; 024 import javax.xml.bind.annotation.XmlTransient; 025 026 import org.apache.camel.Predicate; 027 import org.apache.camel.Processor; 028 import org.apache.camel.builder.PredicateBuilder; 029 import org.apache.camel.processor.Interceptor; 030 import org.apache.camel.spi.RouteContext; 031 032 033 /** 034 * Represents an XML <intercept/> element 035 * 036 * @version $Revision: 2669 $ 037 */ 038 @XmlRootElement(name = "intercept") 039 @XmlAccessorType(XmlAccessType.FIELD) 040 public class InterceptType extends OutputType<ProcessorType> { 041 042 @XmlTransient 043 private ProceedType proceed = new ProceedType(); 044 @XmlTransient 045 private Boolean stopIntercept = Boolean.FALSE; 046 @XmlTransient 047 private Boolean usePredicate = Boolean.FALSE; 048 049 @Override 050 public String toString() { 051 return "Intercept[" + getOutputs() + "]"; 052 } 053 054 @Override 055 public String getShortName() { 056 return "intercept"; 057 } 058 059 @Override 060 public String getLabel() { 061 return "intercept"; 062 } 063 064 @Override 065 public Processor createProcessor(RouteContext routeContext) throws Exception { 066 Interceptor interceptor = new Interceptor(); 067 routeContext.intercept(interceptor); 068 069 final Processor interceptRoute = createOutputsProcessor(routeContext); 070 interceptor.setInterceptorLogic(interceptRoute); 071 072 return interceptor; 073 } 074 075 /** 076 * Applies this interceptor only if the given predicate is true 077 * 078 * @param predicate the predicate 079 * @return the builder 080 */ 081 public ChoiceType when(Predicate predicate) { 082 usePredicate = Boolean.TRUE; 083 ChoiceType choice = choice().when(PredicateBuilder.not(predicate)); 084 choice.addOutput(proceed); 085 return choice.otherwise(); 086 } 087 088 public ProceedType getProceed() { 089 return proceed; 090 } 091 092 public void stopIntercept() { 093 setStopIntercept(Boolean.TRUE); 094 } 095 096 /** 097 * This method is <b>only</b> for handling some post configuration 098 * that is needed from the Spring DSL side as JAXB does not invoke the fluent 099 * builders, so we need to manually handle this afterwards, and since this is 100 * an interceptor it has to do a bit of magic logic to fixup to handle predicates 101 * with or without proceed/stop set as well. 102 */ 103 public void afterPropertiesSet() { 104 List<ProcessorType<?>> list = new ArrayList<ProcessorType<?>>(); 105 for (ProcessorType<?> out : outputs) { 106 if (out instanceof WhenType) { 107 // JAXB does not invoke the when() fluent builder so we need to wrap the when in 108 // a choice with the proceed as the when for the Java DSL does 109 WhenType when = (WhenType) out; 110 usePredicate = Boolean.TRUE; 111 ChoiceType choice = new ChoiceType(); 112 choice.when(PredicateBuilder.not(when.getExpression())); 113 choice.addOutput(proceed); 114 list.add(choice); 115 116 ChoiceType otherwise = choice.otherwise(); 117 // add the children to the otherwise 118 for (ProcessorType child : when.getOutputs()) { 119 if (child instanceof StopType) { 120 // notify we should stop 121 stopIntercept(); 122 } else { 123 otherwise.addOutput(child); 124 } 125 } 126 } else if (out instanceof StopType) { 127 // notify we shuld stop 128 stopIntercept(); 129 } else { 130 list.add(out); 131 } 132 } 133 134 // replace old output with this redone output list 135 outputs.clear(); 136 for (ProcessorType<?> out : list) { 137 addOutput(out); 138 } 139 } 140 141 public InterceptType createProxy() { 142 InterceptType answer = new InterceptType(); 143 answer.getOutputs().addAll(this.getOutputs()); 144 145 answer.setStopIntercept(getStopIntercept()); 146 147 // hack: now we need to replace the proceed of the proxy with its own 148 // a bit ugly, operating based on the assumption that the proceed is 149 // in its outputs (if proceed() was called) and/or in the 150 // outputs of the otherwise or last when clause for the predicated version. 151 if (answer.getOutputs().size() > 0) { 152 // this is for the predicate version or if a choice() is present 153 ChoiceType choice = null; 154 for (ProcessorType processor : answer.getOutputs()) { 155 if (processor instanceof ChoiceType) { 156 // special cases for predicates (choices) 157 choice = (ChoiceType) processor; 158 159 // for the predicated version we add the proceed() to otherwise() 160 // before knowing if stop() will follow, so let's make a small adjustment 161 if (usePredicate && getStopIntercept()) { 162 WhenType when = choice.getWhenClauses().get(0); 163 when.getOutputs().remove(this.getProceed()); 164 } 165 166 // add proceed to the when clause 167 addProceedProxy(this.getProceed(), answer.getProceed(), 168 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate && !getStopIntercept()); 169 170 // force adding a proceed at the end (otherwise) if its not a stop type 171 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept()); 172 173 if (getStopIntercept()) { 174 // must add proceed to when clause if stop is explictiy declared, otherwise when the 175 // predicate test fails then there is no proceed 176 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded) 177 addProceedProxy(this.getProceed(), answer.getProceed(), 178 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate); 179 } 180 181 break; 182 } 183 } 184 if (choice == null) { 185 // force adding a proceed at the end if its not a stop type 186 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept()); 187 } 188 } 189 190 return answer; 191 } 192 193 private void addProceedProxy(ProceedType orig, ProceedType proxy, ProcessorType<?> processor, boolean force) { 194 int index = processor.getOutputs().indexOf(orig); 195 if (index >= 0) { 196 processor.addOutput(proxy); 197 // replace original proceed with proxy 198 List<ProcessorType<?>> outs = processor.getOutputs(); 199 outs.remove(proxy); 200 outs.set(index, proxy); 201 } else if (force) { 202 processor.addOutput(proxy); 203 } 204 } 205 206 public void setStopIntercept(Boolean stop) { 207 this.stopIntercept = stop; 208 } 209 210 public Boolean getStopIntercept() { 211 return stopIntercept; 212 } 213 214 }