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.ArrayList;
020import java.util.Collections;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.camel.CamelContext;
027import org.apache.camel.Component;
028import org.apache.camel.EndpointConfiguration;
029import org.apache.camel.TypeConverter;
030import 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 */
036public 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}