/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.internal.ws.processor.generator;

import com.sun.codemodel.internal.ClassType;
import com.sun.codemodel.internal.JAnnotationUse;
import com.sun.codemodel.internal.JBlock;
import com.sun.codemodel.internal.JCatchBlock;
import com.sun.codemodel.internal.JClass;
import com.sun.codemodel.internal.JClassAlreadyExistsException;
import com.sun.codemodel.internal.JCommentPart;
import com.sun.codemodel.internal.JConditional;
import com.sun.codemodel.internal.JDefinedClass;
import com.sun.codemodel.internal.JDocComment;
import com.sun.codemodel.internal.JExpr;
import com.sun.codemodel.internal.JFieldVar;
import com.sun.codemodel.internal.JInvocation;
import com.sun.codemodel.internal.JMethod;
import com.sun.codemodel.internal.JMod;
import com.sun.codemodel.internal.JTryBlock;
import com.sun.codemodel.internal.JType;
import com.sun.codemodel.internal.JVar;
import com.sun.tools.internal.ws.processor.model.Model;
import com.sun.tools.internal.ws.processor.model.ModelProperties;
import com.sun.tools.internal.ws.processor.model.Port;
import com.sun.tools.internal.ws.processor.model.Service;
import com.sun.tools.internal.ws.processor.model.java.JavaInterface;
import com.sun.tools.internal.ws.resources.GeneratorMessages;
import com.sun.tools.internal.ws.wscompile.ErrorReceiver;
import com.sun.tools.internal.ws.wscompile.Options;
import com.sun.tools.internal.ws.wscompile.WsimportOptions;
import com.sun.tools.internal.ws.wsdl.document.PortType;
import com.sun.xml.internal.ws.spi.db.BindingHelper;

import org.xml.sax.Locator;

import javax.xml.namespace.QName;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.WebServiceException;
import java.net.MalformedURLException;
import java.net.URL;

import com.sun.xml.internal.ws.util.ServiceFinder;
import java.util.Locale;

