1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.ws; 27 28 import com.sun.istack.internal.tools.MaskingClassLoader; 29 import com.sun.istack.internal.tools.ParallelWorldClassLoader; 30 import com.sun.tools.internal.ws.resources.WscompileMessages; 31 import com.sun.tools.internal.ws.wscompile.Options; 32 import com.sun.tools.internal.xjc.api.util.ToolsJarNotFoundException; 33 import com.sun.xml.internal.bind.util.Which; 34 35 import javax.xml.ws.Service; 36 import javax.xml.ws.WebServiceFeature; 37 import javax.xml.namespace.QName; 38 import java.io.File; 39 import java.io.OutputStream; 40 import java.io.IOException; 41 import java.lang.reflect.Constructor; 42 import java.lang.reflect.InvocationTargetException; 43 import java.lang.reflect.Method; 44 import java.net.MalformedURLException; 45 import java.net.URL; 46 import java.net.URLClassLoader; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 51 /** 52 * Invokes JAX-WS tools in a special class loader that can pick up annotation processing classes, 53 * even if it's not available in the tool launcher classpath. 54 * 55 * @author Kohsuke Kawaguchi 56 */ 57 public final class Invoker { 58 static int invoke(String mainClass, String[] args) throws Throwable { 59 // use the platform default proxy if available. 60 // see sun.net.spi.DefaultProxySelector for details. 61 if(!noSystemProxies) { 62 try { 63 System.setProperty("java.net.useSystemProxies","true"); 64 } catch (SecurityException e) { 65 // failing to set this property isn't fatal 66 } 67 } 68 69 ClassLoader oldcc = Thread.currentThread().getContextClassLoader(); 70 try { 71 ClassLoader cl = Invoker.class.getClassLoader(); 72 if(Arrays.asList(args).contains("-Xendorsed")) 73 cl = createClassLoader(cl); // perform JDK6 workaround hack 74 else { 75 int targetArgIndex = Arrays.asList(args).indexOf("-target"); 76 Options.Target targetVersion; 77 if (targetArgIndex != -1) { 78 targetVersion = Options.Target.parse(args[targetArgIndex+1]); 79 } else { 80 targetVersion = Options.Target.getDefault(); 81 } 82 Options.Target loadedVersion = Options.Target.getLoadedAPIVersion(); 83 84 //Check if the target version is supported by the loaded API version 85 if (!loadedVersion.isLaterThan(targetVersion)) { 86 if (Service.class.getClassLoader() == null) 87 System.err.println(WscompileMessages.INVOKER_NEED_ENDORSED(loadedVersion.getVersion(), targetVersion.getVersion())); 88 else { 89 System.err.println(WscompileMessages.WRAPPER_TASK_LOADING_INCORRECT_API(loadedVersion.getVersion(), Which.which(Service.class), targetVersion.getVersion())); 90 } 91 return -1; 92 } 93 94 //find and load tools.jar 95 List<URL> urls = new ArrayList<URL>(); 96 findToolsJar(cl, urls); 97 98 if(urls.size() > 0){ 99 List<String> mask = new ArrayList<String>(Arrays.asList(maskedPackages)); 100 101 // first create a protected area so that we load JAXB/WS 2.1 API 102 // and everything that depends on them inside 103 cl = new MaskingClassLoader(cl,mask); 104 105 // then this classloader loads the API and tools.jar 106 cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl); 107 108 // finally load the rest of the RI. The actual class files are loaded from ancestors 109 cl = new ParallelWorldClassLoader(cl,""); 110 } 111 112 } 113 114 Thread.currentThread().setContextClassLoader(cl); 115 116 Class compileTool = cl.loadClass(mainClass); 117 Constructor ctor = compileTool.getConstructor(OutputStream.class); 118 Object tool = ctor.newInstance(System.out); 119 Method runMethod = compileTool.getMethod("run",String[].class); 120 boolean r = (Boolean)runMethod.invoke(tool,new Object[]{args}); 121 return r ? 0 : 1; 122 } catch (ToolsJarNotFoundException e) { 123 System.err.println(e.getMessage()); 124 } catch (InvocationTargetException e) { 125 throw e.getCause(); 126 } catch(ClassNotFoundException e){ 127 throw e; 128 }finally { 129 Thread.currentThread().setContextClassLoader(oldcc); 130 } 131 132 return -1; 133 } 134 135 /** 136 * Returns true if the RI appears to be loading the JAX-WS 2.1 API. 137 */ 138 public static boolean checkIfLoading21API() { 139 try { 140 Service.class.getMethod("getPort",Class.class, WebServiceFeature[].class); 141 // yup. things look good. 142 return true; 143 } catch (NoSuchMethodException e) { 144 } catch (LinkageError e) { 145 } 146 // nope 147 return false; 148 } 149 150 /** 151 * Returns true if the RI appears to be loading the JAX-WS 2.2 API. 152 */ 153 public static boolean checkIfLoading22API() { 154 try { 155 Service.class.getMethod("create",java.net.URL.class, QName.class, WebServiceFeature[].class); 156 // yup. things look good. 157 return true; 158 } catch (NoSuchMethodException e) { 159 } catch (LinkageError e) { 160 } 161 // nope 162 return false; 163 } 164 165 166 /** 167 * Creates a classloader that can load JAXB/WS 2.2 API and tools.jar, 168 * and then return a classloader that can RI classes, which can see all those APIs and tools.jar. 169 */ 170 public static ClassLoader createClassLoader(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { 171 172 URL[] urls = findIstack22APIs(cl); 173 if(urls.length==0) 174 return cl; // we seem to be able to load everything already. no need for the hack 175 176 List<String> mask = new ArrayList<String>(Arrays.asList(maskedPackages)); 177 if(urls.length>1) { 178 // we need to load 2.1 API from side. so add them to the mask 179 mask.add("javax.xml.bind."); 180 mask.add("javax.xml.ws."); 181 } 182 183 // first create a protected area so that we load JAXB/WS 2.1 API 184 // and everything that depends on them inside 185 cl = new MaskingClassLoader(cl,mask); 186 187 // then this classloader loads the API and tools.jar 188 cl = new URLClassLoader(urls, cl); 189 190 // finally load the rest of the RI. The actual class files are loaded from ancestors 191 cl = new ParallelWorldClassLoader(cl,""); 192 193 return cl; 194 } 195 196 /** 197 * Creates a classloader for loading JAXB/WS 2.1 jar and tools.jar 198 */ 199 private static URL[] findIstack21APIs(ClassLoader cl) throws ClassNotFoundException, MalformedURLException, ToolsJarNotFoundException { 200 List<URL> urls = new ArrayList<URL>(); 201 202 if(Service.class.getClassLoader()==null) { 203 // JAX-WS API is loaded from bootstrap classloader 204 URL res = cl.getResource("javax/xml/ws/EndpointReference.class"); 205 if(res==null) 206 throw new ClassNotFoundException("There's no JAX-WS 2.1 API in the classpath"); 207 urls.add(ParallelWorldClassLoader.toJarUrl(res)); 208 209 res = cl.getResource("javax/xml/bind/annotation/XmlSeeAlso.class"); 210 if(res==null) 211 throw new ClassNotFoundException("There's no JAXB 2.1 API in the classpath"); 212 urls.add(ParallelWorldClassLoader.toJarUrl(res)); 213 } 214 215 findToolsJar(cl, urls); 216 217 return urls.toArray(new URL[urls.size()]); 218 } 219 /** 220 * Creates a classloader for loading JAXB/WS 2.2 jar and tools.jar 221 */ 222 private static URL[] findIstack22APIs(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { 223 List<URL> urls = new ArrayList<URL>(); 224 225 if(Service.class.getClassLoader()==null) { 226 // JAX-WS API is loaded from bootstrap classloader 227 URL res = cl.getResource("javax/xml/ws/EndpointContext.class"); 228 if(res==null) 229 throw new ClassNotFoundException("There's no JAX-WS 2.2 API in the classpath"); 230 urls.add(ParallelWorldClassLoader.toJarUrl(res)); 231 res = cl.getResource("javax/xml/bind/JAXBPermission.class"); 232 if(res==null) 233 throw new ClassNotFoundException("There's no JAXB 2.2 API in the classpath"); 234 urls.add(ParallelWorldClassLoader.toJarUrl(res)); 235 } 236 237 findToolsJar(cl, urls); 238 239 return urls.toArray(new URL[urls.size()]); 240 } 241 242 private static void findToolsJar(ClassLoader cl, List<URL> urls) throws ToolsJarNotFoundException, MalformedURLException { 243 try { 244 Class.forName("com.sun.tools.javac.Main",false,cl); 245 // we can already load them in the parent class loader. 246 // so no need to look for tools.jar. 247 // this happens when we are run inside IDE/Ant, or 248 // in Mac OS. 249 } catch (ClassNotFoundException e) { 250 // otherwise try to find tools.jar 251 File jreHome = new File(System.getProperty("java.home")); 252 File toolsJar = new File( jreHome.getParent(), "lib/tools.jar" ); 253 254 if (!toolsJar.exists()) { 255 throw new ToolsJarNotFoundException(toolsJar); 256 } 257 urls.add(toolsJar.toURL()); 258 } 259 } 260 261 /** 262 * The list of package prefixes we want the 263 * {@link MaskingClassLoader} to prevent the parent 264 * classLoader from loading 265 */ 266 public static String[] maskedPackages = new String[]{ 267 "com.sun.istack.internal.tools.", 268 "com.sun.tools.internal.jxc.", 269 "com.sun.tools.internal.xjc.", 270 "com.sun.tools.internal.ws.", 271 "com.sun.codemodel.internal.", 272 "com.sun.relaxng.", 273 "com.sun.xml.internal.xsom.", 274 "com.sun.xml.internal.bind.", 275 "com.ctc.wstx.", //wsimport, wsgen ant task 276 "org.codehaus.stax2.", //wsimport, wsgen ant task 277 "com.sun.xml.internal.messaging.saaj.", //wsgen ant task 278 "com.sun.xml.internal.ws." 279 }; 280 281 /** 282 * Escape hatch to work around IBM JDK problem. 283 * See http://www-128.ibm.com/developerworks/forums/dw_thread.jsp?nav=false&forum=367&thread=164718&cat=10 284 */ 285 public static boolean noSystemProxies = false; 286 287 static { 288 try { 289 noSystemProxies = Boolean.getBoolean(Invoker.class.getName()+".noSystemProxies"); 290 } catch(SecurityException e) { 291 // ignore 292 } 293 } 294 }