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