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.archive;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.net.JarURLConnection;
022    import java.net.URL;
023    import java.util.ArrayList;
024    import java.util.Arrays;
025    import java.util.List;
026    
027    /**
028     * Supports JarArchive and FileArchive URLs
029     *
030     * @version $Rev$ $Date$
031     */
032    public class ClasspathArchive extends CompositeArchive {
033    
034        private final List<URL> urls = new ArrayList<URL>();
035        private final ClassLoader loader;
036    
037        public ClasspathArchive(ClassLoader loader, URL... urls) {
038            this(loader, Arrays.asList(urls));
039        }
040    
041        public ClasspathArchive(ClassLoader loader, Iterable<URL> urls) {
042            super(archives(loader, urls));
043            this.loader = loader;
044    
045        }
046    
047        public static List<Archive> archives(ClassLoader loader, Iterable<URL> urls) {
048            List<Archive> archives = new ArrayList<Archive>();
049    
050            for (URL location : urls) {
051                try {
052                    archives.add(archive(loader, location));
053                } catch (Exception e) {
054                    // TODO This is what we did before, so not too urgent to change, but not ideal
055                    e.printStackTrace();
056                }
057            }
058    
059            return archives;
060        }
061    
062        public static Archive archive(ClassLoader loader, URL location) {
063    
064            if (location.getProtocol().equals("jar")) {
065    
066                return new JarArchive(loader, location);
067    
068            } else if (location.getProtocol().equals("file")) {
069    
070                try {
071    
072                    // See if it's actually a jar
073    
074                    URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
075                    JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
076                    juc.getJarFile();
077    
078                    return new JarArchive(loader, jarUrl);
079    
080                } catch (IOException e) {
081    
082                    return new FileArchive(loader, location);
083    
084                }
085            }
086    
087            throw new UnsupportedOperationException("unsupported archive type: " + location);
088        }
089    
090        public static List<Archive> archives(ClassLoader loader, URL... urls) {
091            return archives(loader, Arrays.asList(urls));
092        }
093    
094        @Override
095        public InputStream getBytecode(String className) throws IOException, ClassNotFoundException {
096            int pos = className.indexOf("<");
097            if (pos > -1) {
098                className = className.substring(0, pos);
099            }
100            pos = className.indexOf(">");
101            if (pos > -1) {
102                className = className.substring(0, pos);
103            }
104            if (!className.endsWith(".class")) {
105                className = className.replace('.', '/') + ".class";
106            }
107    
108            URL resource = loader.getResource(className);
109            if (resource != null) return resource.openStream();
110    
111            throw new ClassNotFoundException(className);
112        }
113    
114        @Override
115        public Class<?> loadClass(String className) throws ClassNotFoundException {
116            return loader.loadClass(className);
117        }
118    }