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;
018
019import java.util.Collections;
020import java.util.SortedMap;
021
022import org.apache.camel.CamelContext;
023import org.apache.camel.Component;
024import org.apache.camel.Endpoint;
025import org.apache.camel.InvalidPropertyException;
026import org.apache.camel.RuntimeCamelException;
027import org.apache.camel.util.IntrospectionSupport;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031/**
032 * Implements {@link org.apache.camel.EndpointConfiguration} for Endpoint implementations
033 * which are annotated with {@link org.apache.camel.spi.UriEndpoint}
034 * to use the {@link org.apache.camel.spi.UriParam} and {@link org.apache.camel.spi.UriParams} annotations
035 * to denote its parameters which can be specified via URI query parameters.
036 */
037public class UriComponentConfiguration extends ComponentConfigurationSupport {
038    private static final Logger LOG = LoggerFactory.getLogger(UriComponentConfiguration.class);
039
040    private final Class<? extends Endpoint> endpointClass;
041    private final SortedMap<String, ParameterConfiguration> parameterConfigurationMap;
042    private boolean strictOnParameterNames = true;
043
044    public UriComponentConfiguration(Component component, Class<? extends Endpoint> endpointClass,
045                                     SortedMap<String, ParameterConfiguration> parameterConfigurationMap) {
046        super(component);
047        this.endpointClass = endpointClass;
048        this.parameterConfigurationMap = Collections.unmodifiableSortedMap(parameterConfigurationMap);
049    }
050
051    public UriComponentConfiguration(Component component, Class<? extends Endpoint> endpointClass) {
052        this(component, endpointClass, UriEndpointComponent.createParameterConfigurationMap(endpointClass));
053    }
054
055    public UriComponentConfiguration(UriEndpointComponent component) {
056        this(component, component.getEndpointClass(), component.getParameterConfigurationMap());
057    }
058
059    @Override
060    public Object getEndpointParameter(Endpoint endpoint, String name) throws RuntimeCamelException {
061        ParameterConfiguration config = getParameterConfiguration(name);
062
063        // lets try get the property regardless of if this maps to a valid property name
064        // then if the introspection fails we will get a valid error otherwise
065        // lets raise a warning afterwards that we should update the metadata on the endpoint class
066        Object answer = null;
067        try {
068            answer = IntrospectionSupport.getProperty(endpoint, name);
069        } catch (Exception e) {
070            throw new RuntimeCamelException(
071                    "Failed to get property '" + name + "' on " + endpoint + " due " + e.getMessage(), e);
072        }
073        if (config == null) {
074            unknownPropertyName(name);
075        }
076        return answer;
077    }
078
079    @Override
080    public void setEndpointParameter(Endpoint endpoint, String name, Object value) throws RuntimeCamelException {
081        ParameterConfiguration config = getParameterConfiguration(name);
082
083        // lets try set the property regardless of if this maps to a valid property name
084        // then if the injection fails we will get a valid error otherwise
085        // lets raise a warning afterwards that we should update the metadata on the endpoint class
086        try {
087            IntrospectionSupport.setProperty(endpoint, name, value);
088        } catch (Exception e) {
089            throw new RuntimeCamelException("Failed to set property '" + name + "' on " + endpoint + " to value "
090                    + value + " due " + e.getMessage(), e);
091        }
092        if (config == null) {
093            unknownPropertyName(name);
094        }
095    }
096
097    public CamelContext getCamelContext() {
098        return component.getCamelContext();
099    }
100
101    public Class<? extends Endpoint> getEndpointClass() {
102        return endpointClass;
103    }
104
105    public boolean isStrictOnParameterNames() {
106        return strictOnParameterNames;
107    }
108
109    /**
110     * Strict mode is enabled by default but if disabled then invalid parameter names
111     * will not result in exceptions but we will just log warnings about their use
112     *
113     * @param strictOnParameterNames whether to throw exceptions if invalid
114     *                               parameter names are used or not
115     */
116    public void setStrictOnParameterNames(boolean strictOnParameterNames) {
117        this.strictOnParameterNames = strictOnParameterNames;
118    }
119
120    @Override
121    public SortedMap<String, ParameterConfiguration> getParameterConfigurationMap() {
122        return parameterConfigurationMap;
123    }
124
125    @Override
126    protected void validatePropertyName(String name) {
127        ParameterConfiguration parameterConfiguration = getParameterConfiguration(name);
128        if (parameterConfiguration == null) {
129            unknownPropertyName(name);
130        }
131    }
132
133    @Override
134    protected Object validatePropertyValue(String name, Object value) {
135        ParameterConfiguration parameterConfiguration = getParameterConfiguration(name);
136        if (parameterConfiguration == null) {
137            unknownPropertyName(name);
138            return value;
139        } else {
140            Class<?> parameterType = parameterConfiguration.getParameterType();
141            return getCamelContext().getTypeConverter().convertTo(parameterType, value);
142        }
143    }
144
145    protected void unknownPropertyName(String name) {
146        if (isStrictOnParameterNames()) {
147            throw new InvalidPropertyException(this, name, endpointClass);
148        } else {
149            LOG.warn("Using parameter " + name + " on endpoint " + getEndpointClass().getName()
150                    + " which does not have a @UriParam annotation! "
151                    + "Please add the @UriParam annotation to the " + name + " field");
152        }
153    }
154
155}