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: * DataProviderGenerator.java
043: *
044: * Created on February 14, 2005, 3:19 PM
045: */
046:
047: package org.netbeans.modules.visualweb.ejb.load;
048:
049: import org.netbeans.modules.visualweb.ejb.datamodel.MethodInfo;
050: import org.netbeans.modules.visualweb.ejb.datamodel.MethodParam;
051: import org.netbeans.modules.visualweb.ejb.util.Util;
052: import java.io.File;
053: import java.io.FileOutputStream;
054: import java.io.PrintWriter;
055: import java.net.URLClassLoader;
056: import java.util.ArrayList;
057: import java.util.Collection;
058: import java.util.Date;
059: import java.util.Iterator;
060:
061: /**
062: * This class is to help generate a data provider class for a given method.
063: * The generated data provide implements IndexedDataProvider if the given method
064: * returns a Collection or Array. Otherwise, a base DataProvider interface is implemented
065: *
066: * @author dongmei cao
067: */
068: public class DataProviderGenerator {
069: private static String[] PRIMITIVE_TYPES = { "char", "byte",
070: "short", "int", "long", "float", "double", "boolean" };
071:
072: private static String[] PRIMITIVE_WRAPPERS = {
073: "java.lang.Character", "java.lang.Byte", "java.lang.Short",
074: "java.lang.Integer", "java.lang.Long", "java.lang.Float",
075: "java.lang.Double", "java.lang.Boolean" };
076:
077: private String packageName;
078: private String clientWrapperClassName;
079: private MethodInfo methodInfo;
080: private URLClassLoader classLoader;
081:
082: public DataProviderGenerator() {
083: }
084:
085: public DataProviderGenerator(String clientWrapperFullClassName,
086: MethodInfo methodInfo, URLClassLoader classLoader) {
087:
088: // Get the package name
089: int lastDot = clientWrapperFullClassName.lastIndexOf('.');
090: packageName = clientWrapperFullClassName.substring(0, lastDot);
091:
092: // The class name
093: this .clientWrapperClassName = Util
094: .getClassName(clientWrapperFullClassName);
095:
096: this .methodInfo = methodInfo;
097: this .classLoader = classLoader;
098: }
099:
100: public Collection generateClasses(String srcDir)
101: throws EjbLoadException {
102:
103: // First, generate the bean class source code
104: ClassDescriptor[] beanClassDescriptor = generateBeanClass(
105: srcDir, packageName);
106:
107: // Take care the case where there is no package
108: String beanClassName = beanClassDescriptor[0].getPackageName()
109: + "." + beanClassDescriptor[0].getClassName();
110: if (beanClassDescriptor[0].getPackageName() == null
111: || beanClassDescriptor[0].getPackageName().length() == 0)
112: beanClassName = beanClassDescriptor[0].getClassName();
113:
114: // Now, Generate the BeanInfo class source code
115: DataProviderBeanInfoGenerator beanInfoGenerator = new DataProviderBeanInfoGenerator(
116: beanClassName, methodInfo, clientWrapperClassName);
117: ClassDescriptor beanInfoClassDescriptor = beanInfoGenerator
118: .generateClass(srcDir);
119:
120: // Add generate the DesignInfo class souce code
121: DataProviderDesignInfoGenerator designInfoGenerator = new DataProviderDesignInfoGenerator(
122: clientWrapperClassName, beanClassName, methodInfo);
123: ClassDescriptor[] designInfoClassDescriptors = designInfoGenerator
124: .generateClass(srcDir);
125:
126: // Done! Return all the class descriptors
127:
128: ArrayList classDescriptors = new ArrayList();
129: for (int i = 0; i < beanClassDescriptor.length; i++) {
130: classDescriptors.add(beanClassDescriptor[i]);
131: }
132:
133: classDescriptors.add(beanInfoClassDescriptor);
134:
135: for (int i = 0; i < designInfoClassDescriptors.length; i++)
136: classDescriptors.add(designInfoClassDescriptors[i]);
137:
138: return classDescriptors;
139: }
140:
141: public ClassDescriptor[] generateBeanClass(String srcDir,
142: String packageName) throws EjbLoadException {
143: // Declare it outside the try-catch so that the file name can be logged in case of exception
144: File javaFile = null;
145:
146: try {
147: // Update the data provider with full package data provider class name
148: String className = methodInfo.getDataProvider();
149: methodInfo.setDataProvider(packageName + "." + className);
150:
151: String classDir = packageName.replace('.',
152: File.separatorChar);
153: File dirF = new File(srcDir + File.separator + classDir);
154: if (!dirF.exists()) {
155: if (!dirF.mkdirs())
156: System.out.println(".....failed to make dir"
157: + srcDir + File.separator + classDir);
158: }
159:
160: String classFile = className + ".java"; // NOI18N
161: javaFile = new File(dirF, classFile);
162: javaFile.createNewFile();
163:
164: ClassDescriptor classDescriptor = new ClassDescriptor(
165: className, // class name
166: packageName, // package name
167: javaFile.getAbsolutePath(), // full path java file name
168: classDir + File.separator + classFile); // file name with package in path
169:
170: ClassDescriptor helperDescriptor = new ClassDescriptor(
171: className + "$ResultBean", packageName, new File(
172: dirF, className + "$ResultBean.class")
173: .getAbsolutePath(), classDir
174: + File.separator + className
175: + "$ResultBean.class", true);
176:
177: String qualifiedClassName = packageName + "." + className;
178: String qualifiedClientWrapperName = packageName + "."
179: + clientWrapperClassName;
180:
181: // Generate java code
182:
183: PrintWriter out = new PrintWriter(new FileOutputStream(
184: javaFile));
185:
186: // package
187: if (packageName != null && packageName.length() != 0) {
188: out.println("package " + packageName + ";");
189: out.println();
190: }
191:
192: // comments
193: out.println("/**");
194: out.println(" * Source code created on " + new Date());
195: out.println(" */");
196: out.println();
197:
198: // start of class
199: String dpSuperClassName = "com.sun.data.provider.impl.MethodResultTableDataProvider";
200: //String dpSuperClassName = "MethodResultDataProvider";
201:
202: out.println("public class " + className + " extends "
203: + dpSuperClassName + " {");
204: out.println();
205:
206: // Memeber variables
207: String clientWrapperClassVar = Util
208: .decapitalize(clientWrapperClassName);
209: out.println(" protected " + qualifiedClientWrapperName
210: + " " + clientWrapperClassVar + ";");
211: out.println(" // Properties. One per method parameter.");
212: ArrayList methodParams = methodInfo.getParameters();
213: for (int i = 0; i < methodParams.size(); i++) {
214: MethodParam p = (MethodParam) methodParams.get(i);
215: out.println(" protected " + p.getType() + " "
216: + p.getName() + ";");
217: }
218: out.println();
219:
220: out.println(" // The EJB wrapper object");
221:
222: // Default Constructor
223: out.println(" public " + className + "() {");
224: out.println(" }");
225: out.println();
226:
227: // Getter and setter for the client wrapper class
228: out.println(" public " + qualifiedClientWrapperName
229: + " get" + clientWrapperClassName + "() {");
230: out.println(" return this." + clientWrapperClassVar
231: + ";");
232: out.println(" }");
233: out.println();
234:
235: out.println(" public void set" + clientWrapperClassName
236: + "( " + clientWrapperClassName + " "
237: + clientWrapperClassVar + " ) { ");
238: out.println(" this." + clientWrapperClassVar + " = "
239: + clientWrapperClassVar + ";");
240:
241: boolean usePrimitiveWrapper = false;
242:
243: if (methodInfo.getReturnType().isPrimitive()
244: && !methodInfo.getReturnType().isCollection()) {
245: usePrimitiveWrapper = true;
246: out
247: .println(" super.setDataClassInstance( this );");
248: out.println(" try { ");
249: out.println(" originalDataMethod = "
250: + qualifiedClientWrapperName
251: + ".class.getMethod(");
252: out.println(" \""
253: + methodInfo.getName() + "\", new Class[] {"
254: + getMethodParamTypes() + "} );");
255: out
256: .println(" super.setDataMethod( getWrapperMethod() ); ");
257: out
258: .println(" }catch (java.lang.NoSuchMethodException ne) {");
259: out.println(" ne.printStackTrace();");
260: out.println(" }");
261: } else {
262: // Set the object instance the method is invoked from
263: out.println(" super.setDataClassInstance( "
264: + clientWrapperClassVar + ");");
265:
266: // Set the Collection element type is the return type is Collection
267: if (methodInfo.getReturnType().isCollection()) {
268: String elemClassName = methodInfo.getReturnType()
269: .getElemClassName();
270:
271: out.println(" try {");
272: out
273: .println(" Class elemType = Class.forName( \""
274: + elemClassName + "\");");
275: out
276: .println(" super.setCollectionElementType( elemType );");
277: out
278: .println(" } catch( java.lang.ClassNotFoundException ne ) {");
279: out.println(" ne.printStackTrace();");
280: out.println(" }");
281: out.println();
282: }
283:
284: // Set the method where the data is retrieved
285: out.println(" try { ");
286: out.println(" super.setDataMethod( "
287: + qualifiedClientWrapperName
288: + ".class.getMethod(");
289: out.println(" \"" + methodInfo.getName()
290: + "\", new Class[] {" + getMethodParamTypes()
291: + "} ) );");
292: out
293: .println(" } catch( java.lang.NoSuchMethodException ne ) { ");
294: out.println(" ne.printStackTrace();");
295: out.println(" }");
296: }
297: out.println(" }");
298: out.println();
299:
300: // Methods for get/set of the properties/method parameters
301: for (int i = 0; i < methodParams.size(); i++) {
302: MethodParam p = (MethodParam) methodParams.get(i);
303:
304: // Getter
305: out.println(" public " + p.getType() + " get"
306: + Util.capitalize(p.getName()) + "() {");
307: out.println(" return " + p.getName() + ";");
308: out.println(" }");
309: out.println();
310:
311: // Setter
312: out.println(" public void set"
313: + Util.capitalize(p.getName()) + "( "
314: + p.getType() + " " + p.getName() + " ) { ");
315: out.println(" this." + p.getName() + " = "
316: + p.getName() + ";");
317: out.println(" }");
318: out.println();
319: }
320: out.println();
321:
322: // Implement abstract method from super class - getDataMethodArguments()
323: if (usePrimitiveWrapper) {
324: out
325: .println(" private java.lang.Object[] getOriginalDataMethodArguments() {");
326: } else {
327: out
328: .println(" public java.lang.Object[] getDataMethodArguments() {");
329: }
330:
331: int methodArgSize = (methodInfo.getParameters() == null) ? 0
332: : methodInfo.getParameters().size();
333:
334: out.println(" try { ");
335: out
336: .println(" java.lang.Object[] values = new java.lang.Object["
337: + methodArgSize + "];");
338: out.println();
339:
340: for (int i = 0; i < methodArgSize; i++) {
341:
342: MethodParam parameter = (MethodParam) methodInfo
343: .getParameters().get(i);
344: out.println(" values["
345: + i
346: + "] = "
347: + convertPrimitiveType(parameter.getName(),
348: parameter.getType()) + ";");
349: }
350:
351: out.println(" return values;");
352: out.println(" } catch( java.lang.Exception e ) { ");
353: out.println(" e.printStackTrace();");
354: out.println(" return null; ");
355: out.println(" }");
356:
357: out.println();
358: out.println(" }");
359: out.println();
360:
361: // Override getFieldKeys() method to filter out the class field
362: out
363: .println(" public com.sun.data.provider.FieldKey[] getFieldKeys() throws com.sun.data.provider.DataProviderException {");
364: out
365: .println(" com.sun.data.provider.FieldKey[] fieldKeys = super.getFieldKeys(); ");
366: out
367: .println(" java.util.ArrayList finalKeys = new java.util.ArrayList(); ");
368: out
369: .println(" for( int i = 0; i < fieldKeys.length; i ++ ) { ");
370: out
371: .println(" if( !fieldKeys[i].getFieldId().equals( \"class\" ) )");
372: out
373: .println(" finalKeys.add( fieldKeys[i] ); ");
374: out.println(" } ");
375: out
376: .println(" return (com.sun.data.provider.FieldKey[])finalKeys.toArray( new com.sun.data.provider.FieldKey[0] ); ");
377: out.println(" } ");
378:
379: // helper methods for primitive return types
380: if (usePrimitiveWrapper) {
381: String mrt = methodInfo.getReturnType().getClassName();
382: String resultBeanName = qualifiedClassName
383: + ".ResultBean";
384:
385: out.println("");
386: out
387: .println(" private java.lang.reflect.Method originalDataMethod; ");
388: out.println("");
389: out.println(" public " + resultBeanName
390: + " invokeMethod() {");
391: out.println(" try { ");
392: out.println(" " + mrt + " result = (" + mrt
393: + ")originalDataMethod.invoke("
394: + clientWrapperClassVar
395: + ", getOriginalDataMethodArguments()); ");
396: out.println(" " + resultBeanName
397: + " methodResult = new " + resultBeanName
398: + "(); ");
399: out
400: .println(" methodResult.setMethodResult(result); ");
401: out.println(" return methodResult; ");
402: out
403: .println(" }catch (java.lang.Exception ex) { ");
404: out.println(" ex.printStackTrace(); ");
405: out.println(" return null; ");
406: out.println(" }");
407: out.println(" } ");
408: out.println("");
409: out
410: .println(" private java.lang.reflect.Method getWrapperMethod() throws java.lang.NoSuchMethodException {");
411: out
412: .println(" return this.getClass().getMethod(\"invokeMethod\", new java.lang.Class[0]); ");
413: out.println(" } ");
414: out.println("");
415: out
416: .println(" public static final class ResultBean { ");
417: out.println(" private " + mrt
418: + " methodResult; ");
419: out.println("");
420: out.println(" public ResultBean() { ");
421: out.println(" } ");
422: out.println("");
423: out.println(" public " + mrt
424: + " getMethodResult() { ");
425: out.println(" return this.methodResult; ");
426: out.println(" }");
427: out.println("");
428: out.println(" public void setMethodResult("
429: + mrt + " result) { ");
430: out.println(" this.methodResult = result; ");
431: out.println(" } ");
432: out.println(" } ");
433: }
434:
435: // End of client bean clas
436: out.println("}");
437:
438: out.flush();
439: out.close();
440:
441: if (usePrimitiveWrapper) {
442: return new ClassDescriptor[] { classDescriptor,
443: helperDescriptor };
444: } else {
445: return new ClassDescriptor[] { classDescriptor };
446: }
447: } catch (java.io.FileNotFoundException ex) {
448: // Log error
449: ex.printStackTrace();
450:
451: // Throw up as a SYSTEM_ERROR
452: throw new EjbLoadException(ex.getMessage());
453: } catch (java.io.IOException ex) {
454: // Log error
455:
456: ex.printStackTrace();
457:
458: // Throw up as a SYSTEM_ERROR
459: throw new EjbLoadException(ex.getMessage());
460: }
461: }
462:
463: private String convertPrimitiveType(String name, String type) {
464: for (int i = 0; i < PRIMITIVE_TYPES.length; i++) {
465: String typeName = PRIMITIVE_TYPES[i];
466: if (type != null && typeName.equals(type.trim())) {
467: return PRIMITIVE_WRAPPERS[i] + ".valueOf(this." + name
468: + ")";
469: }
470: }
471:
472: return "this." + name;
473: }
474:
475: private String getMethodParamTypes() {
476: StringBuffer buf = new StringBuffer();
477: boolean first = true;
478: if (methodInfo.getParameters() != null) {
479: for (Iterator iter = methodInfo.getParameters().iterator(); iter
480: .hasNext();) {
481: MethodParam p = (MethodParam) iter.next();
482:
483: if (first)
484: first = false;
485: else
486: buf.append(", ");
487:
488: buf.append(p.getType());
489: buf.append(".class"); // NOI18N
490: }
491: }
492:
493: return buf.toString();
494: }
495:
496: private void addMethodComment(PrintWriter out, String comment) {
497: out.println(" /**");
498: out.println(" *" + comment);
499: out.println(" */");
500: }
501:
502: private boolean isIndexedDataProvider() {
503: if (methodInfo.getReturnType().isCollection())
504: return true;
505: else if (methodInfo.getReturnType().getClassName()
506: .indexOf("[]") != -1)
507: return true;
508: else
509: return false;
510: }
511: }
|