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.List; 020 import javax.xml.bind.annotation.XmlAccessType; 021 import javax.xml.bind.annotation.XmlAccessorType; 022 import javax.xml.bind.annotation.XmlAttribute; 023 import javax.xml.bind.annotation.XmlRootElement; 024 025 import org.apache.camel.Endpoint; 026 import org.apache.camel.Predicate; 027 import org.apache.camel.Processor; 028 import org.apache.camel.impl.InterceptSendToEndpoint; 029 import org.apache.camel.processor.InterceptEndpointProcessor; 030 import org.apache.camel.spi.EndpointStrategy; 031 import org.apache.camel.spi.RouteContext; 032 import org.apache.camel.util.EndpointHelper; 033 034 /** 035 * Represents an XML <interceptToEndpoint/> element 036 * 037 * @version 038 */ 039 @XmlRootElement(name = "interceptToEndpoint") 040 @XmlAccessorType(XmlAccessType.FIELD) 041 public class InterceptSendToEndpointDefinition extends OutputDefinition<InterceptSendToEndpointDefinition> { 042 043 // TODO: Support lookup endpoint by ref (requires a bit more work) 044 045 // TODO: interceptSendToEndpoint needs to proxy the endpoints at very first 046 // so when other processors uses an endpoint its already proxied, see workaround in SendProcessor 047 // needed when we haven't proxied beforehand. This requires some work in the route builder in Camel 048 // to implement so that should be a part of a bigger rework/improvement in the future 049 050 @XmlAttribute(required = true) 051 private String uri; 052 @XmlAttribute 053 private Boolean skipSendToOriginalEndpoint; 054 055 public InterceptSendToEndpointDefinition() { 056 } 057 058 public InterceptSendToEndpointDefinition(String uri) { 059 this.uri = uri; 060 } 061 062 @Override 063 public String toString() { 064 return "InterceptSendToEndpoint[" + uri + " -> " + getOutputs() + "]"; 065 } 066 067 @Override 068 public String getShortName() { 069 return "interceptSendToEndpoint"; 070 } 071 072 @Override 073 public String getLabel() { 074 return "interceptSendToEndpoint[" + uri + "]"; 075 } 076 077 @Override 078 public boolean isAbstract() { 079 return true; 080 } 081 082 @Override 083 public Processor createProcessor(final RouteContext routeContext) throws Exception { 084 // create the detour 085 final Processor detour = this.createChildProcessor(routeContext, true); 086 087 // register endpoint callback so we can proxy the endpoint 088 routeContext.getCamelContext().addRegisterEndpointCallback(new EndpointStrategy() { 089 public Endpoint registerEndpoint(String uri, Endpoint endpoint) { 090 if (endpoint instanceof InterceptSendToEndpoint) { 091 // endpoint already decorated 092 return endpoint; 093 } else if (getUri() == null || EndpointHelper.matchEndpoint(routeContext.getCamelContext(), uri, getUri())) { 094 // only proxy if the uri is matched decorate endpoint with our proxy 095 // should be false by default 096 boolean skip = isSkipSendToOriginalEndpoint(); 097 InterceptSendToEndpoint proxy = new InterceptSendToEndpoint(endpoint, skip); 098 proxy.setDetour(detour); 099 return proxy; 100 } else { 101 // no proxy so return regular endpoint 102 return endpoint; 103 } 104 } 105 }); 106 107 108 // remove the original intercepted route from the outputs as we do not intercept as the regular interceptor 109 // instead we use the proxy endpoints producer do the triggering. That is we trigger when someone sends 110 // an exchange to the endpoint, see InterceptSendToEndpoint for details. 111 RouteDefinition route = routeContext.getRoute(); 112 List<ProcessorDefinition<?>> outputs = route.getOutputs(); 113 outputs.remove(this); 114 115 return new InterceptEndpointProcessor(uri, detour); 116 } 117 118 /** 119 * Applies this interceptor only if the given predicate is true 120 * 121 * @param predicate the predicate 122 * @return the builder 123 */ 124 public InterceptSendToEndpointDefinition when(Predicate predicate) { 125 WhenDefinition when = new WhenDefinition(predicate); 126 addOutput(when); 127 return this; 128 } 129 130 /** 131 * Skip sending the {@link org.apache.camel.Exchange} to the original intended endpoint 132 * 133 * @return the builder 134 */ 135 public InterceptSendToEndpointDefinition skipSendToOriginalEndpoint() { 136 setSkipSendToOriginalEndpoint(Boolean.TRUE); 137 return this; 138 } 139 140 /** 141 * This method is <b>only</b> for handling some post configuration 142 * that is needed since this is an interceptor, and we have to do 143 * a bit of magic logic to fixup to handle predicates 144 * with or without proceed/stop set as well. 145 */ 146 public void afterPropertiesSet() { 147 // okay the intercept endpoint works a bit differently than the regular interceptors 148 // so we must fix the route definition yet again 149 150 if (getOutputs().size() == 0) { 151 // no outputs 152 return; 153 } 154 155 // if there is a when definition at first, then its a predicate for this interceptor 156 ProcessorDefinition<?> first = getOutputs().get(0); 157 if (first instanceof WhenDefinition && !(first instanceof WhenSkipSendToEndpointDefinition)) { 158 WhenDefinition when = (WhenDefinition) first; 159 160 // create a copy of when to use as replacement 161 WhenSkipSendToEndpointDefinition newWhen = new WhenSkipSendToEndpointDefinition(); 162 newWhen.setExpression(when.getExpression()); 163 newWhen.setId(when.getId()); 164 newWhen.setInheritErrorHandler(when.isInheritErrorHandler()); 165 newWhen.setParent(when.getParent()); 166 newWhen.setOtherAttributes(when.getOtherAttributes()); 167 newWhen.setNodeFactory(when.getNodeFactory()); 168 newWhen.setDescription(when.getDescription()); 169 170 // move this outputs to the when, expect the first one 171 // as the first one is the interceptor itself 172 for (int i = 1; i < outputs.size(); i++) { 173 ProcessorDefinition<?> out = outputs.get(i); 174 newWhen.addOutput(out); 175 } 176 // remove the moved from the original output, by just keeping the first one 177 clearOutput(); 178 outputs.add(newWhen); 179 } 180 } 181 182 public Boolean getSkipSendToOriginalEndpoint() { 183 return skipSendToOriginalEndpoint; 184 } 185 186 public void setSkipSendToOriginalEndpoint(Boolean skipSendToOriginalEndpoint) { 187 this.skipSendToOriginalEndpoint = skipSendToOriginalEndpoint; 188 } 189 190 public boolean isSkipSendToOriginalEndpoint() { 191 return skipSendToOriginalEndpoint != null && skipSendToOriginalEndpoint; 192 } 193 194 public String getUri() { 195 return uri; 196 } 197 198 public void setUri(String uri) { 199 this.uri = uri; 200 } 201 }