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.ArrayList;
020    import java.util.Collections;
021    import java.util.LinkedHashMap;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import org.apache.camel.CamelContext;
027    import org.apache.camel.Component;
028    import org.apache.camel.EndpointConfiguration;
029    import org.apache.camel.TypeConverter;
030    import org.apache.camel.util.UnsafeUriCharactersEncoder;
031    
032    /**
033     * Fallback implementation of {@link EndpointConfiguration} used by {@link Component}s
034     * that did not yet define a configuration type.
035     */
036    public final class MappedEndpointConfiguration extends DefaultEndpointConfiguration {
037        // TODO: need 2 sets to differentiate between user keys and fixed keys
038        private Map<String, Object> params = new LinkedHashMap<String, Object>();
039    
040        MappedEndpointConfiguration(CamelContext camelContext) {
041            super(camelContext);
042        }
043    
044        MappedEndpointConfiguration(CamelContext camelContext, String uri) {
045            super(camelContext);
046            setURI(uri);
047        }
048    
049        @SuppressWarnings("unchecked")
050        public <T> T getParameter(String name) {
051            return (T) params.get(name);
052        }
053    
054        @Override
055        public <T> void setParameter(String name, T value) {
056            params.put(name, value);
057        }
058        
059        @Override
060        public boolean equals(Object other) {
061            if (other == null || !(other instanceof MappedEndpointConfiguration)) {
062                return false;
063            }
064            // if all parameters including scheme are the same, the component and uri must be the same too
065            return this == other || (this.getClass() == other.getClass() && params.equals(((MappedEndpointConfiguration)other).params));
066        }
067    
068        @Override
069        public int hashCode() {
070            return params.hashCode();
071        }
072    
073        @Override
074        protected void parseURI() {
075            ConfigurationHelper.populateFromURI(getCamelContext(), this, new ConfigurationHelper.ParameterSetter() {
076                @Override
077                public <T> void set(CamelContext camelContext, EndpointConfiguration config, String name, T value) {
078                    if (name != null && value != null) {
079                        params.put(name, value);
080                    }
081                }
082            });
083        }
084    
085        @Override
086        public String toUriString(UriFormat format) {
087            Set<Map.Entry<String, Object>> entries = params.entrySet();
088            List<String> queryParams = new ArrayList<String>();
089            
090            String scheme = null;
091            String schemeSpecificPart = null;
092            String authority = null;
093            String path = null;
094            String fragment = null;
095    
096            TypeConverter converter = getCamelContext().getTypeConverter();
097    
098            // Separate URI values from query parameters
099            for (Map.Entry<String, Object> entry : entries) {
100                String key = entry.getKey();
101                Object value = entry.getValue();
102                if (key.equals(EndpointConfiguration.URI_SCHEME)) {
103                    scheme = converter.convertTo(String.class, value);
104                } else if (key.equals(EndpointConfiguration.URI_SCHEME_SPECIFIC_PART)) {
105                    schemeSpecificPart = converter.convertTo(String.class, value);
106                } else if (key.equals(EndpointConfiguration.URI_AUTHORITY)) {
107                    authority = converter.convertTo(String.class, value);
108                } else if (key.equals(EndpointConfiguration.URI_USER_INFO)) {
109                    // ignore, part of authority
110                } else if (key.equals(EndpointConfiguration.URI_HOST)) {
111                    // ignore, part of authority
112                } else if (key.equals(EndpointConfiguration.URI_PORT)) {
113                    // ignore, part of authority
114                } else if (key.equals(EndpointConfiguration.URI_PATH)) {
115                    path = converter.convertTo(String.class, value);
116                } else if (key.equals(EndpointConfiguration.URI_QUERY)) {
117                    // ignore, but this should not be the case, may be a good idea to log...
118                } else if (key.equals(EndpointConfiguration.URI_FRAGMENT)) {
119                    fragment = converter.convertTo(String.class, value);
120                } else {
121                    // convert to "param=value" format here, order will be preserved
122                    if (value instanceof List) {
123                        for (Object item : (List<?>)value) {
124                            queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(item.toString()));
125                        }
126                    } else {
127                        queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(value.toString()));
128                    }
129                }
130            }
131    
132            Collections.sort(queryParams);
133            String q = "";
134            for (String entry : queryParams) {
135                q += q.length() == 0 ? "" : "&";
136                q += entry;
137            }
138    
139            StringBuilder u = new StringBuilder(64);
140            if (scheme != null) {
141                u.append(scheme); // SHOULD NOT be null
142                u.append(":");
143            }
144            if (authority != null) {
145                u.append("//");
146                u.append(authority);
147                u.append(path);
148                if (q.length() > 0) {
149                    u.append("?");
150                    u.append(q);
151                }
152                if (fragment != null) {
153                    u.append("#");
154                    u.append(fragment);
155                }
156            } else {
157                // add leading // if not provided
158                if (!schemeSpecificPart.startsWith("//")) {
159                    u.append("//");
160                }
161                u.append(schemeSpecificPart);
162            }
163            return u.toString();
164        }
165    }