001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.tools.ws;
038:
039: import com.sun.istack.tools.MaskingClassLoader;
040: import com.sun.istack.tools.ParallelWorldClassLoader;
041: import com.sun.tools.ws.resources.WscompileMessages;
042: import com.sun.tools.xjc.api.util.ToolsJarNotFoundException;
043: import com.sun.xml.bind.util.Which;
044:
045: import javax.xml.ws.Service;
046: import javax.xml.ws.WebServiceFeature;
047: import java.io.File;
048: import java.io.OutputStream;
049: import java.lang.reflect.Constructor;
050: import java.lang.reflect.InvocationTargetException;
051: import java.lang.reflect.Method;
052: import java.net.MalformedURLException;
053: import java.net.URL;
054: import java.net.URLClassLoader;
055: import java.util.ArrayList;
056: import java.util.Arrays;
057: import java.util.List;
058:
059: /**
060: * Invokes JAX-WS tools in a special class loader that can pick up APT classes,
061: * even if it's not available in the tool launcher classpath.
062: *
063: * @author Kohsuke Kawaguchi
064: */
065: public final class Invoker {
066: static int invoke(String mainClass, String[] args) throws Throwable {
067: // use the platform default proxy if available.
068: // see sun.net.spi.DefaultProxySelector for details.
069: if (!noSystemProxies) {
070: try {
071: System.setProperty("java.net.useSystemProxies", "true");
072: } catch (SecurityException e) {
073: // failing to set this property isn't fatal
074: }
075: }
076:
077: ClassLoader oldcc = Thread.currentThread()
078: .getContextClassLoader();
079: try {
080: ClassLoader cl = Invoker.class.getClassLoader();
081: if (Arrays.asList(args).contains("-Xendorsed"))
082: cl = createClassLoader(cl); // perform JDK6 workaround hack
083: else {
084: if (!checkIfLoading21API()) {
085: if (Service.class.getClassLoader() == null)
086: System.err.println(WscompileMessages
087: .INVOKER_NEED_ENDORSED());
088: else
089: System.err.println(WscompileMessages
090: .WRAPPER_TASK_LOADING_20_API(Which
091: .which(Service.class)));
092: return -1;
093: }
094: //find and load tools.jar
095: List<URL> urls = new ArrayList<URL>();
096: findToolsJar(cl, urls);
097:
098: if (urls.size() > 0) {
099: List<String> mask = new ArrayList<String>(Arrays
100: .asList(maskedPackages));
101:
102: // first create a protected area so that we load JAXB/WS 2.1 API
103: // and everything that depends on them inside
104: cl = new MaskingClassLoader(cl, mask);
105:
106: // then this classloader loads the API and tools.jar
107: cl = new URLClassLoader(urls.toArray(new URL[urls
108: .size()]), cl);
109:
110: // finally load the rest of the RI. The actual class files are loaded from ancestors
111: cl = new ParallelWorldClassLoader(cl, "");
112: }
113:
114: }
115:
116: Thread.currentThread().setContextClassLoader(cl);
117:
118: Class compileTool = cl.loadClass(mainClass);
119: Constructor ctor = compileTool
120: .getConstructor(OutputStream.class);
121: Object tool = ctor.newInstance(System.out);
122: Method runMethod = compileTool.getMethod("run",
123: String[].class);
124: boolean r = (Boolean) runMethod.invoke(tool,
125: new Object[] { args });
126: return r ? 0 : 1;
127: } catch (ToolsJarNotFoundException e) {
128: System.err.println(e.getMessage());
129: } catch (InvocationTargetException e) {
130: throw e.getCause();
131: } catch (ClassNotFoundException e) {
132: throw e;
133: } finally {
134: Thread.currentThread().setContextClassLoader(oldcc);
135: }
136:
137: return -1;
138: }
139:
140: /**
141: * Returns true if the RI appears to be loading the JAX-WS 2.1 API.
142: */
143: public static boolean checkIfLoading21API() {
144: try {
145: Service.class.getMethod("getPort", Class.class,
146: WebServiceFeature[].class);
147: // yup. things look good.
148: return true;
149: } catch (NoSuchMethodException e) {
150: } catch (LinkageError e) {
151: }
152: // nope
153: return false;
154: }
155:
156: /**
157: * Creates a classloader that can load JAXB/WS 2.1 API and tools.jar,
158: * and then return a classloader that can RI classes, which can see all those APIs and tools.jar.
159: */
160: public static ClassLoader createClassLoader(ClassLoader cl)
161: throws ClassNotFoundException, MalformedURLException,
162: ToolsJarNotFoundException {
163:
164: URL[] urls = findIstackAPIs(cl);
165: if (urls.length == 0)
166: return cl; // we seem to be able to load everything already. no need for the hack
167:
168: List<String> mask = new ArrayList<String>(Arrays
169: .asList(maskedPackages));
170: if (urls.length > 1) {
171: // we need to load 2.1 API from side. so add them to the mask
172: mask.add("javax.xml.bind.");
173: mask.add("javax.xml.ws.");
174: }
175:
176: // first create a protected area so that we load JAXB/WS 2.1 API
177: // and everything that depends on them inside
178: cl = new MaskingClassLoader(cl, mask);
179:
180: // then this classloader loads the API and tools.jar
181: cl = new URLClassLoader(urls, cl);
182:
183: // finally load the rest of the RI. The actual class files are loaded from ancestors
184: cl = new ParallelWorldClassLoader(cl, "");
185:
186: return cl;
187: }
188:
189: /**
190: * Creates a classloader for loading JAXB/WS 2.1 jar and tools.jar
191: */
192: private static URL[] findIstackAPIs(ClassLoader cl)
193: throws ClassNotFoundException, MalformedURLException,
194: ToolsJarNotFoundException {
195: List<URL> urls = new ArrayList<URL>();
196:
197: if (Service.class.getClassLoader() == null) {
198: // JAX-WS API is loaded from bootstrap classloader
199: URL res = cl
200: .getResource("javax/xml/ws/EndpointReference.class");
201: if (res == null)
202: throw new ClassNotFoundException(
203: "There's no JAX-WS 2.1 API in the classpath");
204: urls.add(ParallelWorldClassLoader.toJarUrl(res));
205:
206: res = cl
207: .getResource("javax/xml/bind/annotation/XmlSeeAlso.class");
208: if (res == null)
209: throw new ClassNotFoundException(
210: "There's no JAXB 2.1 API in the classpath");
211: urls.add(ParallelWorldClassLoader.toJarUrl(res));
212: }
213:
214: findToolsJar(cl, urls);
215:
216: return urls.toArray(new URL[urls.size()]);
217: }
218:
219: private static void findToolsJar(ClassLoader cl, List<URL> urls)
220: throws ToolsJarNotFoundException, MalformedURLException {
221: try {
222: Class.forName("com.sun.tools.javac.Main", false, cl);
223: Class.forName("com.sun.tools.apt.Main", false, cl);
224: // we can already load them in the parent class loader.
225: // so no need to look for tools.jar.
226: // this happens when we are run inside IDE/Ant, or
227: // in Mac OS.
228: } catch (ClassNotFoundException e) {
229: // otherwise try to find tools.jar
230: File jreHome = new File(System.getProperty("java.home"));
231: File toolsJar = new File(jreHome.getParent(),
232: "lib/tools.jar");
233:
234: if (!toolsJar.exists()) {
235: throw new ToolsJarNotFoundException(toolsJar);
236: }
237: urls.add(toolsJar.toURL());
238: }
239: }
240:
241: /**
242: * The list of package prefixes we want the
243: * {@link MaskingClassLoader} to prevent the parent
244: * classLoader from loading
245: */
246: public static String[] maskedPackages = new String[] {
247: "com.sun.istack.tools.", "com.sun.tools.jxc.",
248: "com.sun.tools.xjc.", "com.sun.tools.ws.",
249: "com.sun.codemodel.", "com.sun.relaxng.",
250: "com.sun.xml.xsom.", "com.sun.xml.bind.", "com.sun.xml.ws." };
251:
252: /**
253: * Escape hatch to work around IBM JDK problem.
254: * See http://www-128.ibm.com/developerworks/forums/dw_thread.jsp?nav=false&forum=367&thread=164718&cat=10
255: */
256: public static boolean noSystemProxies = false;
257:
258: static {
259: try {
260: noSystemProxies = Boolean.getBoolean(Invoker.class
261: .getName()
262: + ".noSystemProxies");
263: } catch (SecurityException e) {
264: // ignore
265: }
266: }
267: }
|