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
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.websvcmgr.codegen;
043:
044: import com.sun.tools.ws.processor.model.Operation;
045: import java.io.IOException;
046: import java.lang.annotation.Annotation;
047: import java.lang.reflect.Method;
048: import java.net.URL;
049: import java.util.List;
050:
051: import org.netbeans.modules.visualweb.websvcmgr.util.Util;
052: import java.io.Writer;
053: import java.util.HashMap;
054: import java.util.HashSet;
055: import java.util.Iterator;
056: import java.util.Map;
057: import java.util.Set;
058: import javax.xml.bind.annotation.XmlType;
059: import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlOperation;
060: import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlPort;
061: import org.netbeans.modules.websvc.manager.api.WebServiceDescriptor;
062: import org.netbeans.modules.websvc.manager.util.ManagerUtil;
063:
064: /**
065: * A simple writer to write the Java Source.
066: * @author Winston Prakash, cao
067: */
068: public class WrapperClientWriter extends java.io.PrintWriter {
069:
070: private String serviceName;
071: private String serviceVariable;
072:
073: private String super ClassName;
074: private Set<String> interfaces = new HashSet<String>();
075: private String packageName;
076: private Set<String> imports = new HashSet<String>();
077: private String className;
078: private WebServiceDescriptor wsData;
079: private WsdlPort port;
080: private final List<WsdlOperation> operations;
081: private ClassLoader wsClassLoader;
082: private String portGetterMethod;
083: private String portClassName;
084:
085: int indent = 0;
086:
087: private Set<DataProviderInfo> dataProviders = new HashSet<DataProviderInfo>();
088: private final List<java.lang.reflect.Method> sortedMethods;
089: boolean isJaxRpc = false;
090:
091: /** Creates a new instance of JavaWriter */
092: public WrapperClientWriter(Writer writer,
093: WebServiceDescriptor wsData, boolean isJaxRpc,
094: List<java.lang.reflect.Method> sortedMethods,
095: List<WsdlOperation> operations) {
096: super (writer);
097:
098: this .operations = operations;
099: this .sortedMethods = sortedMethods;
100: this .isJaxRpc = isJaxRpc;
101: this .wsData = wsData;
102: // Always implements java.io.Seriazable
103: interfaces.add("java.io.Serializable");
104: }
105:
106: public void setContainedClassInfo(String serviceName) {
107: this .serviceName = serviceName;
108: serviceVariable = serviceName.substring(serviceName
109: .lastIndexOf('.') + 1, serviceName.length());
110: serviceVariable = serviceVariable.toLowerCase() + "1";
111: }
112:
113: public void setPortGetterMethod(String methodName) {
114: portGetterMethod = methodName;
115: }
116:
117: public void setPortClassName(String portClass) {
118: portClassName = portClass;
119: }
120:
121: public void setClassLoader(ClassLoader loader) {
122: this .wsClassLoader = loader;
123: }
124:
125: public Set getDataProviders() {
126: return this .dataProviders;
127: }
128:
129: /** Set package name */
130: public void setPackage(String pkgName) {
131: packageName = pkgName;
132: }
133:
134: public void setClassName(String className) {
135: this .className = className;
136: }
137:
138: public void addImport(String importLine) {
139: imports.add(importLine);
140: }
141:
142: public void setPort(WsdlPort port) {
143: this .port = port;
144: if (portGetterMethod == null) {
145: portGetterMethod = port.getPortGetter();
146: }
147: }
148:
149: /** Set the name of the super class this class would extends */
150: public void setSuperClass(String super Class) {
151: super ClassName = super Class;
152: }
153:
154: public void writeClass() throws IOException {
155: /**
156: * Write the package statement
157: */
158: println("package " + packageName + ";");
159: println();
160:
161: /**
162: * Write the imports statement.
163: */
164: if (!imports.isEmpty()) {
165: Iterator iter = imports.iterator();
166: while (iter.hasNext()) {
167: println("import " + iter.next() + ";");
168: }
169: println();
170: }
171:
172: if (isJaxRpc) {
173: println("import java.rmi.RemoteException;");
174: println("import javax.xml.rpc.Stub;");
175: println("import javax.xml.rpc.ServiceException;");
176: } else if (!isJaxRpc) {
177: println("import javax.xml.ws.BindingProvider;");
178: }
179:
180: println("import java.beans.Beans;");
181: println();
182:
183: /**
184: * Write the class declaration
185: */
186:
187: // The class name will be the port display + "Client"
188: print("public class " + className);
189: if (super ClassName != null)
190: print(" extends " + super ClassName + " ");
191: else
192: print(" ");
193: if (!interfaces.isEmpty()) {
194: print("implements ");
195: Iterator iter = interfaces.iterator();
196: while (iter.hasNext()) {
197: print((String) iter.next());
198: if (iter.hasNext())
199: print(",");
200: }
201: }
202: println(" {");
203: println();
204:
205: // write the class instance variables.
206:
207: // write a variable for the port
208:
209: // get the Java class name for the port
210: String portInterfaceName = (portClassName == null) ? port
211: .getJavaName() : portClassName;
212: /**
213: * Strip off the leading package qualification since we don't need it.
214: */
215: portInterfaceName = portInterfaceName.substring(
216: portInterfaceName.lastIndexOf('.') + 1,
217: portInterfaceName.length());
218: /**
219: * create the variable name for the port
220: * NOTE: - When we write out the methods, we'll need to use the same convention of naming the port that
221: * we do here.
222: */
223: String portInterfaceVariable = portInterfaceName.substring(
224: portInterfaceName.lastIndexOf('.') + 1,
225: portInterfaceName.length());
226: String portInterfacePrefix = portInterfaceVariable
227: .toLowerCase();
228: portInterfaceVariable = portInterfaceVariable.toLowerCase()
229: + "1";
230: /**
231: * Apparently, the compiletool uppercases the first letter of the port name to make it a proper getter so we need to do the same.
232: */
233: String modifiedPortName = ManagerUtil
234: .upperCaseFirstChar(portInterfaceName);
235:
236: println(" private " + portInterfaceName + " "
237: + portInterfaceVariable + ";");
238: println();
239:
240: // Variable to indicate whehther it is in test mode or ot
241: println(" private boolean testMode = false;");
242: println(" private boolean initialized = false;");
243:
244: // Write the constructor
245: println(" public " + className + "() {");
246: println(" }");
247:
248: // Now the methods
249: printOperations(port);
250:
251: // The method for turning on/off the test mode
252: println(" public void testMode( Boolean testing) {");
253: println(" this.testMode = testing.booleanValue();");
254: println(" }");
255: println();
256:
257: // write the initialize method (moved from the constructor to avoid unnecessary
258: // W/S instantiation during designtime)
259: if (isJaxRpc) {
260: println(" public void initialize() {");
261: println(" if (initialized) return;");
262: println(" System.setProperty(\"javax.xml.soap.MessageFactory\",\"com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl\");");
263: println(" try {");
264: println(" " + serviceName + " " + serviceVariable
265: + " = " + "new " + serviceName + "_Impl();");
266: println(" " + portInterfaceVariable + " = "
267: + serviceVariable + "." + portGetterMethod + "();");
268: println(" initialized = true;");
269: println(" } catch (ServiceException se) {");
270: println(" se.printStackTrace();");
271: println(" }");
272:
273: println(" }");
274: println();
275: } else {
276: // Instantiate the Service class, specifying the wsdl URL kept in the
277: // web service jar
278: URL url = wsData.getWsdlUrl();
279: String urlPath = url.getPath();
280: int start;
281: if (url.getProtocol().toLowerCase().startsWith("file")) { // NOI18N
282: start = urlPath.lastIndexOf(System
283: .getProperty("path.separator"));
284: start = (start < 0) ? urlPath.lastIndexOf("/") : start;
285: } else {
286: start = urlPath.lastIndexOf("/");
287: }
288: start = (start < 0 || start >= urlPath.length() - 1) ? 0
289: : start + 1;
290:
291: String wsdlFileName = urlPath.substring(start);
292: String namespace = wsData.getModel().getNamespaceURI();
293: String qname = wsData.getName();
294:
295: println(" public void initialize() {");
296: println(" if (initialized) return;");
297: println(" "
298: + "java.net.URL wsdl = this.getClass().getResource(\""
299: + wsdlFileName + "\");");
300: println(" " + serviceName + " " + serviceVariable
301: + " = " + "new " + serviceName
302: + "(wsdl, new javax.xml.namespace.QName(\""
303: + namespace + "\", \"" + qname + "\"));");
304: println(" " + portInterfaceVariable + " = "
305: + serviceVariable + "." + portGetterMethod + "();");
306: println(" initialized = true;");
307: println(" }");
308: println();
309: }
310:
311: // End of class
312: println("}");
313: }
314:
315: private void printOperations(WsdlPort port) {
316:
317: // This is to keep track of the overloadded method names
318: Map<String, Integer> methodNames = new HashMap<String, Integer>();
319:
320: /**
321: * get the Java class name for the port.
322: */
323: String portInterfaceName = (portClassName == null) ? port
324: .getJavaName() : portClassName;
325: /**
326: * Strip off the leading package qualification since we don't need it.
327: */
328: portInterfaceName = portInterfaceName.substring(
329: portInterfaceName.lastIndexOf('.') + 1,
330: portInterfaceName.length());
331: /**
332: * create the variable name for the port
333: * NOTE: -This variable name needs to be the same one written out for the class instance varables.
334: */
335: String portInterfaceVariable = portInterfaceName.substring(
336: portInterfaceName.lastIndexOf('.') + 1,
337: portInterfaceName.length());
338: String portInterfacePrefix = portInterfaceVariable
339: .toLowerCase();
340: portInterfaceVariable = portInterfaceVariable.toLowerCase()
341: + "1";
342:
343: // Use the internal model if doing jax-ws, otherwise use java reflection
344: Iterator<DataProviderMethod> methodIterator = null;
345: if (isJaxRpc) {
346: methodIterator = new Iterator<DataProviderMethod>() {
347: private int i = 0;
348:
349: public boolean hasNext() {
350: return i < sortedMethods.size();
351: }
352:
353: public DataProviderMethod next() {
354: java.lang.reflect.Method method = sortedMethods
355: .get(i++);
356: return new DataProviderJavaMethod(method);
357: }
358:
359: public void remove() {
360: throw new UnsupportedOperationException(
361: "Not supported yet.");
362: }
363: };
364: } else {
365: methodIterator = new Iterator<DataProviderMethod>() {
366: private int i = 0;
367:
368: public boolean hasNext() {
369: return i < operations.size();
370: }
371:
372: public DataProviderMethod next() {
373: Operation nextOperation = (Operation) operations
374: .get(i++).getInternalJAXWSOperation();
375: return new DataProviderModelMethod(nextOperation
376: .getJavaMethod());
377: }
378:
379: public void remove() {
380: throw new UnsupportedOperationException(
381: "Not supported yet.");
382: }
383: };
384: }
385:
386: while (methodIterator.hasNext()) {
387: DataProviderMethod method = methodIterator.next();
388:
389: println();
390:
391: String methodReturnTypeName = method.getMethodReturnType();
392: String methodName = method.getMethodName();
393:
394: print(" public " + methodReturnTypeName + " " + methodName
395: + "(");
396:
397: boolean firstParameter = true;
398: for (DataProviderParameter parameter : method
399: .getParameters()) {
400: if (!firstParameter) {
401: print(",");
402: } else {
403: firstParameter = false;
404: }
405:
406: print(parameter.getType() + " " + parameter.getName());
407: }
408: print(") ");
409:
410: boolean firstException = true;
411: for (String exceptionClass : method.getExceptions()) {
412: if (firstException) {
413: print(" throws ");
414: firstException = false;
415: } else {
416: print(", ");
417: }
418:
419: print(exceptionClass);
420: }
421: println(" {");
422:
423: if (!"void".equals(methodReturnTypeName)) {
424: println(" if( Beans.isDesignTime() && !testMode )");
425: println(" return "
426: + designTimeReturnValue(methodReturnTypeName)
427: + ";");
428: println(" else {");
429: println(" initialize();");
430: print(" return " + portInterfaceVariable + "."
431: + methodName + "(");
432: } else {
433: println(" if( Beans.isDesignTime() && !testMode ) ");
434: println(" return;");
435: println(" else {");
436: println(" initialize();");
437: print(" " + portInterfaceVariable + "."
438: + methodName + "(");
439: }
440:
441: firstParameter = true;
442: for (DataProviderParameter parameter : method
443: .getParameters()) {
444: if (!firstParameter) {
445: print(", ");
446: } else {
447: firstParameter = false;
448: }
449: print(parameter.getName());
450: }
451: println(");");
452: println(" }");
453: println(" }");
454:
455: // If this method return non-void, we'll need to generate DataProvider (readonly for now) for it
456: // For overloaded method, we'll index method names
457: if ((!isJaxRpc && Util
458: .hasOutput(((DataProviderModelMethod) method)
459: .getJavaMethod()))
460: || (isJaxRpc && !"void".equals(method
461: .getMethodReturnType()))) { // NOI18N
462: String dpClassName = method.getMethodName();
463:
464: Integer occurrence = methodNames.get(method
465: .getMethodName());
466: if (occurrence == null)
467: occurrence = new Integer(1);
468: else {
469: occurrence = new Integer(occurrence.intValue() + 1);
470:
471: // The data provider class name = method name + num of occurrence
472: dpClassName = method.getMethodName() + occurrence;
473: }
474: methodNames.put(method.getMethodName(), occurrence);
475:
476: DataProviderInfo info = new DataProviderInfo(
477: packageName, className, method, dpClassName);
478: dataProviders.add(info);
479:
480: if (!isJaxRpc) {
481: int index = Util
482: .getOutputHolderIndex(((DataProviderModelMethod) method)
483: .getJavaMethod());
484: info.setOutputHolderIndex(index);
485:
486: String returnTypeClass = method
487: .getMethodReturnType();
488: returnTypeClass = returnTypeClass.substring(0,
489: separateGenericType(returnTypeClass));
490:
491: if (isWrappedClass(returnTypeClass)) {
492: DataProviderParameter returnType = getSingleProperty(returnTypeClass);
493:
494: if (returnType != null) {
495: String propertyType = returnType.getType();
496: propertyType = propertyType.substring(0,
497: separateGenericType(propertyType));
498:
499: if (!Util.isPrimitiveType(propertyType)) {
500: info.setWrappedProperty(returnType);
501: }
502: }
503: }
504: }
505: }
506: }
507:
508: /**
509: * Now print out the methods for setting the Stub properties.
510: */
511: // Cast the inteface to Stub (jaxrpc)
512: if (isJaxRpc) {
513: String stubVar = "((Stub)" + portInterfaceVariable + ")";
514:
515: println(" public void setUsername(String inUserName) {");
516: println(" initialize();");
517: println(" "
518: + stubVar
519: + "._setProperty(Stub.USERNAME_PROPERTY, inUserName);");
520: println(" }");
521: println();
522:
523: println(" public void setPassword(String inPassword) {");
524: println(" initialize();");
525: println(" "
526: + stubVar
527: + "._setProperty(Stub.PASSWORD_PROPERTY, inPassword);");
528: println(" }");
529: println();
530:
531: println(" public void setAddress(String inAddress) {");
532: println(" initialize();");
533: println(" "
534: + stubVar
535: + "._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, inAddress);");
536: println(" }");
537: println();
538: } else {
539: String bindingVar = "((BindingProvider)"
540: + portInterfaceVariable + ")";
541:
542: println(" public void setUsername(String inUserName) {");
543: println(" initialize();");
544: println(" "
545: + bindingVar
546: + ".getRequestContext().put(BindingProvider.USERNAME_PROPERTY, inUserName);");
547: println(" }");
548: println();
549:
550: println(" public void setPassword(String inPassword) {");
551: println(" initialize();");
552: println(" "
553: + bindingVar
554: + ".getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, inPassword);");
555: println(" }");
556: println();
557:
558: println(" public void setAddress(String inAddress) {");
559: println(" initialize();");
560: println(" "
561: + bindingVar
562: + ".getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, inAddress);");
563: println(" }");
564: println();
565: }
566: }
567:
568: // XXX taken from ReflectionHelper helper methods
569: private boolean isWrappedClass(String typeClass) {
570: try {
571: Class type = Class.forName(typeClass, true, wsClassLoader);
572: Class xmlType = Class.forName(XmlType.class.getName(),
573: true, wsClassLoader);
574:
575: Annotation xmlAnnotation = type.getAnnotation(xmlType);
576: boolean isEnumeration = Enum.class.isAssignableFrom(type);
577:
578: return xmlAnnotation != null && !isEnumeration;
579: } catch (ClassNotFoundException cnfe) {
580: return false;
581: }
582: }
583:
584: private DataProviderParameter getSingleProperty(String typeClass) {
585: List<String> properties = getPropertyNames(typeClass,
586: wsClassLoader);
587: if (properties == null || properties.size() != 1) {
588: return null;
589: } else {
590: String name = properties.get(0);
591: Method getter = Util.getPropertyGetter(typeClass, name,
592: wsClassLoader);
593: if (getter != null) {
594: String type = ManagerUtil.typeToString(getter
595: .getGenericReturnType());
596: return new DataProviderParameter(type, name);
597: } else {
598: return null;
599: }
600: }
601: }
602:
603: // TODO - merge this with ReflectionHelper.separateGenericType
604: private int separateGenericType(String typeName) {
605: int length = typeName.length();
606:
607: if (length < 2 || typeName.charAt(length - 1) != '>') { // NOI18N
608: return length;
609: } else {
610: int depth = 1;
611: for (int i = length - 2; i >= 0; i--) {
612: if (typeName.charAt(i) == '>') {
613: depth += 1;
614: } else if (typeName.charAt(i) == '<') {
615: depth -= 1;
616: }
617:
618: if (depth == 0) {
619: return i;
620: }
621: }
622:
623: return length;
624: }
625: }
626:
627: private List<String> getPropertyNames(String complexType,
628: ClassLoader loader) {
629: try {
630: List<String> properties = new java.util.ArrayList<String>();
631:
632: Class nextClass = Class.forName(complexType, true, loader);
633: Class xmlTypeClass = Class.forName(XmlType.class.getName(),
634: true, loader);
635:
636: for (; nextClass != null; nextClass = nextClass
637: .getSuperclass()) {
638: Annotation annotation = nextClass
639: .getAnnotation(xmlTypeClass);
640: if (annotation == null) {
641: break;
642: }
643:
644: try {
645: Method m = annotation.getClass().getMethod(
646: "propOrder", new Class[0]); // NOI18N
647: String[] props = (String[]) m.invoke(annotation);
648:
649: for (int i = 0; props != null && i < props.length; i++) {
650: if (props[i] != null && props[i].length() > 0)
651: properties.add(props[i]);
652: }
653: } catch (Exception ex) {
654: }
655: }
656:
657: return properties;
658: } catch (Exception ex) {
659: return new java.util.ArrayList<String>();
660: }
661: }
662:
663: private String designTimeReturnValue(String returnType) {
664:
665: String fakeReturn = "null";
666:
667: // Can be one of the following:
668: // int, long, double, float, short, byte
669: // char
670: // boolean
671: // void
672: if (returnType.equals("int") || returnType.equals("long")
673: || returnType.equals("double")
674: || returnType.equals("float")
675: || returnType.equals("short")
676: || returnType.equals("byte")) {
677: return "0";
678: } else if (returnType.equals("boolean")) {
679: return "false";
680: } else if (returnType.equals("char")) {
681: return "\'A\'";
682: } else if (returnType.equals("java.lang.String")) {
683: return "\"ABC\"";
684: } else
685: // return null for all object return type
686: return null;
687: }
688: }
|