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: package org.netbeans.modules.visualweb.websvcmgr.consumer;
042:
043: import java.io.DataInputStream;
044: import java.io.DataOutputStream;
045: import java.io.File;
046: import java.io.FileOutputStream;
047: import java.io.FileWriter;
048: import java.io.IOException;
049: import java.lang.reflect.Method;
050: import java.net.URISyntaxException;
051: import java.net.URL;
052: import java.net.URLClassLoader;
053: import java.util.ArrayList;
054: import java.util.HashMap;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Map;
058: import java.util.Properties;
059: import javax.swing.Action;
060: import org.apache.tools.ant.module.api.support.ActionUtils;
061: import org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderBeanInfoWriter;
062: import org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderDesignInfoWriter;
063: import org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderInfo;
064: import org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderWriter;
065: import org.netbeans.modules.visualweb.websvcmgr.codegen.WrapperClientBeanInfoWriter;
066: import org.netbeans.modules.visualweb.websvcmgr.codegen.WrapperClientWriter;
067: import org.netbeans.modules.visualweb.websvcmgr.util.Util;
068: import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlPort;
069: import org.netbeans.modules.websvc.manager.api.WebServiceDescriptor;
070: import org.netbeans.modules.websvc.manager.spi.WebServiceManagerExt;
071: import org.netbeans.modules.websvc.manager.util.ManagerUtil;
072: import org.netbeans.modules.websvc.saas.spi.websvcmgr.WsdlServiceProxyDescriptor.JarEntry;
073: import org.openide.DialogDisplayer;
074: import org.openide.ErrorManager;
075: import org.openide.NotifyDescriptor;
076: import org.openide.execution.ExecutorTask;
077: import org.openide.filesystems.FileUtil;
078: import org.openide.modules.InstalledFileLocator;
079: import org.openide.nodes.Node;
080: import org.openide.util.NbBundle;
081:
082: /**
083: * WebServiceManagerExt implementation for the Visualweb page designer
084: *
085: * @author quynguyen
086: */
087: public class DesignerWebServiceExtImpl implements WebServiceManagerExt {
088: protected static final String VW_DESIGNTIME_JAR = "vw-dt";
089:
090: public static final String CONSUMER_ID = DesignerWebServiceExtImpl.class
091: .getName();
092: private static final String WEBSVC_HOME_PROP = "websvc.home";
093: private static final String USER_FILE_PROP = "user.properties.file";
094: private static final String WSDL_DIRNAME_PROP = "serviceDirName";
095: private static final String WSDL_NAME_PROP = "serviceName";
096: private static final String WSDL_FILE_NAME_PROP = "wsdlFileName";
097: private static final String PACKAGE_NAME = "packageName";
098: private static final String PACKAGE_DIR = "packageDir";
099: private static final String DESIGNTIME_CLASSPATH = "designtime.classpath";
100: private static final String wsImportCompileScriptName = "ws_import_compile.xml";
101:
102: private static File wsImportCompileScript;
103:
104: private final String userDir = System.getProperty("netbeans.user");
105:
106: public DesignerWebServiceExtImpl() {
107: }
108:
109: private void notifyError(int wsType) {
110: String bundleKey = (wsType == WebServiceDescriptor.JAX_WS_TYPE) ? "CODEGEN_ERROR_JAXWS"
111: : "CODEGEN_ERROR_JAXRPC"; // NOI18N
112:
113: String errorMessage = NbBundle.getMessage(
114: DesignerWebServiceExtImpl.class, bundleKey);
115: NotifyDescriptor d = new NotifyDescriptor.Message(errorMessage);
116: DialogDisplayer.getDefault().notify(d);
117: }
118:
119: public boolean wsServiceAddedExt(WebServiceDescriptor wsMetadataDesc) {
120: boolean result = createClientClasses(wsMetadataDesc);
121:
122: if (!result) {
123: notifyError(wsMetadataDesc.getWsType());
124: return false;
125: }
126:
127: boolean jarResult = jarGeneratedClasses(wsMetadataDesc);
128: if (!jarResult) {
129: removeBuildFiles(wsMetadataDesc.getXmlDescriptorFile()
130: .getParentFile());
131: wsMetadataDesc.removeConsumerData(CONSUMER_ID);
132: notifyError(wsMetadataDesc.getWsType());
133: } else {
134: wsMetadataDesc.addJar(wsMetadataDesc.getName() + "-dt.jar",
135: VW_DESIGNTIME_JAR);
136: wsMetadataDesc.addJar(wsMetadataDesc.getName()
137: + "-dt-src.jar",
138: WebServiceDescriptor.JarEntry.SRC_JAR_TYPE);
139: }
140:
141: return jarResult;
142: }
143:
144: public boolean wsServiceRemovedExt(
145: WebServiceDescriptor wsMetadataDesc) {
146: removeBuildFiles(wsMetadataDesc.getXmlDescriptorFile()
147: .getParentFile());
148: wsMetadataDesc.removeConsumerData(CONSUMER_ID);
149: return true;
150: }
151:
152: private boolean jarGeneratedClasses(
153: WebServiceDescriptor wsMetadataDesc) {
154: try {
155: Properties antProps = createAntProperties(wsMetadataDesc);
156: String antTarget = (wsMetadataDesc.getWsType() == WebServiceDescriptor.JAX_WS_TYPE) ? "jaxws-dt-compile"
157: : "jaxrpc-dt-compile";
158:
159: ExecutorTask executorTask = ActionUtils.runTarget(FileUtil
160: .toFileObject(getAntScript()),
161: new String[] { antTarget }, antProps);
162:
163: executorTask.waitFinished();
164: return executorTask.result() == 0;
165: } catch (Exception ex) {
166: return false;
167: }
168: }
169:
170: private File getAntScript() {
171: if (wsImportCompileScript == null) {
172: wsImportCompileScript = InstalledFileLocator.getDefault()
173: .locate(wsImportCompileScriptName, "", // NOI18N
174: false);
175: }
176:
177: return wsImportCompileScript;
178: }
179:
180: private void removeBuildFiles(File directory) {
181: rmDir(new File(directory, "build")); // NOI18N
182: rmDir(new File(directory, "dt")); // NOI18N
183: rmDir(new File(directory, "src")); // NOI18N
184: }
185:
186: Properties createAntProperties(WebServiceDescriptor wsMetadataDesc)
187: throws URISyntaxException {
188: File wsdlFile = null;
189: try {
190: wsdlFile = new File(wsMetadataDesc.getWsdlUrl().toURI());
191: } catch (URISyntaxException ex) {
192: wsdlFile = new File(wsMetadataDesc.getWsdlUrl().getPath());
193: }
194:
195: String wsdlFileName = wsdlFile.getAbsolutePath();
196: String serviceDirName = wsMetadataDesc.getXmlDescriptorFile()
197: .getParentFile().getParentFile().getName();
198: String serviceName = wsMetadataDesc.getName();
199:
200: Properties properties = new Properties();
201:
202: properties.put(WEBSVC_HOME_PROP,
203: WebServiceDescriptor.WEBSVC_HOME);
204: // INFO - This build properties file contains the classpath information
205: // about all the library reference in the IDE
206: properties.put(USER_FILE_PROP, userDir + "/build.properties");
207: properties.put(WSDL_DIRNAME_PROP, serviceDirName);
208: properties.put(WSDL_NAME_PROP, serviceName);
209: properties.put(WSDL_FILE_NAME_PROP, wsdlFileName);
210: properties.put(PACKAGE_NAME, wsMetadataDesc.getPackageName());
211: properties.put(PACKAGE_DIR, wsMetadataDesc.getPackageName()
212: .replace('.', '/'));
213:
214: // TODO: provide the dataprovider classpath also form here
215: // Currently obtained by adding ${libs.jsf12-support.classpath} from USER_FILE_PROP
216: File designtimeJarFile = InstalledFileLocator.getDefault()
217: .locate("modules/ext/designtime.jar", null, true);
218: File designtimeBaseJar = InstalledFileLocator.getDefault()
219: .locate("modules/ext/designtime-base.jar", null, true);
220: File propEditors = InstalledFileLocator.getDefault().locate(
221: "modules/ext/editors.jar", null, true);
222:
223: String designtimeCP = designtimeJarFile.getAbsolutePath() + ":"
224: + designtimeBaseJar.getAbsolutePath() + ":"
225: + propEditors.getAbsolutePath();
226:
227: properties.put(DESIGNTIME_CLASSPATH, designtimeCP);
228:
229: return properties;
230: }
231:
232: boolean createClientClasses(WebServiceDescriptor wsMetadataDesc) {
233: boolean isJaxRpc = wsMetadataDesc.getWsType() == WebServiceDescriptor.JAX_RPC_TYPE;
234: String serviceHome = wsMetadataDesc.getXmlDescriptorFile()
235: .getParent();
236: String pkgNameDir = wsMetadataDesc.getPackageName().replace(
237: '.', '/');
238:
239: File sourceDir = new File(serviceHome + "/src/" + pkgNameDir);
240: File dtSourceDir = new File(serviceHome + "/dt/src/"
241: + pkgNameDir);
242: sourceDir.mkdirs();
243: dtSourceDir.mkdirs();
244:
245: Map<String, String> proxyBeanNames = new HashMap<String, String>();
246: Map<String, Map<String, String>> portDataProviderMap = new HashMap<String, Map<String, String>>();
247: DesignerWebServiceExtData data = new DesignerWebServiceExtData();
248:
249: data.setPortToDataProviderMap(portDataProviderMap);
250: data.setPortToProxyBeanNameMap(proxyBeanNames);
251:
252: int portsCreated = 0;
253: List<WsdlPort> ports = wsMetadataDesc.getModel().getPorts();
254: assert ports.size() > 0 : "ports.size = " + ports.size();
255: for (WsdlPort port : ports) {
256: // There will be one client wrapper class per web service port. All the classes (client wrapper class,
257: // data provider classes) for the port will live in a sub-package with the port display name (in lower cases)
258:
259: // Skip non-SOAP ports
260: if (port.getAddress() == null) {
261: continue;
262: }
263:
264: Map<String, String> methodToDataProviderClassMap = new HashMap<String, String>();
265: String className = port.getName() + "Client";
266: String serviceClassName = wsMetadataDesc.getModel()
267: .getJavaName();
268: String javaName = port.getJavaName();
269:
270: File webserviceClient = new File(sourceDir, className
271: + ".java"); // NOI18N
272: File webserviceClientBeanInfo = new File(dtSourceDir,
273: className + "BeanInfo.java"); // NOI18N
274:
275: WrapperClientWriter beanWriter = null;
276: WrapperClientBeanInfoWriter beanInfoWriter = null;
277:
278: try {
279: File proxyJar = null;
280: for (JarEntry entry : wsMetadataDesc.getJars()) {
281: if (entry.getType().equals(JarEntry.PROXY_JAR_TYPE)) {
282: proxyJar = new File(serviceHome, entry
283: .getName());
284: }
285: }
286:
287: if (proxyJar == null) {
288: ErrorManager.getDefault().log(
289: ErrorManager.ERROR,
290: "Could not find proxy jar for port: "
291: + port.getName());
292: continue;
293: }
294:
295: // Create a temporary jar so the proxy jar is not locked (for further updates + deletions)
296: File tmpProxy = createTempCopy(proxyJar);
297: if (tmpProxy != null) {
298: tmpProxy.deleteOnExit();
299: } else {
300: tmpProxy = proxyJar;
301: }
302:
303: URLClassLoader classLoader = new URLClassLoader(
304: ManagerUtil
305: .buildClasspath(
306: tmpProxy,
307: wsMetadataDesc.getWsType() == WebServiceDescriptor.JAX_WS_TYPE)
308: .toArray(new URL[0]), this .getClass()
309: .getClassLoader());
310:
311: String portImplMethod = null;
312: String portImplClassName = null;
313: Class serviceClass = null;
314:
315: // Verify that the port getter method exists in the Service class, otherwise
316: // the code generation in WrapperClientWriter will fail
317: try {
318: serviceClass = classLoader
319: .loadClass(serviceClassName);
320: } catch (ClassNotFoundException e) {
321: try {
322: serviceClassName = wsMetadataDesc
323: .getPackageName()
324: + "."
325: + wsMetadataDesc.getModel().getName(); // NOI18N
326: serviceClass = classLoader
327: .loadClass(serviceClassName);
328: } catch (ClassNotFoundException cnfe) {
329: ErrorManager.getDefault().log(
330: ErrorManager.INFORMATIONAL,
331: "Unable to load service class for port: "
332: + port.getName());
333: continue;
334: }
335: }
336:
337: try {
338: portImplMethod = port.getPortGetter();
339: serviceClass.getMethod(portImplMethod);
340: } catch (NoSuchMethodException e) {
341: for (Method method : serviceClass.getMethods()) {
342: String name = method.getName();
343: if (name.startsWith("get")
344: && name.toLowerCase().contains(
345: port.getName().toLowerCase())) { // NOI18N
346: portImplMethod = method.getName();
347: portImplClassName = method.getReturnType()
348: .getName();
349: break;
350: }
351: }
352:
353: if (portImplClassName == null) {
354: ErrorManager.getDefault().log(
355: ErrorManager.INFORMATIONAL,
356: "Unable to find getter method for port: "
357: + port.getName());
358: continue;
359: }
360: }
361:
362: // Use reflection to get the proxy class methods; needed because the JAX-WS model is not
363: // valid for JAX-RPC clients
364: Class proxyClass = null;
365: try {
366: proxyClass = classLoader.loadClass(javaName);
367: portImplClassName = null;
368: } catch (ClassNotFoundException cnfe) {
369: if (portImplClassName == null) {
370: ErrorManager.getDefault().log(
371: ErrorManager.INFORMATIONAL,
372: "Could not load class: " + javaName);
373: continue;
374: } else {
375: try {
376: proxyClass = classLoader
377: .loadClass(portImplClassName);
378: } catch (ClassNotFoundException ex) {
379: ErrorManager.getDefault().log(
380: ErrorManager.INFORMATIONAL,
381: "Could not load class: "
382: + portImplClassName);
383: continue;
384: }
385: }
386: }
387:
388: java.lang.reflect.Method[] methods = proxyClass
389: .getDeclaredMethods();
390: ArrayList<java.lang.reflect.Method> methodList = new ArrayList<java.lang.reflect.Method>();
391: for (int index = 0; index < methods.length; index++) {
392: methodList.add(methods[index]);
393: }
394:
395: beanWriter = new WrapperClientWriter(new FileWriter(
396: webserviceClient), wsMetadataDesc, isJaxRpc,
397: methodList, port.getOperations());
398:
399: beanInfoWriter = new WrapperClientBeanInfoWriter(
400: new FileWriter(webserviceClientBeanInfo));
401:
402: beanWriter.setClassLoader(classLoader);
403: beanWriter.setPackage(wsMetadataDesc.getPackageName());
404: beanWriter.setClassName(className);
405: beanWriter.setContainedClassInfo(serviceClassName);
406: beanWriter.addImport(wsMetadataDesc.getPackageName()
407: + ".*");
408: beanWriter.setPort(port);
409: beanWriter.setPortGetterMethod(portImplMethod);
410: beanWriter.setPortClassName(portImplClassName);
411: beanWriter.writeClass();
412: beanWriter.flush();
413: beanWriter.close();
414:
415: beanInfoWriter.setPackage(wsMetadataDesc
416: .getPackageName());
417: beanInfoWriter.setClassName(className);
418: beanInfoWriter.writeBeanInfo();
419: beanInfoWriter.flush();
420: beanInfoWriter.close();
421:
422: // Now generate the data provider classes
423: HashMap<String, String> methodToDataProviderTempMap = new HashMap<String, String>();
424: for (Iterator iter = beanWriter.getDataProviders()
425: .iterator(); iter.hasNext();) {
426: DataProviderInfo dp = (DataProviderInfo) iter
427: .next();
428:
429: // update the Port method name to dpClassName mapping
430: methodToDataProviderTempMap.put(
431: Util.getMethodSignatureAsString(dp
432: .getMethod()), wsMetadataDesc
433: .getPackageName()
434: + "." + dp.getClassName());
435:
436: try {
437: // DataProvider.java
438: File dataProviderFile = new File(sourceDir, dp
439: .getClassName()
440: + ".java"); // NOI18N
441: DataProviderWriter dpWriter = new DataProviderWriter(
442: new FileWriter(dataProviderFile), dp,
443: !isJaxRpc);
444: dpWriter.setClassLoader(classLoader);
445: dpWriter.addImport(wsMetadataDesc
446: .getPackageName()
447: + ".*");
448: dpWriter.writeClass();
449: dpWriter.flush();
450: dpWriter.close();
451:
452: // DataProviderBeanInfo.java
453: File dataProviderBeanInfoFile = new File(
454: dtSourceDir, dp.getClassName()
455: + "BeanInfo.java"); // NOI18N
456: DataProviderBeanInfoWriter dpBeanInfoWriter = new DataProviderBeanInfoWriter(
457: new FileWriter(dataProviderBeanInfoFile),
458: dp);
459: dpBeanInfoWriter.writeClass();
460: dpBeanInfoWriter.flush();
461: dpBeanInfoWriter.close();
462:
463: // DataProviderDesignInfo.java
464: // Since the DesignInfo classes are going to be jarred into a separate jar, use a different dir for the source code
465: File dataProviderDesignInfoFile = new File(
466: dtSourceDir, dp.getClassName()
467: + "DesignInfo.java"); // NOI18N
468: DataProviderDesignInfoWriter dpDesignInfoWriter = new DataProviderDesignInfoWriter(
469: new FileWriter(
470: dataProviderDesignInfoFile), dp);
471: dpDesignInfoWriter.writeClass();
472: dpDesignInfoWriter.flush();
473: dpDesignInfoWriter.close();
474:
475: } catch (IOException ioe) {
476: ErrorManager.getDefault().notify(ioe);
477: return false;
478: }
479: }
480:
481: copyIcons(dtSourceDir);
482:
483: // This will be persisted for next IDE session (all the persisted data
484: // needs to be recorded last to prevent errors from corrupting the data structure
485: portDataProviderMap.put(port.getName(),
486: methodToDataProviderClassMap);
487: proxyBeanNames.put(port.getName(), wsMetadataDesc
488: .getPackageName()
489: + "." + className);
490:
491: for (String key : methodToDataProviderTempMap.keySet()) {
492: String value = methodToDataProviderTempMap.get(key);
493: methodToDataProviderClassMap.put(key, value);
494: }
495:
496: portsCreated++;
497: } catch (IOException ioe) {
498: ErrorManager.getDefault().notify(ioe);
499: return false;
500: }
501: }
502:
503: boolean result = portsCreated > 0;
504: if (result) {
505: wsMetadataDesc.addConsumerData(CONSUMER_ID, data);
506: }
507:
508: return result;
509: }
510:
511: private void copyIcons(File dtSourceDir) {
512:
513: /**
514: * Now copy the web service icon image to the folder that will be jarred up.
515: */
516: try {
517: // Copy the Image contents from the URL into the new file craeted in the backing folder.
518: URL[] imageUrls = new URL[] {
519: ManagerUtil.class
520: .getResource("/org/netbeans/modules/websvc/manager/resources/webservice.png"),
521: ManagerUtil.class
522: .getResource("/org/netbeans/modules/websvc/manager/resources/methodicon.png"),
523: ManagerUtil.class
524: .getResource("/org/netbeans/modules/websvc/manager/resources/table_dp_badge.png") };
525: String[] imageFileNames = new String[] {
526: ManagerUtil
527: .getFileName(WrapperClientBeanInfoWriter.WEBSERVICE_ICON_FILENAME),
528: ManagerUtil
529: .getFileName(org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderBeanInfoWriter.DATA_PROVIDER_ICON_FILE_NAME),
530: ManagerUtil
531: .getFileName(org.netbeans.modules.visualweb.websvcmgr.codegen.DataProviderBeanInfoWriter.DATA_PROVIDER_ICON_FILE_NAME2) };
532:
533: for (int i = 0; i < imageUrls.length; i++) {
534: DataInputStream in = new DataInputStream(imageUrls[i]
535: .openStream());
536: File outputFile = new File(dtSourceDir,
537: imageFileNames[i]);
538: DataOutputStream outImage = new DataOutputStream(
539: new FileOutputStream(outputFile));
540:
541: byte[] bytes = new byte[1024];
542: int byteCount = in.read(bytes);
543:
544: while (byteCount > -1) {
545: outImage.write(bytes);
546: byteCount = in.read(bytes);
547: }
548: outImage.flush();
549: outImage.close();
550: in.close();
551: }
552: } catch (IOException ioe) {
553: ErrorManager.getDefault().notify(ioe);
554: }
555: }
556:
557: private File createTempCopy(File src) {
558: try {
559: java.io.File tempFile = java.io.File.createTempFile(
560: "proxyjar", "jar");
561: java.nio.channels.FileChannel inChannel = new java.io.FileInputStream(
562: src).getChannel();
563: java.nio.channels.FileChannel outChannel = new java.io.FileOutputStream(
564: tempFile).getChannel();
565: inChannel.transferTo(0, inChannel.size(), outChannel);
566:
567: inChannel.close();
568: outChannel.close();
569: return tempFile;
570: } catch (IOException ex) {
571: ErrorManager.getDefault().notify(ErrorManager.WARNING, ex);
572: return null;
573: }
574: }
575:
576: private void rmDir(File dir) {
577: File[] files = dir.listFiles();
578: for (int i = 0; files != null && i < files.length; i++) {
579: if (files[i].isDirectory()) {
580: rmDir(files[i]);
581: }
582: files[i].delete();
583: }
584: dir.delete();
585: }
586: }
|