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.impl.cloud; 018 019import org.apache.camel.AsyncCallback; 020import org.apache.camel.AsyncProcessor; 021import org.apache.camel.CamelContext; 022import org.apache.camel.Exchange; 023import org.apache.camel.ExchangePattern; 024import org.apache.camel.Expression; 025import org.apache.camel.Message; 026import org.apache.camel.cloud.ServiceDefinition; 027import org.apache.camel.cloud.ServiceLoadBalancer; 028import org.apache.camel.processor.SendDynamicProcessor; 029import org.apache.camel.support.ServiceSupport; 030import org.apache.camel.util.AsyncProcessorHelper; 031import org.apache.camel.util.ObjectHelper; 032import org.apache.camel.util.ServiceHelper; 033import org.apache.camel.util.StringHelper; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037public class DefaultServiceCallProcessor extends ServiceSupport implements AsyncProcessor { 038 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultServiceCallProcessor.class); 039 040 private final ExchangePattern exchangePattern; 041 private final String name; 042 private final String scheme; 043 private final String uri; 044 private final String contextPath; 045 private final CamelContext camelContext; 046 private final ServiceLoadBalancer loadBalancer; 047 private final Expression expression; 048 private SendDynamicProcessor processor; 049 050 public DefaultServiceCallProcessor( 051 CamelContext camelContext, String name, String scheme, String uri, ExchangePattern exchangePattern, 052 ServiceLoadBalancer loadBalancer, Expression expression) { 053 054 this.uri = uri; 055 this.exchangePattern = exchangePattern; 056 this.camelContext = camelContext; 057 this.loadBalancer = loadBalancer; 058 059 // setup from the provided name which can contain scheme and context-path information as well 060 String serviceName; 061 if (name.contains("/")) { 062 serviceName = StringHelper.before(name, "/"); 063 this.contextPath = StringHelper.after(name, "/"); 064 } else if (name.contains("?")) { 065 serviceName = StringHelper.before(name, "?"); 066 this.contextPath = StringHelper.after(name, "?"); 067 } else { 068 serviceName = name; 069 this.contextPath = null; 070 } 071 if (serviceName.contains(":")) { 072 this.scheme = StringHelper.before(serviceName, ":"); 073 this.name = StringHelper.after(serviceName, ":"); 074 } else { 075 this.scheme = scheme; 076 this.name = serviceName; 077 } 078 079 this.expression = expression; 080 } 081 082 // ************************************* 083 // Properties 084 // ************************************* 085 086 087 public ExchangePattern getExchangePattern() { 088 return exchangePattern; 089 } 090 091 public String getName() { 092 return name; 093 } 094 095 public String getScheme() { 096 return scheme; 097 } 098 099 public String getUri() { 100 return uri; 101 } 102 103 public String getContextPath() { 104 return contextPath; 105 } 106 107 public ServiceLoadBalancer getLoadBalancer() { 108 return loadBalancer; 109 } 110 111 public Expression getExpression() { 112 return expression; 113 } 114 115 // ************************************* 116 // Lifecycle 117 // ************************************* 118 119 @Override 120 protected void doStart() throws Exception { 121 StringHelper.notEmpty(name, "name", "service name"); 122 ObjectHelper.notNull(camelContext, "camel context"); 123 ObjectHelper.notNull(expression, "expression"); 124 ObjectHelper.notNull(loadBalancer, "load balancer"); 125 126 processor = new SendDynamicProcessor(uri, expression); 127 processor.setCamelContext(camelContext); 128 if (exchangePattern != null) { 129 processor.setPattern(exchangePattern); 130 } 131 132 // Start services if needed 133 ServiceHelper.startService(processor); 134 ServiceHelper.startService(loadBalancer); 135 } 136 137 @Override 138 protected void doStop() throws Exception { 139 // Stop services if needed 140 ServiceHelper.stopService(loadBalancer); 141 ServiceHelper.stopService(processor); 142 } 143 144 // ************************************* 145 // Processor 146 // ************************************* 147 148 149 @Override 150 public void process(Exchange exchange) throws Exception { 151 AsyncProcessorHelper.process(this, exchange); 152 } 153 154 @Override 155 public boolean process(final Exchange exchange, final AsyncCallback callback) { 156 Message message = exchange.getIn(); 157 message.setHeader(ServiceCallConstants.SERVICE_CALL_URI, uri); 158 message.setHeader(ServiceCallConstants.SERVICE_CALL_CONTEXT_PATH, contextPath); 159 message.setHeader(ServiceCallConstants.SERVICE_CALL_SCHEME, scheme); 160 161 String serviceName = message.getHeader(ServiceCallConstants.SERVICE_NAME, name, String.class); 162 163 try { 164 return loadBalancer.process(serviceName, server -> execute(server, exchange, callback)); 165 } catch (Exception e) { 166 exchange.setException(e); 167 return true; 168 } 169 } 170 171 private boolean execute(ServiceDefinition server, Exchange exchange, AsyncCallback callback) throws Exception { 172 String host = server.getHost(); 173 int port = server.getPort(); 174 175 LOGGER.debug("Service {} active at server: {}:{}", name, host, port); 176 177 // set selected server as header 178 exchange.getIn().setHeader(ServiceCallConstants.SERVICE_HOST, host); 179 exchange.getIn().setHeader(ServiceCallConstants.SERVICE_PORT, port > 0 ? port : null); 180 exchange.getIn().setHeader(ServiceCallConstants.SERVICE_NAME, server.getName()); 181 exchange.getIn().setHeader(ServiceCallConstants.SERVICE_META, server.getMetadata()); 182 183 // use the dynamic send processor to call the service 184 return processor.process(exchange, callback); 185 } 186}