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.Collection; 020 import java.util.Collections; 021 import java.util.List; 022 023 import javax.xml.bind.annotation.XmlAccessType; 024 import javax.xml.bind.annotation.XmlAccessorType; 025 import javax.xml.bind.annotation.XmlElement; 026 import javax.xml.bind.annotation.XmlRootElement; 027 import javax.xml.bind.annotation.XmlTransient; 028 029 import org.apache.camel.Intercept; 030 import org.apache.camel.Predicate; 031 import org.apache.camel.Processor; 032 import org.apache.camel.builder.PredicateBuilder; 033 import org.apache.camel.processor.Interceptor; 034 import org.apache.camel.spi.RouteContext; 035 036 037 /** 038 * Represents an XML <intercept/> element 039 * 040 * @version $Revision: 50606 $ 041 */ 042 @XmlRootElement(name = "intercept") 043 @XmlAccessorType(XmlAccessType.FIELD) 044 public class InterceptType extends OutputType<ProcessorType> { 045 046 @XmlTransient 047 private ProceedType proceed = new ProceedType(); 048 @XmlTransient 049 private Boolean stopIntercept = Boolean.FALSE; 050 @XmlTransient 051 private Boolean usePredicate = Boolean.FALSE; 052 053 @Override 054 public String toString() { 055 return "Intercept[" + getOutputs() + "]"; 056 } 057 058 @Override 059 public String getShortName() { 060 return "intercept"; 061 } 062 063 @Override 064 public Processor createProcessor(RouteContext routeContext) throws Exception { 065 Interceptor interceptor = new Interceptor(); 066 routeContext.intercept(interceptor); 067 068 final Processor interceptRoute = createOutputsProcessor(routeContext); 069 interceptor.setInterceptorLogic(interceptRoute); 070 071 return interceptor; 072 } 073 074 /** 075 * Applies this interceptor only if the given predicate is true 076 */ 077 public ChoiceType when(Predicate predicate) { 078 usePredicate = Boolean.TRUE; 079 ChoiceType choice = choice().when(PredicateBuilder.not(predicate)); 080 choice.addOutput(proceed); 081 return choice.otherwise(); 082 } 083 084 public ProceedType getProceed() { 085 return proceed; 086 } 087 088 public void stopIntercept() { 089 setStopIntercept(Boolean.TRUE); 090 } 091 092 @XmlElement(name = "stop", required = false) 093 public void setStop(String elementValue /* not used */) { 094 stopIntercept(); 095 } 096 097 public InterceptType createProxy() { 098 InterceptType answer = new InterceptType(); 099 answer.getOutputs().addAll(this.getOutputs()); 100 101 answer.setStopIntercept(getStopIntercept()); 102 103 // hack: now we need to replace the proceed of the proxy with its own 104 // a bit ugly, operating based on the assumption that the proceed is 105 // in its outputs (if proceed() was called) and/or in the 106 // outputs of the otherwise or last when clause for the predicated version. 107 if (answer.getOutputs().size() > 0) { 108 // this is for the predicate version or if a choice() is present 109 ChoiceType choice = null; 110 for (ProcessorType processor : answer.getOutputs()) { 111 if (processor instanceof ChoiceType) { 112 // special cases for predicates (choices) 113 choice = (ChoiceType) processor; 114 115 // for the predicated version we add the proceed() to otherwise() 116 // before knowing if stop() will follow, so let's make a small adjustment 117 if (usePredicate.booleanValue() && getStopIntercept().booleanValue()) { 118 WhenType when = choice.getWhenClauses().get(0); 119 when.getOutputs().remove(this.getProceed()); 120 } 121 122 // add proceed to the when clause 123 addProceedProxy(this.getProceed(), answer.getProceed(), 124 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue() && !getStopIntercept().booleanValue()); 125 126 // force adding a proceed at the end (otherwise) if its not a stop type 127 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept().booleanValue()); 128 129 if (getStopIntercept().booleanValue()) { 130 // must add proceed to when clause if stop is explictiy declared, otherwise when the 131 // predicate test fails then there is no proceed 132 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded) 133 addProceedProxy(this.getProceed(), answer.getProceed(), 134 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue()); 135 } 136 137 break; 138 } 139 } 140 if (choice == null) { 141 // force adding a proceed at the end if its not a stop type 142 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept().booleanValue()); 143 } 144 } 145 146 return answer; 147 } 148 149 private void addProceedProxy(ProceedType orig, ProceedType proxy, ProcessorType<?> processor, boolean force) { 150 int index = processor.getOutputs().indexOf(orig); 151 if (index >= 0) { 152 processor.addOutput(proxy); 153 // replace original proceed with proxy 154 List<ProcessorType<?>> outs = processor.getOutputs(); 155 outs.remove(proxy); 156 outs.set(index, proxy); 157 } else if (force) { 158 processor.addOutput(proxy); 159 } 160 } 161 162 public void setStopIntercept(Boolean stop) { 163 this.stopIntercept = stop; 164 } 165 166 public Boolean getStopIntercept() { 167 return stopIntercept; 168 } 169 170 }