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