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     */
017    package org.apache.camel.impl;
018    
019    import java.util.Collections;
020    import java.util.SortedMap;
021    
022    import org.apache.camel.CamelContext;
023    import org.apache.camel.Component;
024    import org.apache.camel.Endpoint;
025    import org.apache.camel.InvalidPropertyException;
026    import org.apache.camel.RuntimeCamelException;
027    import org.apache.camel.util.IntrospectionSupport;
028    import org.slf4j.Logger;
029    import 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     */
037    public 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    }