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.wscompile;
038:
039: import com.sun.mirror.apt.AnnotationProcessor;
040: import com.sun.mirror.apt.AnnotationProcessorEnvironment;
041: import com.sun.mirror.apt.AnnotationProcessorFactory;
042: import com.sun.mirror.declaration.AnnotationTypeDeclaration;
043: import com.sun.tools.ws.ToolVersion;
044: import com.sun.tools.ws.processor.modeler.annotation.AnnotationProcessorContext;
045: import com.sun.tools.ws.processor.modeler.annotation.WebServiceAP;
046: import com.sun.tools.ws.processor.modeler.wsdl.ConsoleErrorReporter;
047: import com.sun.tools.ws.resources.WscompileMessages;
048: import com.sun.tools.xjc.util.NullStream;
049: import com.sun.xml.txw2.TXW;
050: import com.sun.xml.txw2.TypedXmlWriter;
051: import com.sun.xml.txw2.annotation.XmlAttribute;
052: import com.sun.xml.txw2.annotation.XmlElement;
053: import com.sun.xml.txw2.output.StreamSerializer;
054: import com.sun.xml.ws.api.BindingID;
055: import com.sun.xml.ws.api.server.Container;
056: import com.sun.xml.ws.api.wsdl.writer.WSDLGeneratorExtension;
057: import com.sun.xml.ws.binding.WebServiceFeatureList;
058: import com.sun.xml.ws.model.AbstractSEIModelImpl;
059: import com.sun.xml.ws.model.RuntimeModeler;
060: import com.sun.xml.ws.util.ServiceFinder;
061: import com.sun.xml.ws.wsdl.writer.WSDLGenerator;
062: import com.sun.xml.ws.wsdl.writer.WSDLResolver;
063: import org.xml.sax.SAXParseException;
064:
065: import javax.xml.bind.annotation.XmlSeeAlso;
066: import javax.xml.namespace.QName;
067: import javax.xml.transform.Result;
068: import javax.xml.transform.stream.StreamResult;
069: import javax.xml.ws.EndpointReference;
070: import javax.xml.ws.Holder;
071: import java.io.BufferedOutputStream;
072: import java.io.File;
073: import java.io.FileNotFoundException;
074: import java.io.FileOutputStream;
075: import java.io.IOException;
076: import java.io.OutputStream;
077: import java.io.PrintStream;
078: import java.lang.reflect.Field;
079: import java.net.URLClassLoader;
080: import java.security.AccessController;
081: import java.security.PrivilegedAction;
082: import java.util.Collection;
083: import java.util.Collections;
084: import java.util.HashMap;
085: import java.util.HashSet;
086: import java.util.Map;
087: import java.util.Set;
088:
089: /**
090: * @author Vivek Pandey
091: */
092: public class WsgenTool implements AnnotationProcessorFactory {
093: private final PrintStream out;
094: private final WsgenOptions options = new WsgenOptions();
095:
096: public WsgenTool(OutputStream out, Container container) {
097: this .out = (out instanceof PrintStream) ? (PrintStream) out
098: : new PrintStream(out);
099: this .container = container;
100: }
101:
102: public WsgenTool(OutputStream out) {
103: this (out, null);
104: }
105:
106: public boolean run(String[] args) {
107: final Listener listener = new Listener();
108: for (String arg : args) {
109: if (arg.equals("-version")) {
110: listener.message(ToolVersion.VERSION.BUILD_VERSION);
111: return true;
112: }
113: }
114: try {
115: options.parseArguments(args);
116: options.validate();
117: if (!buildModel(options.endpoint.getName(), listener)) {
118: return false;
119: }
120: } catch (Options.WeAreDone done) {
121: usage(done.getOptions());
122: } catch (BadCommandLineException e) {
123: if (e.getMessage() != null) {
124: System.out.println(e.getMessage());
125: System.out.println();
126: }
127: usage(e.getOptions());
128: return false;
129: } catch (AbortException e) {
130: //error might have been reported
131: } finally {
132: if (!options.keep) {
133: options.removeGeneratedFiles();
134: }
135: }
136: return true;
137: }
138:
139: private AnnotationProcessorContext context;
140: private final Container container;
141:
142: private WebServiceAP webServiceAP;
143:
144: private int round = 0;
145:
146: // Workaround for bug 6499165 on jax-ws,
147: // Original bug with JDK 6500594 , 6500594 when compiled with debug option,
148: private void workAroundJavacDebug() {
149: ClassLoader cl = Thread.currentThread().getContextClassLoader();
150: try {
151: final Class aptMain = cl
152: .loadClass("com.sun.tools.apt.main.Main");
153: AccessController.doPrivileged(new PrivilegedAction<Void>() {
154: public Void run() {
155: try {
156: Field forcedOpts = aptMain
157: .getDeclaredField("forcedOpts");
158: forcedOpts.setAccessible(true);
159: forcedOpts.set(null, new String[] {});
160: } catch (NoSuchFieldException e) {
161: if (options.verbose)
162: e.printStackTrace();
163: } catch (IllegalAccessException e) {
164: if (options.verbose)
165: e.printStackTrace();
166: }
167: return null;
168: }
169: });
170: } catch (ClassNotFoundException e) {
171: if (options.verbose)
172: e.printStackTrace();
173: }
174: }
175:
176: public boolean buildModel(String endpoint, Listener listener)
177: throws BadCommandLineException {
178: final ErrorReceiverFilter errReceiver = new ErrorReceiverFilter(
179: listener);
180: context = new AnnotationProcessorContext();
181: webServiceAP = new WebServiceAP(options, context, errReceiver,
182: out);
183:
184: String[] args = new String[9];
185: args[0] = "-d";
186: args[1] = options.destDir.getAbsolutePath();
187: args[2] = "-classpath";
188: args[3] = options.classpath;
189: args[4] = "-s";
190: args[5] = options.sourceDir.getAbsolutePath();
191: args[6] = "-XclassesAsDecls";
192: args[7] = endpoint;
193: args[8] = "-Xbootclasspath/p:"
194: + JavaCompilerHelper
195: .getJarFile(EndpointReference.class)
196: + File.pathSeparator
197: + JavaCompilerHelper.getJarFile(XmlSeeAlso.class);
198:
199: // Workaround for bug 6499165: issue with javac debug option
200: workAroundJavacDebug();
201: int result = com.sun.tools.apt.Main.process(this , args);
202: if (result != 0) {
203: out.println(WscompileMessages
204: .WSCOMPILE_ERROR(WscompileMessages
205: .WSCOMPILE_COMPILATION_FAILED()));
206: return false;
207: }
208: if (options.genWsdl) {
209: String tmpPath = options.destDir.getAbsolutePath()
210: + File.pathSeparator + options.classpath;
211: ClassLoader classLoader = new URLClassLoader(Options
212: .pathToURLs(tmpPath), this .getClass()
213: .getClassLoader());
214: Class<?> endpointClass;
215: try {
216: endpointClass = classLoader.loadClass(endpoint);
217: } catch (ClassNotFoundException e) {
218: throw new BadCommandLineException(WscompileMessages
219: .WSGEN_CLASS_NOT_FOUND(endpoint));
220: }
221:
222: BindingID bindingID = WsgenOptions
223: .getBindingID(options.protocol);
224: if (!options.protocolSet) {
225: bindingID = BindingID.parse(endpointClass);
226: }
227: RuntimeModeler rtModeler = new RuntimeModeler(
228: endpointClass, options.serviceName, bindingID);
229: rtModeler.setClassLoader(classLoader);
230: if (options.portName != null)
231: rtModeler.setPortName(options.portName);
232: AbstractSEIModelImpl rtModel = rtModeler
233: .buildRuntimeModel();
234:
235: final File[] wsdlFileName = new File[1]; // used to capture the generated WSDL file.
236: final Map<String, File> schemaFiles = new HashMap<String, File>();
237: WebServiceFeatureList wsfeatures = new WebServiceFeatureList(
238: endpointClass);
239: WSDLGenerator wsdlGenerator = new WSDLGenerator(
240: rtModel,
241: new WSDLResolver() {
242: private File toFile(String suggestedFilename) {
243: return new File(options.nonclassDestDir,
244: suggestedFilename);
245: }
246:
247: private Result toResult(File file) {
248: Result result;
249: try {
250: result = new StreamResult(
251: new FileOutputStream(file));
252: result.setSystemId(file.getPath()
253: .replace('\\', '/'));
254: } catch (FileNotFoundException e) {
255: errReceiver.error(e);
256: return null;
257: }
258: return result;
259: }
260:
261: public Result getWSDL(String suggestedFilename) {
262: File f = toFile(suggestedFilename);
263: wsdlFileName[0] = f;
264: return toResult(f);
265: }
266:
267: public Result getSchemaOutput(String namespace,
268: String suggestedFilename) {
269: if (namespace.equals(""))
270: return null;
271: File f = toFile(suggestedFilename);
272: schemaFiles.put(namespace, f);
273: return toResult(f);
274: }
275:
276: public Result getAbstractWSDL(
277: Holder<String> filename) {
278: return toResult(toFile(filename.value));
279: }
280:
281: public Result getSchemaOutput(String namespace,
282: Holder<String> filename) {
283: return getSchemaOutput(namespace,
284: filename.value);
285: }
286: // TODO pass correct impl's class name
287: }, bindingID.createBinding(wsfeatures.toArray()),
288: container, endpointClass, ServiceFinder.find(
289: WSDLGeneratorExtension.class).toArray());
290: wsdlGenerator.doGeneration();
291:
292: if (options.wsgenReport != null)
293: generateWsgenReport(endpointClass, rtModel,
294: wsdlFileName[0], schemaFiles);
295: }
296: return true;
297: }
298:
299: /**
300: * Generates a small XML file that captures the key activity of wsgen,
301: * so that test harness can pick up artifacts.
302: */
303: private void generateWsgenReport(Class<?> endpointClass,
304: AbstractSEIModelImpl rtModel, File wsdlFile,
305: Map<String, File> schemaFiles) {
306: try {
307: ReportOutput.Report report = TXW.create(
308: ReportOutput.Report.class, new StreamSerializer(
309: new BufferedOutputStream(
310: new FileOutputStream(
311: options.wsgenReport))));
312:
313: report.wsdl(wsdlFile.getAbsolutePath());
314: ReportOutput.writeQName(rtModel.getServiceQName(), report
315: .service());
316: ReportOutput.writeQName(rtModel.getPortName(), report
317: .port());
318: ReportOutput.writeQName(rtModel.getPortTypeName(), report
319: .portType());
320:
321: report.implClass(endpointClass.getName());
322:
323: for (Map.Entry<String, File> e : schemaFiles.entrySet()) {
324: ReportOutput.Schema s = report.schema();
325: s.ns(e.getKey());
326: s.location(e.getValue().getAbsolutePath());
327: }
328:
329: report.commit();
330: } catch (IOException e) {
331: // this is code for the test, so we can be lousy in the error handling
332: throw new Error(e);
333: }
334: }
335:
336: /**
337: * "Namespace" for code needed to generate the report file.
338: */
339: static class ReportOutput {
340: @XmlElement("report")
341: interface Report extends TypedXmlWriter {
342: @XmlElement
343: void wsdl(String file); // location of WSDL
344:
345: @XmlElement
346: QualifiedName portType();
347:
348: @XmlElement
349: QualifiedName service();
350:
351: @XmlElement
352: QualifiedName port();
353:
354: /**
355: * Name of the class that has {@link javax.jws.WebService}.
356: */
357: @XmlElement
358: void implClass(String name);
359:
360: @XmlElement
361: Schema schema();
362: }
363:
364: interface QualifiedName extends TypedXmlWriter {
365: @XmlAttribute
366: void uri(String ns);
367:
368: @XmlAttribute
369: void localName(String localName);
370: }
371:
372: interface Schema extends TypedXmlWriter {
373: @XmlAttribute
374: void ns(String ns);
375:
376: @XmlAttribute
377: void location(String filePath);
378: }
379:
380: private static void writeQName(QName n, QualifiedName w) {
381: w.uri(n.getNamespaceURI());
382: w.localName(n.getLocalPart());
383: }
384: }
385:
386: protected void usage(Options options) {
387: System.out.println(WscompileMessages.WSGEN_HELP("WSGEN"));
388: System.out.println(WscompileMessages.WSGEN_USAGE_EXAMPLES());
389: }
390:
391: public Collection<String> supportedOptions() {
392: return supportedOptions;
393: }
394:
395: public Collection<String> supportedAnnotationTypes() {
396: return supportedAnnotations;
397: }
398:
399: public AnnotationProcessor getProcessorFor(
400: Set<AnnotationTypeDeclaration> set,
401: AnnotationProcessorEnvironment apEnv) {
402: if (options.verbose)
403: apEnv.getMessager().printNotice("\tap round: " + ++round);
404: webServiceAP.init(apEnv);
405: return webServiceAP;
406: }
407:
408: class Listener extends WsimportListener {
409: ConsoleErrorReporter cer = new ConsoleErrorReporter(
410: out == null ? new PrintStream(new NullStream()) : out);
411:
412: @Override
413: public void generatedFile(String fileName) {
414: message(fileName);
415: }
416:
417: @Override
418: public void message(String msg) {
419: out.println(msg);
420: }
421:
422: @Override
423: public void error(SAXParseException exception) {
424: cer.error(exception);
425: }
426:
427: @Override
428: public void fatalError(SAXParseException exception) {
429: cer.fatalError(exception);
430: }
431:
432: @Override
433: public void warning(SAXParseException exception) {
434: cer.warning(exception);
435: }
436:
437: @Override
438: public void info(SAXParseException exception) {
439: cer.info(exception);
440: }
441: }
442:
443: /*
444: * Processor doesn't examine any options.
445: */
446: static final Collection<String> supportedOptions = Collections
447: .unmodifiableSet(new HashSet<String>());
448:
449: /*
450: * All annotation types are supported.
451: */
452: static final Collection<String> supportedAnnotations;
453: static {
454: Collection<String> types = new HashSet<String>();
455: types.add("*");
456: types.add("javax.jws.*");
457: types.add("javax.jws.soap.*");
458: supportedAnnotations = Collections
459: .unmodifiableCollection(types);
460: }
461: }
|