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