1 /** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one or more 4 * contributor license agreements. See the NOTICE file distributed with 5 * this work for additional information regarding copyright ownership. 6 * The ASF licenses this file to You under the Apache License, Version 2.0 7 * (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.openejb.tomcat.loader; 19 20 import java.io.File; 21 import java.lang.reflect.Method; 22 import java.net.URL; 23 import java.net.URI; 24 import java.net.URLDecoder; 25 import java.util.Properties; 26 27 public class TomcatEmbedder { 28 /** 29 * 30 * @param properties this instance contains all System properties as well as all initialization parameters of the LoaderServlet 31 * @param catalinaCl The ClassLoader which loaded the ServletConfig class 32 */ 33 public static void embed(Properties properties, ClassLoader catalinaCl) { 34 if (catalinaCl == null) throw new NullPointerException("catalinaCl is null"); 35 if (properties == null) throw new NullPointerException("properties is null"); 36 37 if (!properties.containsKey("openejb.war")) { 38 throw new IllegalArgumentException("properties must contain the openejb.war property"); 39 } 40 // openejbWar represents the absolute path of the openejb webapp i.e. the openejb directory 41 File openejbWar = new File(properties.getProperty("openejb.war")); 42 if (!openejbWar.isDirectory()) { 43 throw new IllegalArgumentException("openejb.war is not a directory: " + openejbWar); 44 } 45 // retrieve the current ClassLoader 46 ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); 47 // set the ClassLoader to the one which loaded ServletConfig.class i.e. the parent ClassLoader 48 Thread.currentThread().setContextClassLoader(catalinaCl); 49 try { 50 // WebappClassLoader childCl = new WebappClassLoader(catalinaCl) 51 Class<?> webappClClass = catalinaCl.loadClass("org.apache.catalina.loader.WebappClassLoader"); 52 ClassLoader childCl = (ClassLoader) webappClClass.getConstructor(ClassLoader.class).newInstance(catalinaCl); 53 54 // childCl.addRepository(openejb-tomcat-loader.jar) 55 // Use reflection to add the openejb-tomcat-loader.jar file to the repository of WebappClassLoader. 56 // WebappClassLoader will now search for classes in this jar too 57 File thisJar = getThisJar(); 58 String thisJarUrl = thisJar.toURI().toString(); 59 webappClClass.getMethod("addRepository", String.class).invoke(childCl, thisJarUrl); 60 61 // childCl.addRepository(openejb-loader.jar) 62 // Use reflection to add the openejb-loader.jar file to the repository of WebappClassLoader. 63 // WebappClassLoader will now search for classes in this jar too 64 65 File jarFile = findOpenEJBJar(openejbWar, "openejb-loader"); 66 String openejbLoaderUrl = jarFile.toURI().toString(); 67 68 webappClClass.getMethod("addRepository", String.class).invoke(childCl, openejbLoaderUrl); 69 70 // childCl.start() 71 webappClClass.getMethod("start").invoke(childCl); 72 73 // TomcatHook.hook() 74 Class<?> tomcatUtilClass = childCl.loadClass("org.apache.openejb.tomcat.loader.TomcatHook"); 75 Method hookMethod = tomcatUtilClass.getDeclaredMethod("hook", Properties.class); 76 hookMethod.setAccessible(true); 77 hookMethod.invoke(null, properties); 78 } catch (Throwable e) { 79 e.printStackTrace(); 80 } finally { 81 Thread.currentThread().setContextClassLoader(oldCl); 82 } 83 } 84 85 private static File getThisJar() { 86 return jarLocation(TomcatEmbedder.class); 87 } 88 89 private static File jarLocation(Class clazz) { 90 try { 91 String classFileName = clazz.getName().replace(".", "/") + ".class"; 92 93 URL classURL = clazz.getClassLoader().getResource(classFileName); 94 95 URI uri = null; 96 String url = classURL.toExternalForm(); 97 if (url.contains("+")) { 98 url = url.replaceAll("\\+", "%2B"); 99 } 100 101 if (url.contains(" ")) { 102 url = url.replaceAll(" ", "%20"); 103 } 104 uri = new URI(url); 105 106 if (uri.getPath() == null){ 107 uri = new URI(uri.getRawSchemeSpecificPart()); 108 } 109 110 String path = uri.getPath(); 111 if (path.contains("!")){ 112 path = path.substring(0, path.indexOf('!')); 113 } else { 114 path = path.substring(0, path.length() - classFileName.length()); 115 } 116 117 path = path.replaceAll("\\+", "%2B"); 118 return new File(URLDecoder.decode(path)); 119 } catch (Exception e) { 120 throw new IllegalStateException(e); 121 } 122 } 123 124 private static File findOpenEJBJar(File openejbWar, String namePrefix) { 125 File openEJBLibDir = new File(openejbWar, "lib"); 126 if (openEJBLibDir == null) return null; 127 128 File openejbLoaderJar = null; 129 for (File file : openEJBLibDir.listFiles()) { 130 if (file.getName().startsWith(namePrefix + "-") && file.getName().endsWith(".jar")) { 131 return file; 132 } 133 } 134 135 return openejbLoaderJar; 136 } 137 }