001: /*
002: * $Header: /cvs/j3dfly/J3dEditor/src/org/jdesktop/j3dedit/scenegrapheditor/sourcecontrol/BeanCodeGenerator.java,v 1.1 2005/04/20 22:21:19 paulby Exp $
003: *
004: * Sun Public License Notice
005: *
006: * The contents of this file are subject to the Sun Public License Version
007: * 1.0 (the "License"). You may not use this file except in compliance with
008: * the License. A copy of the License is available at http://www.sun.com/
009: *
010: * The Original Code is the Java 3D(tm) Scene Graph Editor.
011: * The Initial Developer of the Original Code is Jan Becicka.
012: * Portions created by Jan Becicka are Copyright (C) 2002.
013: * All Rights Reserved.
014: *
015: * Contributor(s): Jan Becicka.
016: *
017: **/
018: package org.jdesktop.j3dedit.scenegrapheditor.sourcecontrol;
019:
020: import javax.media.j3d.Leaf;
021: import javax.media.j3d.Group;
022: import javax.media.j3d.NodeComponent;
023: import org.jdesktop.j3dedit.scenegraph.SGNodeComponent;
024: import org.jdesktop.j3dedit.scenegraph.SGGroup;
025: import org.jdesktop.j3dedit.scenegraph.SGLeaf;
026: import org.jdesktop.j3dedit.scenegraph.SGObject;
027: import javax.media.j3d.SceneGraphObject;
028: import java.lang.reflect.Method;
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.Iterator;
032: import java.util.HashMap;
033: import java.lang.reflect.InvocationTargetException;
034: import javax.media.j3d.Node;
035: import java.util.Vector;
036: import javax.media.j3d.TransformGroup;
037: import java.lang.reflect.Array;
038:
039: /** Generates customization code for fiven bean
040: * @author Jan Becicka
041: * @version 0.1
042: */
043: public class BeanCodeGenerator {
044:
045: /** bean, we are customizing
046: */
047: protected Object bean;
048: /** default instance of the bean
049: */
050: protected Object defaultInstance;
051:
052: /** For name generation
053: */
054: protected NamePool naming;
055:
056: /** list of all get* methods of this bean
057: */
058: protected ArrayList getters = null;
059: /** list of all set* methods of this bean
060: */
061: protected ArrayList setters = null;
062:
063: /** list of customizers to call
064: */
065: protected ArrayList customizers;
066: /** only one default instance for all beans
067: */
068: protected static HashMap defaultInstancePool = null;
069:
070: /** name of this bean
071: */
072: private String fieldName;
073:
074: /** holds construction code String
075: */
076: protected String constructionCode;
077:
078: /** holds declaration code String
079: */
080: protected String declarationCode;
081:
082: /** Holds value of property needToProcessBeans. */
083: protected ArrayList needToProcessBeans;
084:
085: protected String beanClassName;
086:
087: {
088: if (defaultInstancePool == null)
089: defaultInstancePool = new HashMap();
090: }
091:
092: /** Creates new Generator
093: * @param bean bean to creat code
094: * @param naming for creating names
095: */
096: public BeanCodeGenerator(Object bean, NamePool naming) {
097: this .naming = naming;
098: this .bean = bean;
099:
100: customizers = new ArrayList(5);
101: needToProcessBeans = new ArrayList(5);
102: beanClassName = getClassName();
103: init();
104:
105: defaultInstance = createDefaultInstanceOfBean();
106:
107: if (defaultInstance != null) {
108: createGettersSettersList();
109: createDeclarationCode();
110: createConstructionCode();
111: createCustomizationCode();
112: }
113: }
114:
115: protected String getClassName() {
116: return bean.getClass().getName();
117: }
118:
119: protected void init() {
120: }
121:
122: /** Override this method, if you want to have different default instance (e.g. YourNean(10))
123: * @return instance of bean
124: */
125: protected Object createDefaultInstanceOfBean() {
126: Object defaultInst = defaultInstancePool.get(bean.getClass());
127: if (defaultInst == null) {
128: try {
129: defaultInst = bean.getClass().newInstance();
130: defaultInstancePool.put(bean.getClass(), defaultInst);
131: } catch (InstantiationException e) {
132: e.printStackTrace();
133: } catch (IllegalAccessException e) {
134: //e.printStackTrace();
135: System.err.println(e.getMessage());
136: }
137: }
138: return defaultInst;
139: }
140:
141: /** creates addChild(..)
142: */
143: protected void createAdders() {
144: if (bean instanceof Group) {
145: try {
146: Method m = bean.getClass().getMethod("addChild",
147: new Class[] { Node.class });
148: int num = ((Group) bean).numChildren();
149: for (int i = 0; i < num; i++) {
150: addCustomizationCode(new MethodWithParameter(
151: m,
152: createIdentifier(((Group) bean).getChild(i))));
153: }
154: } catch (NoSuchMethodException e) {
155: e.printStackTrace();
156: }
157: }
158: }
159:
160: /** Override this method, if you want to create parametric constructor constr
161: */
162: protected void createConstructionCode() {
163: constructionCode = getFieldName() + " = new " + beanClassName
164: + "();\n";
165: }
166:
167: /** Override this method, if you want to create your own declaration
168: */
169: protected void createDeclarationCode() {
170: declarationCode = beanClassName + " " + getFieldName() + ";\n";
171: }
172:
173: /** creates setters e.g. <CODE>t.setTransform(..);</CODE>
174: */
175: protected void createCustomizationCode() {
176:
177: Method setter, getter;
178:
179: Iterator g = getters.iterator();
180: while (g.hasNext()) {
181: //process all getters
182: getter = (Method) g.next();
183: setter = findSetter(getter);
184:
185: if (setter == null)
186: continue;
187:
188: Object result1 = null;
189: Object result2 = null;
190: Class[] parameterTypes = getter.getParameterTypes();
191: if (parameterTypes.length == 0)
192: try {
193: result1 = getter.invoke(defaultInstance,
194: (Object[]) null);
195: result2 = getter.invoke(bean, (Object[]) null);
196: } catch (IllegalAccessException e) {
197: e.printStackTrace();
198: } catch (InvocationTargetException e) {
199: System.err.println("Warning: cannot inspect "
200: + getter + ":" + e.getTargetException());
201: }
202: else if ((parameterTypes.length == 1)
203: && !parameterTypes[0]
204: .isAssignableFrom(Number.class)
205: && getter.getReturnType().equals(void.class)) {
206:
207: try {
208: result1 = parameterTypes[0].newInstance();
209: result2 = parameterTypes[0].newInstance();
210: getter.invoke(defaultInstance,
211: new Object[] { result1 });
212: getter.invoke(bean, new Object[] { result2 });
213: } catch (IllegalAccessException e) {
214: e.printStackTrace();
215: } catch (InvocationTargetException e) {
216: e.printStackTrace();
217: } catch (InstantiationException e) {
218: System.out.println("Warning: cannot create: "
219: + getter);
220: continue;
221: }
222:
223: } else
224: //don't know how to handle this, maybe subclasses does
225: handleSpecialGetter(getter);
226:
227: if (result1 == null && result2 == null)
228: continue;
229: if (result2 == null)
230: continue;
231: if (!result2.equals(result1)) {
232: // if not equal, add setter
233: if (setter != null && filterMethod(setter)) {
234: // if setter exists, add it
235: addCustomizationCode(new MethodWithParameter(
236: setter, createIdentifier(result2)));
237: }
238: }
239: }
240: createAdders();
241: }
242:
243: /** creates or returns identifier od given object
244: * @param o bean
245: * @return name of identifier
246: */
247: protected final String createIdentifier(Object o) {
248: if (o == null)
249: return "null";
250: if (o instanceof Boolean)
251: return o.toString();
252: if (o instanceof Number)
253: return Literals.numberToString((Number) o);
254: if (o instanceof String)
255: return "\"" + o.toString() + "\"";
256: String instanceName = (String) naming.getObjectName(o);
257: needToProcessBeans.add(o);
258: return instanceName;
259: }
260:
261: /** returns cunstruction string
262: * @return Construction String
263: */
264: public final String getConstructionCode() {
265: return constructionCode;
266: }
267:
268: /** returns declaration string
269: * @return returns declaration string
270: */
271: public final String getDeclarationCode() {
272: return declarationCode;
273: }
274:
275: /** returns name of field
276: * @return FieldName
277: */
278: public final String getFieldName() {
279: if (fieldName == null) {
280: fieldName = naming.getObjectName(bean);
281: }
282: return fieldName;
283: }
284:
285: /** returns customization code
286: * @return Customization String
287: */
288: public final String getCustomizationCode() {
289: Iterator f = customizers.iterator();
290: StringBuffer buf = new StringBuffer();
291:
292: while (f.hasNext()) {
293: buf.append(getFieldName() + "." + f.next() + ";\n");
294: }
295: return buf.toString();
296: }
297:
298: /** Getter for property needToProcessBeans.
299: * @return Value of property needToProcessBeans.
300: */
301: public final ArrayList getNeedToProcessBeans() {
302: return needToProcessBeans;
303: }
304:
305: /**
306: * @param mwp
307: */
308: protected void addCustomizationCode(MethodWithParameter mwp) {
309: customizers.add(mwp);
310: }
311:
312: /**
313: * @param m
314: * @return */
315: protected boolean filterMethod(Method m) {
316: return true;
317: }
318:
319: /** use this method, if you want handle some strange getter
320: * by default only getCapability/setCapability is handled
321: * @param g
322: */
323: protected void handleSpecialGetter(Method g) {
324: if (g.getName().equals("getCapability")) {
325: handleCapability();
326: }
327: }
328:
329: protected void handleCapability() {
330: SceneGraphObject b = (SceneGraphObject) bean;
331: SceneGraphObject d = (SceneGraphObject) defaultInstance;
332:
333: try {
334: Method set = b.getClass().getMethod("setCapability",
335: new Class[] { int.class });
336: Method clear = b.getClass().getMethod("clearCapability",
337: new Class[] { int.class });
338: for (int i = 0; i < 32; i++) {
339: if (b.getCapability(i) != d.getCapability(i)) {
340: if (b.getCapability(i)) {
341: //set
342: addCustomizationCode(new MethodWithParameter(
343: set, new Integer(i)));
344: } else {
345: //clear
346: addCustomizationCode(new MethodWithParameter(
347: clear, new Integer(i)));
348: }
349: }
350: }
351: } catch (NoSuchMethodException e) {
352: e.printStackTrace();
353: }
354: }
355:
356: /** find setter for getter
357: * @param m getter
358: * @return setter
359: */
360: private Method findSetter(Method m) {
361: Iterator s = setters.iterator();
362: String getterName = m.getName().substring(3);
363: Method setter;
364:
365: while (s.hasNext()) {
366: setter = ((Method) s.next());
367: String setterName = setter.getName().substring(3);
368: if (getterName.equals(setterName)) {
369: return setter;
370: }
371: }
372: return null;
373: }
374:
375: /**
376: */
377: private void createGettersSettersList() {
378: getters = new ArrayList();
379: setters = new ArrayList();
380:
381: Method[] methods;
382:
383: try {
384: methods = bean.getClass().getMethods();
385: } catch (SecurityException e) {
386: return;
387: }
388:
389: for (int i = 0; i < methods.length; i++) {
390: if (methods[i].getName().startsWith("get")) {
391: getters.add(methods[i]);
392: } else {
393: if (methods[i].getName().startsWith("set")) {
394: setters.add(methods[i]);
395: }
396: }
397: }
398: }
399: }
|