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.xbean.finder;
018    
019    import java.io.BufferedInputStream;
020    import java.io.File;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.net.JarURLConnection;
024    import java.net.MalformedURLException;
025    import java.net.URL;
026    import java.util.ArrayList;
027    import java.util.Enumeration;
028    import java.util.HashMap;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Properties;
032    import java.util.Iterator;
033    import java.util.jar.JarEntry;
034    import java.util.jar.JarFile;
035    
036    public class ResourceFinder {
037    
038        private final String path;
039        private final ClassLoader classLoader;
040    
041        public ResourceFinder(String path) {
042            this(path, Thread.currentThread().getContextClassLoader());
043        }
044    
045        public ResourceFinder(String path, ClassLoader classLoader) {
046            this.path = path;
047            this.classLoader = classLoader;
048        }
049    
050    
051        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
052        //
053        //   Find String
054        //
055        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
056    
057        public String findString(String key) throws IOException {
058            String uri = path + key;
059    
060            URL resource = classLoader.getResource(uri);
061            if (resource == null) {
062                throw new IOException("Could not find command in : " + uri);
063            }
064    
065            return readContents(resource);
066        }
067    
068        public List<String> findAllStrings(String key) throws IOException {
069            String uri = path + key;
070    
071            List<String> strings = new ArrayList<String>();
072    
073            Enumeration<URL> resources = classLoader.getResources(uri);
074            while (resources.hasMoreElements()) {
075                URL url = resources.nextElement();
076                String string = readContents(url);
077                strings.add(string);
078            }
079            return strings;
080        }
081    
082        public List<String> findAvailableStrings(String key) throws IOException {
083            String uri = path + key;
084    
085            List<String> strings = new ArrayList<String>();
086    
087            Enumeration<URL> resources = classLoader.getResources(uri);
088            while (resources.hasMoreElements()) {
089                try {
090                    URL url = resources.nextElement();
091                    String string = readContents(url);
092                    strings.add(string);
093                } catch (Exception notAvailable) {
094                }
095            }
096            return strings;
097        }
098    
099        public Map<String,String> mapAllStrings(String key) throws IOException {
100            Map<String,String> strings = new HashMap<String,String>();
101            Map<String, URL> resourcesMap = getResourcesMap(key);
102            for (Iterator iterator = resourcesMap.entrySet().iterator(); iterator.hasNext();) {
103                Map.Entry entry = (Map.Entry) iterator.next();
104                String name = (String) entry.getKey();
105                URL url = (URL) entry.getValue();
106                String value = readContents(url);
107                strings.put(name,value);
108            }
109            return strings;
110        }
111    
112        public Map<String,String> mapAvailableStrings(String key) throws IOException {
113            Map<String,String> strings = new HashMap<String,String>();
114            Map<String, URL> resourcesMap = getResourcesMap(key);
115            for (Iterator iterator = resourcesMap.entrySet().iterator(); iterator.hasNext();) {
116                try {
117                    Map.Entry entry = (Map.Entry) iterator.next();
118                    String name = (String) entry.getKey();
119                    URL url = (URL) entry.getValue();
120                    String value = readContents(url);
121                    strings.put(name,value);
122                } catch (Exception notAvailable) {
123                }
124            }
125            return strings;
126        }
127    
128    
129        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
130        //
131        //   Find Class
132        //
133        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
134    
135        public Class findClass(String key) throws IOException, ClassNotFoundException {
136            String className = findString(key);
137            Class clazz = classLoader.loadClass(className);
138            return clazz;
139        }
140    
141        public List<Class> findAllClasses(String key) throws IOException, ClassNotFoundException {
142            List<Class> classes = new ArrayList<Class>();
143            List<String> strings = findAllStrings(key);
144            for (String className : strings) {
145                Class clazz = classLoader.loadClass(className);
146                classes.add(clazz);
147            }
148            return classes;
149        }
150    
151        public List<Class> findAvailableClasses(String key) throws IOException {
152            List<Class> classes = new ArrayList<Class>();
153            List<String> strings = findAvailableStrings(key);
154            for (String className : strings) {
155                try {
156                    Class clazz = classLoader.loadClass(className);
157                    classes.add(clazz);
158                } catch (Exception notAvailable) {
159                }
160            }
161            return classes;
162        }
163    
164        public Map<String, Class> mapAllClasses(String key) throws IOException, ClassNotFoundException {
165            Map<String, Class> classes = new HashMap<String, Class>();
166            Map<String, String> map = mapAllStrings(key);
167            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
168                Map.Entry entry = (Map.Entry) iterator.next();
169                String string = (String) entry.getKey();
170                String className = (String) entry.getValue();
171                Class clazz = classLoader.loadClass(className);
172                classes.put(string, clazz);
173            }
174            return classes;
175        }
176    
177        public Map<String, Class> mapAvailableClasses(String key) throws IOException {
178            Map<String, Class> classes = new HashMap<String, Class>();
179            Map<String, String> map = mapAvailableStrings(key);
180            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
181                try {
182                    Map.Entry entry = (Map.Entry) iterator.next();
183                    String string = (String) entry.getKey();
184                    String className = (String) entry.getValue();
185                    Class clazz = classLoader.loadClass(className);
186                    classes.put(string, clazz);
187                } catch (Exception notAvailable) {
188                }
189            }
190            return classes;
191        }
192    
193        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
194        //
195        //   Find Implementation
196        //
197        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
198    
199        public Class findImplementation(Class interfase) throws IOException, ClassNotFoundException {
200            String className = findString(interfase.getName());
201            Class impl = classLoader.loadClass(className);
202            if (!interfase.isAssignableFrom(impl)) {
203                throw new ClassCastException("Class not of type: " + interfase.getName());
204            }
205            return impl;
206        }
207    
208        public List<Class> findAllImplementations(Class interfase) throws IOException, ClassNotFoundException {
209            List<Class> implementations = new ArrayList<Class>();
210            List<String> strings = findAllStrings(interfase.getName());
211            for (String className : strings) {
212                Class impl = classLoader.loadClass(className);
213                if (!interfase.isAssignableFrom(impl)) {
214                    throw new ClassCastException("Class not of type: " + interfase.getName());
215                }
216                implementations.add(impl);
217            }
218            return implementations;
219        }
220    
221        public List<Class> findAvailableImplementations(Class interfase) throws IOException {
222            List<Class> implementations = new ArrayList<Class>();
223            List<String> strings = findAvailableStrings(interfase.getName());
224            for (String className : strings) {
225                try {
226                    Class impl = classLoader.loadClass(className);
227                    if (interfase.isAssignableFrom(impl)) {
228                        implementations.add(impl);
229                    }
230                } catch (Exception notAvailable) {
231                }
232            }
233            return implementations;
234        }
235    
236        public Map<String, Class> mapAllImplementations(Class interfase) throws IOException, ClassNotFoundException {
237            Map<String, Class> implementations = new HashMap<String, Class>();
238            Map<String, String> map = mapAllStrings(interfase.getName());
239            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
240                Map.Entry entry = (Map.Entry) iterator.next();
241                String string = (String) entry.getKey();
242                String className = (String) entry.getValue();
243                Class impl = classLoader.loadClass(className);
244                if (!interfase.isAssignableFrom(impl)) {
245                    throw new ClassCastException("Class not of type: " + interfase.getName());
246                }
247                implementations.put(string, impl);
248            }
249            return implementations;
250        }
251    
252        public Map<String, Class> mapAvailableImplementations(Class interfase) throws IOException {
253            Map<String, Class> implementations = new HashMap<String, Class>();
254            Map<String, String> map = mapAvailableStrings(interfase.getName());
255            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
256                try {
257                    Map.Entry entry = (Map.Entry) iterator.next();
258                    String string = (String) entry.getKey();
259                    String className = (String) entry.getValue();
260                    Class impl = classLoader.loadClass(className);
261                    if (interfase.isAssignableFrom(impl)) {
262                        implementations.put(string, impl);
263                    }
264                } catch (Exception notAvailable) {
265                }
266            }
267            return implementations;
268        }
269    
270    
271        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
272        //
273        //   Find Properties
274        //
275        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
276    
277        public Properties findProperties(String key) throws IOException {
278            String uri = path + key;
279    
280            URL resource = classLoader.getResource(uri);
281            if (resource == null) {
282                throw new IOException("Could not find command in : " + uri);
283            }
284    
285            return loadProperties(resource);
286        }
287    
288        public List<Properties> findAllProperties(String key) throws IOException {
289            String uri = path + key;
290    
291            List<Properties> properties = new ArrayList<Properties>();
292    
293            Enumeration<URL> resources = classLoader.getResources(uri);
294            while (resources.hasMoreElements()) {
295                URL url = resources.nextElement();
296                Properties props = loadProperties(url);
297                properties.add(props);
298            }
299            return properties;
300        }
301    
302        public List<Properties> findAvailableProperties(String key) throws IOException {
303            String uri = path + key;
304    
305            List<Properties> properties = new ArrayList<Properties>();
306    
307            Enumeration<URL> resources = classLoader.getResources(uri);
308            while (resources.hasMoreElements()) {
309                try {
310                    URL url = resources.nextElement();
311                    Properties props = loadProperties(url);
312                    properties.add(props);
313                } catch (Exception notAvailable) {
314                }
315            }
316            return properties;
317        }
318    
319        public Map<String, Properties> mapAllProperties(String key) throws IOException {
320            Map<String, Properties> propertiesMap = new HashMap<String, Properties>();
321            Map<String, URL> map = getResourcesMap(key);
322            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
323                Map.Entry entry = (Map.Entry) iterator.next();
324                String string = (String) entry.getKey();
325                URL url = (URL) entry.getValue();
326                Properties properties = loadProperties(url);
327                propertiesMap.put(string, properties);
328            }
329            return propertiesMap;
330        }
331    
332        public Map<String, Properties> mapAvailableProperties(String key) throws IOException {
333            Map<String, Properties> propertiesMap = new HashMap<String, Properties>();
334            Map<String, URL> map = getResourcesMap(key);
335            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
336                try {
337                    Map.Entry entry = (Map.Entry) iterator.next();
338                    String string = (String) entry.getKey();
339                    URL url = (URL) entry.getValue();
340                    Properties properties = loadProperties(url);
341                    propertiesMap.put(string, properties);
342                } catch (Exception notAvailable) {
343                }
344            }
345            return propertiesMap;
346        }
347    
348        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
349        //
350        //   Map Resources
351        //
352        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
353    
354        public Map<String, URL> getResourcesMap(String key) throws IOException {
355            String basePath = path + key;
356    
357            Map<String, URL> resources = new HashMap<String, URL>();
358            if (!basePath.endsWith("/")){
359                basePath += "/";
360            }
361            Enumeration<URL> urls = classLoader.getResources(basePath);
362    
363            while (urls.hasMoreElements()) {
364                URL location = urls.nextElement();
365    
366                try {
367                    if (location.getProtocol().equals("jar")) {
368    
369                        readJarEntries(location, basePath, resources);
370    
371                    } else if (location.getProtocol().equals("file")) {
372    
373                        readDirectoryEntries(location, resources);
374    
375                    }
376                } catch (Exception e) {
377                }
378            }
379    
380            return resources;
381        }
382    
383        private static void readDirectoryEntries(URL location, Map<String, URL> resources) throws MalformedURLException {
384            File dir = new File(location.getPath());
385            if (dir.isDirectory()) {
386                File[] files = dir.listFiles();
387                for (File file : files) {
388                    if (!file.isDirectory()){
389                        String name = file.getName();
390                        URL url = file.toURL();
391                        resources.put(name, url);
392                    }
393                }
394            }
395        }
396    
397        private static void readJarEntries(URL location, String basePath, Map<String, URL> resources) throws IOException {
398            JarURLConnection conn = (JarURLConnection) location.openConnection();
399            JarFile jarfile = conn.getJarFile();
400    
401            Enumeration<JarEntry> entries = jarfile.entries();
402            while (entries != null && entries.hasMoreElements()) {
403                JarEntry entry = entries.nextElement();
404                String name = entry.getName();
405    
406                if (entry.isDirectory() || !name.startsWith(basePath) || name.length() == basePath.length()) {
407                    continue;
408                }
409    
410                name = name.substring(basePath.length());
411    
412                if (name.contains("/")) {
413                    continue;
414                }
415    
416                URL resource = new URL(location, name);
417                resources.put(name, resource);
418            }
419        }
420    
421        private Properties loadProperties(URL resource) throws IOException {
422            InputStream in = resource.openStream();
423    
424            BufferedInputStream reader = null;
425            try {
426                reader = new BufferedInputStream(in);
427                Properties properties = new Properties();
428                properties.load(reader);
429    
430                return properties;
431            } finally {
432                try {
433                    in.close();
434                    reader.close();
435                } catch (Exception e) {
436                }
437            }
438        }
439    
440        private String readContents(URL resource) throws IOException {
441            InputStream in = resource.openStream();
442            BufferedInputStream reader = null;
443            StringBuffer sb = new StringBuffer();
444    
445            try {
446                reader = new BufferedInputStream(in);
447    
448                int b = reader.read();
449                while (b != -1) {
450                    sb.append((char) b);
451                    b = reader.read();
452                }
453    
454                return sb.toString().trim();
455            } finally {
456                try {
457                    in.close();
458                    reader.close();
459                } catch (Exception e) {
460                }
461            }
462        }
463    
464    
465        public Enumeration doFindCommands() throws IOException {
466            return Thread.currentThread().getContextClassLoader().getResources(path);
467        }
468    
469    }