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.component.properties;
018    
019    import java.io.FileInputStream;
020    import java.io.FileNotFoundException;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.util.Map;
024    import java.util.Properties;
025    
026    import org.apache.camel.CamelContext;
027    import org.apache.camel.util.IOHelper;
028    import org.apache.camel.util.ObjectHelper;
029    
030    /**
031     * Default {@link org.apache.camel.component.properties.PropertiesResolver} which can resolve properties
032     * from file and classpath.
033     * <p/>
034     * You can denote <tt>classpath:</tt> or <tt>file:</tt> as prefix in the uri to select whether the file
035     * is located in the classpath or on the file system.
036     *
037     * @version 
038     */
039    public class DefaultPropertiesResolver implements PropertiesResolver {
040    
041        public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
042            Properties answer = new Properties();
043    
044            for (String path : uri) {
045                if (path.startsWith("ref:")) {
046                    Properties prop = loadPropertiesFromRegistry(context, ignoreMissingLocation, path);
047                    prop = prepareLoadedProperties(prop);
048                    answer.putAll(prop);
049                } else if (path.startsWith("file:")) {
050                    Properties prop = loadPropertiesFromFilePath(context, ignoreMissingLocation, path);
051                    prop = prepareLoadedProperties(prop);
052                    answer.putAll(prop);
053                } else {
054                    // default to classpath
055                    Properties prop = loadPropertiesFromClasspath(context, ignoreMissingLocation, path);
056                    prop = prepareLoadedProperties(prop);
057                    answer.putAll(prop);
058                }
059            }
060    
061            return answer;
062        }
063    
064        protected Properties loadPropertiesFromFilePath(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
065            Properties answer = new Properties();
066    
067            if (path.startsWith("file:")) {
068                path = ObjectHelper.after(path, "file:");
069            }
070    
071            InputStream is = null;
072            try {
073                is = new FileInputStream(path);
074                answer.load(is);
075            } catch (FileNotFoundException e) {
076                if (!ignoreMissingLocation) {
077                    throw e;
078                }
079            } finally {
080                IOHelper.close(is);
081            }
082    
083            return answer;
084        }
085    
086        protected Properties loadPropertiesFromClasspath(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
087            Properties answer = new Properties();
088    
089            if (path.startsWith("classpath:")) {
090                path = ObjectHelper.after(path, "classpath:");
091            }
092    
093            InputStream is = context.getClassResolver().loadResourceAsStream(path);
094            if (is == null) {
095                if (!ignoreMissingLocation) {
096                    throw new FileNotFoundException("Properties file " + path + " not found in classpath");
097                }
098            } else {
099                try {
100                    answer.load(is);
101                } finally {
102                    IOHelper.close(is);
103                }
104            }
105            return answer;
106        }
107    
108        protected Properties loadPropertiesFromRegistry(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
109            if (path.startsWith("ref:")) {
110                path = ObjectHelper.after(path, "ref:");
111            }
112            Properties answer = context.getRegistry().lookup(path, Properties.class);
113            if (answer == null && (!ignoreMissingLocation)) {
114                throw new FileNotFoundException("Properties " + path + " not found in registry");
115            }
116            return answer != null ? answer : new Properties();
117        }
118    
119        /**
120         * Strategy to prepare loaded properties before being used by Camel.
121         * <p/>
122         * This implementation will ensure values are trimmed, as loading properties from
123         * a file with values having trailing spaces is not automatic trimmed by the Properties API
124         * from the JDK.
125         *
126         * @param properties  the properties
127         * @return the prepared properties
128         */
129        protected Properties prepareLoadedProperties(Properties properties) {
130            Properties answer = new Properties();
131            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
132                Object key = entry.getKey();
133                Object value = entry.getValue();
134                if (value instanceof String) {
135                    String s = (String) value;
136    
137                    // trim any trailing spaces which can be a problem when loading from
138                    // a properties file, note that java.util.Properties does already this
139                    // for any potential leading spaces so there's nothing to do there
140                    value = trimTrailingWhitespaces(s);
141                }
142                answer.put(key, value);
143            }
144            return answer;
145        }
146    
147        private static String trimTrailingWhitespaces(String s) {
148            int endIndex = s.length();
149            for (int index = s.length() - 1; index >= 0; index--) {
150                if (s.charAt(index) == ' ') {
151                    endIndex = index;
152                } else {
153                    break;
154                }
155            }
156            String answer = s.substring(0, endIndex);
157            return answer;
158        }
159    
160    }