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.classpath;
018    
019    import java.io.File;
020    import java.lang.reflect.Method;
021    import java.net.URL;
022    import java.net.URLClassLoader;
023    import java.security.AccessController;
024    import java.security.PrivilegedAction;
025    
026    public class TomcatClassPath extends SunURLClassPath {
027    
028        /**
029         * The Tomcat Common ClassLoader
030         */
031        private final ClassLoader classLoader;
032    
033        /**
034         * The addRepository(String jar) method of the Tomcat Common ClassLoader
035         */
036        private Method addRepositoryMethod;
037        private Method addURLMethod;
038    
039    
040        public TomcatClassPath() {
041            this(getCommonLoader(getContextClassLoader()).getParent());
042        }
043    
044        public TomcatClassPath(ClassLoader classLoader){
045            this.classLoader = classLoader;
046            try {
047                addRepositoryMethod = getAddRepositoryMethod();
048            } catch (Exception tomcat4Exception) {
049                // Must be tomcat 5
050                try {
051                    addURLMethod = getAddURLMethod();
052                } catch (Exception tomcat5Exception) {
053                    throw new RuntimeException("Failed accessing classloader for Tomcat 4 or 5", tomcat5Exception);
054                }
055            }
056        }
057    
058        private static ClassLoader getCommonLoader(ClassLoader loader) {
059            if (loader.getClass().getName().equals("org.apache.catalina.loader.StandardClassLoader")) {
060                return loader;
061            } else {
062                return getCommonLoader(loader.getParent());
063            }
064        }
065        
066        public ClassLoader getClassLoader() {
067            return classLoader;
068        }
069    
070        public void addJarsToPath(File dir) throws Exception {
071            String[] jarNames = dir.list(new java.io.FilenameFilter() {
072                public boolean accept(File dir, String name) {
073                    return (name.endsWith(".jar") || name.endsWith(".zip"));
074                }
075            });
076    
077            if (jarNames == null) {
078                return;
079            }
080    
081            for (int j = 0; j < jarNames.length; j++) {
082                this.addJarToPath(new File(dir, jarNames[j]).toURL());
083            }
084            rebuild();
085        }
086    
087        public void addJarToPath(URL jar) throws Exception {
088            this._addJarToPath(jar);
089            rebuild();
090        }
091    
092        public void _addJarToPath(URL jar) throws Exception {
093            String path = jar.toExternalForm();
094            this.addRepository(path);
095        }
096    
097        public void addRepository(String path) throws Exception {
098            if (addRepositoryMethod != null){
099                addRepositoryMethod.invoke(getClassLoader(), new Object[]{path});
100            } else {
101                addURLMethod.invoke(getClassLoader(), new Object[]{new File(path).toURL()});
102            }
103        }
104    
105        protected void rebuild() {
106            try {
107                sun.misc.URLClassPath cp = getURLClassPath((URLClassLoader) getClassLoader());
108                URL[] urls = cp.getURLs();
109                //for (int i=0; i < urls.length; i++){
110                //    System.out.println(urls[i].toExternalForm());
111                //}
112                if (urls.length < 1)
113                    return;
114    
115                StringBuffer path = new StringBuffer(urls.length * 32);
116    
117                File s = new File(urls[0].getFile());
118                path.append(s.getPath());
119                //System.out.println(s.getPath());
120    
121                for (int i = 1; i < urls.length; i++) {
122                    path.append(File.pathSeparator);
123    
124                    s = new File(urls[i].getFile());
125                    //System.out.println(s.getPath());
126                    path.append(s.getPath());
127                }
128                System.setProperty("java.class.path", path.toString());
129            } catch (Exception e) {
130            }
131    
132        }
133    
134        /**
135         * This method gets the Tomcat StandardClassLoader.addRepository method
136         * via reflection. This allows us to call the addRepository method for
137         * Tomcat integration, but doesn't require us to include or ship any
138         * Tomcat libraries.
139         *
140         * @return URLClassLoader.addURL method instance
141         */
142        private Method getAddURLMethod() throws Exception {
143            return (Method) AccessController.doPrivileged(new PrivilegedAction() {
144                public Object run() {
145                    Method method = null;
146                    try {
147                        Class clazz = URLClassLoader.class;
148                        method = clazz.getDeclaredMethod("addURL", new Class[]{URL.class});
149                        method.setAccessible(true);
150                        return method;
151                    } catch (Exception e2) {
152                        e2.printStackTrace();
153                    }
154                    return method;
155                }
156            });
157        }
158    
159        private Method getAddRepositoryMethod() throws Exception {
160            return (Method) AccessController.doPrivileged(new PrivilegedAction() {
161                public Object run() {
162                    Method method = null;
163                    try {
164                        Class clazz = getClassLoader().getClass();
165                        method = clazz.getDeclaredMethod("addRepository", new Class[]{String.class});
166                        method.setAccessible(true);
167                        return method;
168                    } catch (Exception e2) {
169                        throw (IllegalStateException) new IllegalStateException("Unable to find or access the addRepository method in StandardClassLoader").initCause(e2);
170                    }
171                }
172            });
173        }
174    
175    }