Author:WS Development Team, Jitendra Kotamraju
/** * @author WS Development Team * @author Jitendra Kotamraju */
public class ServiceGenerator extends GeneratorBase { public static void generate(Model model, WsimportOptions options, ErrorReceiver receiver) { ServiceGenerator serviceGenerator = new ServiceGenerator(model, options, receiver); serviceGenerator.doGeneration(); } private ServiceGenerator(Model model, WsimportOptions options, ErrorReceiver receiver) { init(model, options, receiver); } @Override public void visit(Service service) { JavaInterface intf = service.getJavaInterface(); String className = Names.customJavaTypeClassName(intf); if (donotOverride && GeneratorUtil.classExists(options, className)) { log("Class " + className + " exists. Not overriding."); return; } JDefinedClass cls; try { cls = getClass(className, ClassType.CLASS); } catch (JClassAlreadyExistsException e) { receiver.error(service.getLocator(), GeneratorMessages.GENERATOR_SERVICE_CLASS_ALREADY_EXIST(className, service.getName())); return; } cls._extends(javax.xml.ws.Service.class); String serviceFieldName = BindingHelper.mangleNameToClassName(service.getName().getLocalPart()).toUpperCase(Locale.ENGLISH); String wsdlLocationName = serviceFieldName + "_WSDL_LOCATION"; JFieldVar urlField = cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, URL.class, wsdlLocationName); JFieldVar exField = cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, WebServiceException.class, serviceFieldName+"_EXCEPTION"); String serviceName = serviceFieldName + "_QNAME"; cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, QName.class, serviceName, JExpr._new(cm.ref(QName.class)).arg(service.getName().getNamespaceURI()).arg(service.getName().getLocalPart())); JClass qNameCls = cm.ref(QName.class); JInvocation inv; inv = JExpr._new(qNameCls); inv.arg("namespace"); inv.arg("localpart"); if (options.useBaseResourceAndURLToLoadWSDL) { writeClassLoaderBaseResourceWSDLLocation(className, cls, urlField, exField); } else if (wsdlLocation.startsWith("http://") || wsdlLocation.startsWith("https://") || wsdlLocation.startsWith("file:/")) { writeAbsWSDLLocation(cls, urlField, exField); } else if (wsdlLocation.startsWith("META-INF/")) { writeClassLoaderResourceWSDLLocation(className, cls, urlField, exField); } else { writeResourceWSDLLocation(className, cls, urlField, exField); } //write class comment - JAXWS warning JDocComment comment = cls.javadoc(); if (service.getJavaDoc() != null) { comment.add(service.getJavaDoc()); comment.add("\n\n"); } for (String doc : getJAXWSClassComment()) { comment.add(doc); } // Generating constructor // for e.g: public ExampleService() JMethod constructor1 = cls.constructor(JMod.PUBLIC); String constructor1Str = String.format("super(__getWsdlLocation(), %s);", serviceName); constructor1.body().directStatement(constructor1Str); // Generating constructor // for e.g: public ExampleService(WebServiceFeature ... features) if (options.target.isLaterThan(Options.Target.V2_2)) { JMethod constructor2 = cls.constructor(JMod.PUBLIC); constructor2.varParam(WebServiceFeature.class, "features"); String constructor2Str = String.format("super(__getWsdlLocation(), %s, features);", serviceName); constructor2.body().directStatement(constructor2Str); } // Generating constructor // for e.g: public ExampleService(URL wsdlLocation) if (options.target.isLaterThan(Options.Target.V2_2)) { JMethod constructor3 = cls.constructor(JMod.PUBLIC); constructor3.param(URL.class, "wsdlLocation"); String constructor3Str = String.format("super(wsdlLocation, %s);", serviceName); constructor3.body().directStatement(constructor3Str); } // Generating constructor // for e.g: public ExampleService(URL wsdlLocation, WebServiceFeature ... features) if (options.target.isLaterThan(Options.Target.V2_2)) { JMethod constructor4 = cls.constructor(JMod.PUBLIC); constructor4.param(URL.class, "wsdlLocation"); constructor4.varParam(WebServiceFeature.class, "features"); String constructor4Str = String.format("super(wsdlLocation, %s, features);", serviceName); constructor4.body().directStatement(constructor4Str); } // Generating constructor // for e.g: public ExampleService(URL wsdlLocation, QName serviceName) JMethod constructor5 = cls.constructor(JMod.PUBLIC); constructor5.param(URL.class, "wsdlLocation"); constructor5.param(QName.class, "serviceName"); constructor5.body().directStatement("super(wsdlLocation, serviceName);"); // Generating constructor // for e.g: public ExampleService(URL, QName, WebServiceFeature ...) if (options.target.isLaterThan(Options.Target.V2_2)) { JMethod constructor6 = cls.constructor(JMod.PUBLIC); constructor6.param(URL.class, "wsdlLocation"); constructor6.param(QName.class, "serviceName"); constructor6.varParam(WebServiceFeature.class, "features"); constructor6.body().directStatement("super(wsdlLocation, serviceName, features);"); } //@WebService JAnnotationUse webServiceClientAnn = cls.annotate(cm.ref(WebServiceClient.class)); writeWebServiceClientAnnotation(service, webServiceClientAnn); // additional annotations for (GeneratorExtension f:ServiceFinder.find(GeneratorExtension.class)) { f.writeWebServiceClientAnnotation(options, cm, cls); } //@HandlerChain writeHandlerConfig(Names.customJavaTypeClassName(service.getJavaInterface()), cls, options); for (Port port : service.getPorts()) { if (port.isProvider()) { continue; // No getXYZPort() for porvider based endpoint } //Get the SEI class JType retType; try { retType = getClass(port.getJavaInterface().getName(), ClassType.INTERFACE); } catch (JClassAlreadyExistsException e) { QName portTypeName = (QName) port.getProperty( ModelProperties.PROPERTY_WSDL_PORT_TYPE_NAME); Locator loc = null; if (portTypeName != null) { PortType pt = port.portTypes.get(portTypeName); if (pt != null) { loc = pt.getLocator(); } } receiver.error(loc, GeneratorMessages.GENERATOR_SEI_CLASS_ALREADY_EXIST(port.getJavaInterface().getName(), portTypeName)); return; } //write getXyzPort() writeDefaultGetPort(port, retType, cls); //write getXyzPort(WebServicesFeature...) if (options.target.isLaterThan(Options.Target.V2_1)) { writeGetPort(port, retType, cls); } } writeGetWsdlLocation(cm.ref(URL.class), cls, urlField, exField); } private void writeGetPort(Port port, JType retType, JDefinedClass cls) { JMethod m = cls.method(JMod.PUBLIC, retType, port.getPortGetter()); JDocComment methodDoc = m.javadoc(); if (port.getJavaDoc() != null) { methodDoc.add(port.getJavaDoc()); } JCommentPart ret = methodDoc.addReturn(); JCommentPart paramDoc = methodDoc.addParam("features"); paramDoc.append("A list of "); paramDoc.append("{@link " + WebServiceFeature.class.getName() + "}"); paramDoc.append("to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values."); ret.add("returns " + retType.name()); m.varParam(WebServiceFeature.class, "features"); JBlock body = m.body(); StringBuilder statement = new StringBuilder("return "); statement.append("super.getPort(new QName(\"").append(port.getName().getNamespaceURI()).append("\", \"").append(port.getName().getLocalPart()).append("\"), "); statement.append(retType.name()); statement.append(".class, features);"); body.directStatement(statement.toString()); writeWebEndpoint(port, m); } /* Generates the code to create URL for absolute WSDL location for e.g.: static { URL url = null; WebServiceException e = null; try { url = new URL("http://ExampleService.wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } EXAMPLESERVICE_WSDL_LOCATION = url; EXAMPLESERVICE_EXCEPTION = e; } */ private void writeAbsWSDLLocation(JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { JBlock staticBlock = cls.init(); JVar urlVar = staticBlock.decl(cm.ref(URL.class), "url", JExpr._null()); JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); JTryBlock tryBlock = staticBlock._try(); tryBlock.body().assign(urlVar, JExpr._new(cm.ref(URL.class)).arg(wsdlLocation)); JCatchBlock catchBlock = tryBlock._catch(cm.ref(MalformedURLException.class)); catchBlock.param("ex"); catchBlock.body().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg(JExpr.ref("ex"))); staticBlock.assign(urlField, urlVar); staticBlock.assign(exField, exVar); } /* Generates the code to create URL for WSDL location as resource for e.g.: static { EXAMPLESERVICE_WSDL_LOCATION = ExampleService.class.getResource(...); Exception e = null; if (EXAMPLESERVICE_WSDL_LOCATION == null) { e = new WebServiceException("..."); } EXAMPLESERVICE_EXCEPTION = e; } */ private void writeResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { JBlock staticBlock = cls.init(); staticBlock.assign(urlField, JExpr.dotclass(cm.ref(className)).invoke("getResource").arg(wsdlLocation)); JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); JConditional ifBlock = staticBlock._if(urlField.eq(JExpr._null())); ifBlock._then().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg( "Cannot find "+JExpr.quotify('\'', wsdlLocation)+" wsdl. Place the resource correctly in the classpath.")); staticBlock.assign(exField, exVar); } /* Generates the code to create URL for WSDL location as classloader resource for e.g.: static { EXAMPLESERVICE_WSDL_LOCATION = ExampleService.class.getClassLoader().getResource(...); Exception e = null; if (EXAMPLESERVICE_WSDL_LOCATION == null) { e = new WebServiceException("..."); } EXAMPLESERVICE_EXCEPTION = e; } */ private void writeClassLoaderResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { JBlock staticBlock = cls.init(); staticBlock.assign(urlField, JExpr.dotclass(cm.ref(className)).invoke("getClassLoader").invoke("getResource").arg(wsdlLocation)); JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); JConditional ifBlock = staticBlock._if(urlField.eq(JExpr._null())); ifBlock._then().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg( "Cannot find "+JExpr.quotify('\'', wsdlLocation)+" wsdl. Place the resource correctly in the classpath.")); staticBlock.assign(exField, exVar); } /* Generates the code to create URL for WSDL location from classloader base resource for e.g.: static { Exception e = null; URL url = null; try { url = new URL(ExampleService.class.getClassLoader().getResource("."), ...); } catch (MalformedURLException murl) { e = new WebServiceException(murl); } EXAMPLESERVICE_WSDL_LOCATION = url; EXAMPLESERVICE_EXCEPTION = e; } */ private void writeClassLoaderBaseResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { JBlock staticBlock = cls.init(); JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); JVar urlVar = staticBlock.decl(cm.ref(URL.class), "url", JExpr._null()); JTryBlock tryBlock = staticBlock._try(); tryBlock.body().assign(urlVar, JExpr._new(cm.ref(URL.class)).arg(JExpr.dotclass(cm.ref(className)).invoke("getResource").arg(".")).arg(wsdlLocation)); JCatchBlock catchBlock = tryBlock._catch(cm.ref(MalformedURLException.class)); JVar murlVar = catchBlock.param("murl"); catchBlock.body().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg(murlVar)); staticBlock.assign(urlField, urlVar); staticBlock.assign(exField, exVar); } /* Generates code that gives wsdl URL. If there is an exception in creating the URL, it throws an exception. for example: private URL __getWsdlLocation() { if (EXAMPLESERVICE_EXCEPTION != null) { throw EXAMPLESERVICE_EXCEPTION; } return EXAMPLESERVICE_WSDL_LOCATION; } */ private void writeGetWsdlLocation(JType retType, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { JMethod m = cls.method(JMod.PRIVATE|JMod.STATIC , retType, "__getWsdlLocation"); JConditional ifBlock = m.body()._if(exField.ne(JExpr._null())); ifBlock._then()._throw(exField); m.body()._return(urlField); } private void writeDefaultGetPort(Port port, JType retType, JDefinedClass cls) { String portGetter = port.getPortGetter(); JMethod m = cls.method(JMod.PUBLIC, retType, portGetter); JDocComment methodDoc = m.javadoc(); if (port.getJavaDoc() != null) { methodDoc.add(port.getJavaDoc()); } JCommentPart ret = methodDoc.addReturn(); ret.add("returns " + retType.name()); JBlock body = m.body(); StringBuilder statement = new StringBuilder("return "); statement.append("super.getPort(new QName(\"").append(port.getName().getNamespaceURI()).append("\", \"").append(port.getName().getLocalPart()).append("\"), "); statement.append(retType.name()); statement.append(".class);"); body.directStatement(statement.toString()); writeWebEndpoint(port, m); } private void writeWebServiceClientAnnotation(Service service, JAnnotationUse wsa) { String serviceName = service.getName().getLocalPart(); String serviceNS = service.getName().getNamespaceURI(); wsa.param("name", serviceName); wsa.param("targetNamespace", serviceNS); wsa.param("wsdlLocation", wsdlLocation); } private void writeWebEndpoint(Port port, JMethod m) { JAnnotationUse webEndpointAnn = m.annotate(cm.ref(WebEndpoint.class)); webEndpointAnn.param("name", port.getName().getLocalPart()); } }