1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package com.sun.star.lib.unoloader; 25 26 import java.io.IOException; 27 import java.lang.reflect.InvocationTargetException; 28 import java.net.MalformedURLException; 29 import java.net.URL; 30 import java.net.URLClassLoader; 31 import java.util.jar.Attributes; 32 import java.util.jar.Manifest; 33 import java.util.jar.JarInputStream; 34 35 /** 36 * The root UNO class loader. 37 * 38 * <p>This class loader is able to load all published URE classes, including the 39 * classes representing the published URE UNO types. For consistency, it is 40 * important that within each Java UNO environment there is one instance of this 41 * class loader that is the defining class loader of all published URE classes 42 * (and hence of all unpublished URE classes, too) and of all classes 43 * representing UNO types (the published URE UNO types, any unpublished URE UNO 44 * types, and any additional UNO types introduced by components; for the latter, 45 * {@link #addURL} may be necessary).</p> 46 * 47 * <p><em>This is an internal, unstable class of the Uno Runtime Environment; it 48 * should not be used by client code.</em></p> 49 * 50 * @since UDK 3.2.0 51 */ 52 public final class UnoClassLoader extends URLClassLoader { 53 /** 54 * Instantiates the root UNO class loader. 55 * 56 * @param base a base URL relative to which the URE JARs 57 * (<code>java_uno.jar</code>, <code>juh.jar</code>, <code>jurt.jar</code>, 58 * <code>ridl.jar</code>) can be found; must not be <code>null</code>. 59 * 60 * @param classPath an array of URLs that form the class path of this class 61 * loader; may be <code>null</code>, which is the same as an empty array. 62 * The URLs are interpreted in the same way as the arguments of a {@link 63 * URLClassLoader}. 64 * 65 * @param parent the parent class loader for delegation. 66 * 67 * @throws MalformedURLException if the given <code>base</code> URL is 68 * malformed. 69 */ UnoClassLoader(URL base, URL[] classPath, ClassLoader parent)70 public UnoClassLoader(URL base, URL[] classPath, ClassLoader parent) 71 throws MalformedURLException 72 { 73 super(createUrls(base, classPath), parent); 74 } 75 76 /** 77 * Obtains a class loader for a UNO JAR. 78 * 79 * @param jar the URL of a UNO JAR; must not be <code>null</code>. 80 * 81 * @param mainAttributes represents the main section of the manifest of the 82 * given JAR <code>jar</code>; <code>null</code> if the given JAR does not 83 * have a manifest. (This redundant parameter is there for performance 84 * reasons, as typically the caller of this method already has this 85 * information available.) 86 * 87 * @return an appropriate class loader; will never be <code>null</code>. 88 * 89 * @throws MalformedURLException if the given <code>jar</code> URL or any of 90 * the UNO-Type-Path URLs specified in the given JAR are malformed. 91 */ getClassLoader(URL jar, Attributes mainAttributes)92 public ClassLoader getClassLoader(URL jar, Attributes mainAttributes) 93 throws MalformedURLException 94 { 95 String path = mainAttributes == null ? 96 null : mainAttributes.getValue("UNO-Type-Path"); 97 if (path == null) { 98 path = "<>"; 99 } 100 for (int i = 0; i < path.length();) { 101 while (i < path.length() && path.charAt(i) == ' ') { 102 ++i; 103 } 104 if (i < path.length()) { 105 String url; 106 if (path.charAt(i) == '<') { 107 int j = path.indexOf('>', i + 1); 108 if (j < 0) { 109 url = path.substring(i + 1); 110 i = path.length(); 111 } else { 112 url = path.substring(i + 1, j); 113 i = j + 1; 114 } 115 } else { 116 int j = path.indexOf(' ', i + 1); 117 if (j < 0) { 118 j = path.length(); 119 } 120 url = path.substring(i, j); 121 i = j; 122 } 123 addURL(new URL(jar, url)); 124 } 125 } 126 return URLClassLoader.newInstance(new URL[] { jar }, this); 127 } 128 129 /** 130 * Executes a UNO JAR. 131 * 132 * @param jar the URL of a UNO JAR that specifies a Main-Class; must not be 133 * <code>null</code>. 134 * 135 * @param arguments any arguments passed to the <code>main</code> method of 136 * the specified Main-Class of the given JAR <code>jar</code>; must not be 137 * <code>null</code>. 138 * 139 * @throws IOException if there are any problems processing the given JAR 140 * <code>jar</code>. 141 * 142 * @throws ClassNotFoundException if the given JAR <code>jar</code> does not 143 * specify a Main-Class, or if the specified Main-Class cannot be found. 144 * 145 * @throws NoSuchMethodException if the specified Main-Class of the given 146 * JAR <code>jar</code> does not have an appropriate <code>main</code> 147 * method. 148 * 149 * @throws InvocationTargetException if an exception occurs while executing 150 * the <code>main</code> method of the specified Main-Class of the given JAR 151 * <code>jar</code>. 152 */ execute(URL jar, String[] arguments)153 public void execute(URL jar, String[] arguments) 154 throws IOException, ClassNotFoundException, NoSuchMethodException, 155 InvocationTargetException 156 { 157 Attributes attr = getJarMainAttributes(jar); 158 String name = attr == null 159 ? null : attr.getValue(Attributes.Name.MAIN_CLASS); 160 if (name == null) { 161 throw new ClassNotFoundException( 162 jar + " does not specify a main class"); 163 } 164 try { 165 getClassLoader(jar, attr).loadClass(name.replace('/', '.')). 166 getMethod("main", new Class[] { String[].class }). 167 invoke(null, new Object[] { arguments }); 168 } catch (IllegalAccessException e) { 169 throw new RuntimeException("impossible " + e); 170 } 171 } 172 173 /** 174 * Obtains the main section of the manifest of a JAR. 175 * 176 * @param jar the URL of a JAR; must not be <code>null</code>. 177 * 178 * @return the representation of the main section of the manifest of the 179 * given JAR <code>jar</code>, or <code>null</code> if the given JAR does 180 * not have a manifest. 181 * 182 * @throws IOException if there are any problems processing the given JAR 183 * <code>jar</code>. 184 */ getJarMainAttributes(URL jar)185 public static Attributes getJarMainAttributes(URL jar) throws IOException { 186 JarInputStream s = new JarInputStream(jar.openStream()); 187 Manifest mf; 188 try { 189 mf = s.getManifest(); 190 } finally { 191 s.close(); 192 } 193 return mf == null ? null : mf.getMainAttributes(); 194 } 195 createUrls(URL base, URL[] classPath)196 private static URL[] createUrls(URL base, URL[] classPath) 197 throws MalformedURLException 198 { 199 final int JARS = 4; 200 URL[] urls = new URL[JARS + (classPath == null ? 0 : classPath.length)]; 201 urls[0] = new URL(base, "java_uno.jar"); //TODO get rid of it here 202 urls[1] = new URL(base, "juh.jar"); 203 urls[2] = new URL(base, "jurt.jar"); 204 urls[3] = new URL(base, "ridl.jar"); 205 if (classPath != null) { 206 System.arraycopy(classPath, 0, urls, JARS, classPath.length); 207 } 208 return urls; 209 } 210 } 211