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.cloud; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlElementRef; 026import javax.xml.bind.annotation.XmlRootElement; 027import javax.xml.bind.annotation.XmlTransient; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.Expression; 031import org.apache.camel.ExtendedCamelContext; 032import org.apache.camel.NoFactoryAvailableException; 033import org.apache.camel.cloud.ServiceCallConstants; 034import org.apache.camel.cloud.ServiceExpressionFactory; 035import org.apache.camel.model.ProcessorDefinition; 036import org.apache.camel.model.language.ExpressionDefinition; 037import org.apache.camel.spi.Metadata; 038import org.apache.camel.support.CamelContextHelper; 039import org.apache.camel.support.PropertyBindingSupport; 040 041@Metadata(label = "routing,cloud") 042@XmlRootElement(name = "serviceExpression") 043@XmlAccessorType(XmlAccessType.FIELD) 044public class ServiceCallExpressionConfiguration extends ServiceCallConfiguration implements ServiceExpressionFactory { 045 @XmlTransient 046 private final ServiceCallDefinition parent; 047 @XmlTransient 048 private final String factoryKey; 049 @XmlAttribute 050 @Metadata(defaultValue = ServiceCallConstants.SERVICE_HOST) 051 private String hostHeader = ServiceCallConstants.SERVICE_HOST; 052 @XmlAttribute 053 @Metadata(defaultValue = ServiceCallConstants.SERVICE_PORT) 054 private String portHeader = ServiceCallConstants.SERVICE_PORT; 055 @XmlElementRef(required = false) 056 private ExpressionDefinition expressionType; 057 @XmlTransient 058 private Expression expression; 059 060 public ServiceCallExpressionConfiguration() { 061 this(null, null); 062 } 063 064 public ServiceCallExpressionConfiguration(ServiceCallDefinition parent, String factoryKey) { 065 this.parent = parent; 066 this.factoryKey = factoryKey; 067 } 068 069 public ServiceCallDefinition end() { 070 return this.parent; 071 } 072 073 public ProcessorDefinition<?> endParent() { 074 return this.parent.end(); 075 } 076 077 // ************************************************************************* 078 // 079 // ************************************************************************* 080 081 public ServiceCallServiceChooserConfiguration property(String key, String value) { 082 return (ServiceCallServiceChooserConfiguration) super.property(key, value); 083 } 084 085 public String getHostHeader() { 086 return hostHeader; 087 } 088 089 /** 090 * The header that holds the service host information, default 091 * ServiceCallConstants.SERVICE_HOST 092 */ 093 public void setHostHeader(String hostHeader) { 094 this.hostHeader = hostHeader; 095 } 096 097 public String getPortHeader() { 098 return portHeader; 099 } 100 101 /** 102 * The header that holds the service port information, default 103 * ServiceCallConstants.SERVICE_PORT 104 */ 105 public void setPortHeader(String portHeader) { 106 this.portHeader = portHeader; 107 } 108 109 public ExpressionDefinition getExpressionType() { 110 return expressionType; 111 } 112 113 public void setExpressionType(ExpressionDefinition expressionType) { 114 this.expressionType = expressionType; 115 } 116 117 public Expression getExpression() { 118 return expression; 119 } 120 121 public void setExpression(Expression expression) { 122 this.expression = expression; 123 } 124 125 /** 126 * The header that holds the service host information, default 127 * ServiceCallConstants.SERVICE_HOST 128 */ 129 public ServiceCallExpressionConfiguration hostHeader(String hostHeader) { 130 setHostHeader(hostHeader); 131 return this; 132 } 133 134 /** 135 * The header that holds the service port information, default 136 * ServiceCallConstants.SERVICE_PORT 137 */ 138 public ServiceCallExpressionConfiguration portHeader(String portHeader) { 139 setPortHeader(portHeader); 140 return this; 141 } 142 143 public ServiceCallExpressionConfiguration expressionType(ExpressionDefinition expressionType) { 144 setExpressionType(expressionType); 145 return this; 146 } 147 148 public ServiceCallExpressionConfiguration expression(Expression expression) { 149 setExpression(expression); 150 return this; 151 } 152 153 // ************************************************************************* 154 // Factory 155 // ************************************************************************* 156 157 @Override 158 public Expression newInstance(CamelContext camelContext) throws Exception { 159 Expression answer = getExpression(); 160 if (answer != null) { 161 return answer; 162 } 163 164 ExpressionDefinition expressionType = getExpressionType(); 165 if (expressionType != null && answer == null) { 166 return expressionType.createExpression(camelContext); 167 } 168 169 if (factoryKey != null) { 170 // First try to find the factory from the registry. 171 ServiceExpressionFactory factory = CamelContextHelper.lookup(camelContext, factoryKey, ServiceExpressionFactory.class); 172 if (factory != null) { 173 // If a factory is found in the registry do not re-configure it 174 // as 175 // it should be pre-configured. 176 answer = factory.newInstance(camelContext); 177 } else { 178 179 Class<?> type; 180 try { 181 // Then use Service factory. 182 type = camelContext.adapt(ExtendedCamelContext.class).getFactoryFinder(ServiceCallDefinitionConstants.RESOURCE_PATH).findClass(factoryKey).orElse(null); 183 } catch (Exception e) { 184 throw new NoFactoryAvailableException(ServiceCallDefinitionConstants.RESOURCE_PATH + factoryKey, e); 185 } 186 187 if (type != null) { 188 if (ServiceExpressionFactory.class.isAssignableFrom(type)) { 189 factory = (ServiceExpressionFactory)camelContext.getInjector().newInstance(type, false); 190 } else { 191 throw new IllegalArgumentException("Resolving Expression: " + factoryKey + " detected type conflict: Not a ExpressionFactory implementation. Found: " 192 + type.getName()); 193 } 194 } 195 196 try { 197 Map<String, Object> parameters = new HashMap<>(); 198 camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection().getProperties(this, parameters, null, false); 199 200 parameters.replaceAll((k, v) -> { 201 if (v instanceof String) { 202 try { 203 v = camelContext.resolvePropertyPlaceholders((String)v); 204 } catch (Exception e) { 205 throw new IllegalArgumentException(String.format("Exception while resolving %s (%s)", k, v.toString()), e); 206 } 207 } 208 209 return v; 210 }); 211 212 // Convert properties to Map<String, String> 213 parameters.put("properties", getPropertiesAsMap(camelContext)); 214 215 postProcessFactoryParameters(camelContext, parameters); 216 217 PropertyBindingSupport.build().bind(camelContext, factory, parameters); 218 219 answer = factory.newInstance(camelContext); 220 } catch (Exception e) { 221 throw new IllegalArgumentException(e); 222 } 223 } 224 } 225 226 return answer; 227 } 228 229}