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.XmlRootElement;
025import javax.xml.bind.annotation.XmlTransient;
026
027import org.apache.camel.CamelContext;
028import org.apache.camel.ExtendedCamelContext;
029import org.apache.camel.NoFactoryAvailableException;
030import org.apache.camel.cloud.ServiceChooser;
031import org.apache.camel.cloud.ServiceChooserFactory;
032import org.apache.camel.model.ProcessorDefinition;
033import org.apache.camel.spi.Metadata;
034import org.apache.camel.support.CamelContextHelper;
035import org.apache.camel.support.PropertyBindingSupport;
036import org.apache.camel.util.ObjectHelper;
037
038@Metadata(label = "routing,cloud,service-discovery")
039@XmlRootElement(name = "serviceChooserConfiguration")
040@XmlAccessorType(XmlAccessType.FIELD)
041public class ServiceCallServiceChooserConfiguration extends ServiceCallConfiguration implements ServiceChooserFactory {
042    @XmlTransient
043    private final ServiceCallDefinition parent;
044    @XmlTransient
045    private final String factoryKey;
046
047    public ServiceCallServiceChooserConfiguration() {
048        this(null, null);
049    }
050
051    public ServiceCallServiceChooserConfiguration(ServiceCallDefinition parent, String factoryKey) {
052        this.parent = parent;
053        this.factoryKey = factoryKey;
054    }
055
056    public ServiceCallDefinition end() {
057        return this.parent;
058    }
059
060    public ProcessorDefinition<?> endParent() {
061        return this.parent.end();
062    }
063
064    // *************************************************************************
065    //
066    // *************************************************************************
067
068    public ServiceCallServiceChooserConfiguration property(String key, String value) {
069        return (ServiceCallServiceChooserConfiguration) super.property(key, value);
070    }
071
072    // *************************************************************************
073    // Factory
074    // *************************************************************************
075
076    @Override
077    public ServiceChooser newInstance(CamelContext camelContext) throws Exception {
078        ObjectHelper.notNull(factoryKey, "ServiceChooser factoryKey");
079
080        ServiceChooser answer;
081
082        // First try to find the factory from the registry.
083        ServiceChooserFactory factory = CamelContextHelper.lookup(camelContext, factoryKey, ServiceChooserFactory.class);
084        if (factory != null) {
085            // If a factory is found in the registry do not re-configure it as
086            // it should be pre-configured.
087            answer = factory.newInstance(camelContext);
088        } else {
089
090            Class<?> type;
091            try {
092                // Then use Service factory.
093                type = camelContext.adapt(ExtendedCamelContext.class).getFactoryFinder(ServiceCallDefinitionConstants.RESOURCE_PATH).findClass(factoryKey).orElse(null);
094            } catch (Exception e) {
095                throw new NoFactoryAvailableException(ServiceCallDefinitionConstants.RESOURCE_PATH + factoryKey, e);
096            }
097
098            if (type != null) {
099                if (ServiceChooserFactory.class.isAssignableFrom(type)) {
100                    factory = (ServiceChooserFactory)camelContext.getInjector().newInstance(type, false);
101                } else {
102                    throw new NoFactoryAvailableException("Resolving ServiceChooser: " + factoryKey + " detected type conflict: Not a ServiceChooserFactory implementation. Found: "
103                                                          + type.getName());
104                }
105            }
106
107            try {
108                Map<String, Object> parameters = new HashMap<>();
109                camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection().getProperties(this, parameters, null, false);
110
111                parameters.replaceAll((k, v) -> {
112                    if (v instanceof String) {
113                        try {
114                            v = camelContext.resolvePropertyPlaceholders((String)v);
115                        } catch (Exception e) {
116                            throw new IllegalArgumentException(String.format("Exception while resolving %s (%s)", k, v.toString()), e);
117                        }
118                    }
119
120                    return v;
121                });
122
123                // Convert properties to Map<String, String>
124                parameters.put("properties", getPropertiesAsMap(camelContext));
125
126                postProcessFactoryParameters(camelContext, parameters);
127
128                PropertyBindingSupport.build().bind(camelContext, factory, parameters);
129
130                answer = factory.newInstance(camelContext);
131            } catch (Exception e) {
132                throw new IllegalArgumentException(e);
133            }
134        }
135
136        return answer;
137    }
138
139}