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: 52393 $ 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 String getLabel() { 065 return "intercept"; 066 } 067 068 @Override 069 public Processor createProcessor(RouteContext routeContext) throws Exception { 070 Interceptor interceptor = new Interceptor(); 071 routeContext.intercept(interceptor); 072 073 final Processor interceptRoute = createOutputsProcessor(routeContext); 074 interceptor.setInterceptorLogic(interceptRoute); 075 076 return interceptor; 077 } 078 079 /** 080 * Applies this interceptor only if the given predicate is true 081 */ 082 public ChoiceType when(Predicate predicate) { 083 usePredicate = Boolean.TRUE; 084 ChoiceType choice = choice().when(PredicateBuilder.not(predicate)); 085 choice.addOutput(proceed); 086 return choice.otherwise(); 087 } 088 089 public ProceedType getProceed() { 090 return proceed; 091 } 092 093 public void stopIntercept() { 094 setStopIntercept(Boolean.TRUE); 095 } 096 097 @XmlElement(name = "stop", required = false) 098 public void setStop(String elementValue /* not used */) { 099 stopIntercept(); 100 } 101 102 public InterceptType createProxy() { 103 InterceptType answer = new InterceptType(); 104 answer.getOutputs().addAll(this.getOutputs()); 105 106 answer.setStopIntercept(getStopIntercept()); 107 108 // hack: now we need to replace the proceed of the proxy with its own 109 // a bit ugly, operating based on the assumption that the proceed is 110 // in its outputs (if proceed() was called) and/or in the 111 // outputs of the otherwise or last when clause for the predicated version. 112 if (answer.getOutputs().size() > 0) { 113 // this is for the predicate version or if a choice() is present 114 ChoiceType choice = null; 115 for (ProcessorType processor : answer.getOutputs()) { 116 if (processor instanceof ChoiceType) { 117 // special cases for predicates (choices) 118 choice = (ChoiceType) processor; 119 120 // for the predicated version we add the proceed() to otherwise() 121 // before knowing if stop() will follow, so let's make a small adjustment 122 if (usePredicate.booleanValue() && getStopIntercept().booleanValue()) { 123 WhenType when = choice.getWhenClauses().get(0); 124 when.getOutputs().remove(this.getProceed()); 125 } 126 127 // add proceed to the when clause 128 addProceedProxy(this.getProceed(), answer.getProceed(), 129 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue() && !getStopIntercept().booleanValue()); 130 131 // force adding a proceed at the end (otherwise) if its not a stop type 132 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept().booleanValue()); 133 134 if (getStopIntercept().booleanValue()) { 135 // must add proceed to when clause if stop is explictiy declared, otherwise when the 136 // predicate test fails then there is no proceed 137 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded) 138 addProceedProxy(this.getProceed(), answer.getProceed(), 139 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue()); 140 } 141 142 break; 143 } 144 } 145 if (choice == null) { 146 // force adding a proceed at the end if its not a stop type 147 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept().booleanValue()); 148 } 149 } 150 151 return answer; 152 } 153 154 private void addProceedProxy(ProceedType orig, ProceedType proxy, ProcessorType<?> processor, boolean force) { 155 int index = processor.getOutputs().indexOf(orig); 156 if (index >= 0) { 157 processor.addOutput(proxy); 158 // replace original proceed with proxy 159 List<ProcessorType<?>> outs = processor.getOutputs(); 160 outs.remove(proxy); 161 outs.set(index, proxy); 162 } else if (force) { 163 processor.addOutput(proxy); 164 } 165 } 166 167 public void setStopIntercept(Boolean stop) { 168 this.stopIntercept = stop; 169 } 170 171 public Boolean getStopIntercept() { 172 return stopIntercept; 173 } 174 175 }