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 boolean isTopLevelOnly() { 084 return true; 085 } 086 087 @Override 088 public Processor createProcessor(final RouteContext routeContext) throws Exception { 089 // create the detour 090 final Processor detour = this.createChildProcessor(routeContext, true); 091 092 // register endpoint callback so we can proxy the endpoint 093 routeContext.getCamelContext().addRegisterEndpointCallback(new EndpointStrategy() { 094 public Endpoint registerEndpoint(String uri, Endpoint endpoint) { 095 if (endpoint instanceof InterceptSendToEndpoint) { 096 // endpoint already decorated 097 return endpoint; 098 } else if (getUri() == null || EndpointHelper.matchEndpoint(routeContext.getCamelContext(), uri, getUri())) { 099 // only proxy if the uri is matched decorate endpoint with our proxy 100 // should be false by default 101 boolean skip = isSkipSendToOriginalEndpoint(); 102 InterceptSendToEndpoint proxy = new InterceptSendToEndpoint(endpoint, skip); 103 proxy.setDetour(detour); 104 return proxy; 105 } else { 106 // no proxy so return regular endpoint 107 return endpoint; 108 } 109 } 110 }); 111 112 113 // remove the original intercepted route from the outputs as we do not intercept as the regular interceptor 114 // instead we use the proxy endpoints producer do the triggering. That is we trigger when someone sends 115 // an exchange to the endpoint, see InterceptSendToEndpoint for details. 116 RouteDefinition route = routeContext.getRoute(); 117 List<ProcessorDefinition<?>> outputs = route.getOutputs(); 118 outputs.remove(this); 119 120 return new InterceptEndpointProcessor(uri, detour); 121 } 122 123 /** 124 * Applies this interceptor only if the given predicate is true 125 * 126 * @param predicate the predicate 127 * @return the builder 128 */ 129 public InterceptSendToEndpointDefinition when(Predicate predicate) { 130 WhenDefinition when = new WhenDefinition(predicate); 131 addOutput(when); 132 return this; 133 } 134 135 /** 136 * Skip sending the {@link org.apache.camel.Exchange} to the original intended endpoint 137 * 138 * @return the builder 139 */ 140 public InterceptSendToEndpointDefinition skipSendToOriginalEndpoint() { 141 setSkipSendToOriginalEndpoint(Boolean.TRUE); 142 return this; 143 } 144 145 /** 146 * This method is <b>only</b> for handling some post configuration 147 * that is needed since this is an interceptor, and we have to do 148 * a bit of magic logic to fixup to handle predicates 149 * with or without proceed/stop set as well. 150 */ 151 public void afterPropertiesSet() { 152 // okay the intercept endpoint works a bit differently than the regular interceptors 153 // so we must fix the route definition yet again 154 155 if (getOutputs().size() == 0) { 156 // no outputs 157 return; 158 } 159 160 // if there is a when definition at first, then its a predicate for this interceptor 161 ProcessorDefinition<?> first = getOutputs().get(0); 162 if (first instanceof WhenDefinition && !(first instanceof WhenSkipSendToEndpointDefinition)) { 163 WhenDefinition when = (WhenDefinition) first; 164 165 // create a copy of when to use as replacement 166 WhenSkipSendToEndpointDefinition newWhen = new WhenSkipSendToEndpointDefinition(); 167 newWhen.setExpression(when.getExpression()); 168 newWhen.setId(when.getId()); 169 newWhen.setInheritErrorHandler(when.isInheritErrorHandler()); 170 newWhen.setParent(when.getParent()); 171 newWhen.setOtherAttributes(when.getOtherAttributes()); 172 newWhen.setDescription(when.getDescription()); 173 174 // move this outputs to the when, expect the first one 175 // as the first one is the interceptor itself 176 for (int i = 1; i < outputs.size(); i++) { 177 ProcessorDefinition<?> out = outputs.get(i); 178 newWhen.addOutput(out); 179 } 180 // remove the moved from the original output, by just keeping the first one 181 clearOutput(); 182 outputs.add(newWhen); 183 } 184 } 185 186 public Boolean getSkipSendToOriginalEndpoint() { 187 return skipSendToOriginalEndpoint; 188 } 189 190 public void setSkipSendToOriginalEndpoint(Boolean skipSendToOriginalEndpoint) { 191 this.skipSendToOriginalEndpoint = skipSendToOriginalEndpoint; 192 } 193 194 public boolean isSkipSendToOriginalEndpoint() { 195 return skipSendToOriginalEndpoint != null && skipSendToOriginalEndpoint; 196 } 197 198 public String getUri() { 199 return uri; 200 } 201 202 public void setUri(String uri) { 203 this.uri = uri; 204 } 205 }