001: /*
002: * sqlc 1
003: * SQL Compiler
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/products/sqlc/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.codegen;
024:
025: import java.lang.reflect.Method;
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033: import java.util.Set;
034: import java.util.StringTokenizer;
035:
036: import org.apache.bcel.classfile.JavaClass;
037: import org.w3c.dom.Element;
038:
039: import biz.hammurapi.util.Visitable;
040: import biz.hammurapi.util.Visitor;
041: import biz.hammurapi.xml.dom.DomSerializable;
042:
043: /**
044: * Helper class to build net of interfaces
045: * @author Pavel Vlasov
046: * @version $Revision: 1.8 $
047: */
048: public class InterfacePool {
049: List descriptors = new ArrayList();
050: Map nameMap = new HashMap();
051:
052: class WordEntry implements Visitable {
053: String name;
054: InterfaceDescriptor descriptor;
055: // word -> WordEntry
056: Map subWords = new HashMap();
057:
058: /**
059: * Node with own descriptor is always 0 cardinality
060: * @return
061: */
062: int getCardinality() {
063: return descriptor == null ? 0 : subWords.size();
064: }
065:
066: Set getCommonMethods() {
067: final Set[] ret = { null };
068: accept(new Visitor() {
069: public boolean visit(Object target) {
070: WordEntry we = (WordEntry) target;
071: if (we.descriptor != null) {
072: if (ret[0] == null) {
073: ret[0] = new HashSet(we.descriptor.methods);
074: } else {
075: ret[0].retainAll(we.descriptor.methods);
076: }
077: }
078: return true;
079: }
080: });
081:
082: return ret[0];
083: }
084:
085: /**
086: * Number of master interfaces in subinterfaces.
087: * @return
088: */
089: int getMasterCount() {
090: final int[] ret = { 0 };
091: accept(new Visitor() {
092: public boolean visit(Object target) {
093: WordEntry we = (WordEntry) target;
094: if (we.descriptor != null
095: && we.descriptor.isMaster()) {
096: ++ret[0];
097: }
098: return true;
099: }
100: });
101:
102: return ret[0];
103: }
104:
105: public boolean accept(Visitor visitor) {
106: if (visitor.visit(this )) {
107: Iterator it = subWords.values().iterator();
108: while (it.hasNext()) {
109: ((Visitable) it.next()).accept(visitor);
110: }
111: return true;
112: }
113: return false;
114: }
115: }
116:
117: WordEntry wordEntry = new WordEntry();
118:
119: {
120: wordEntry.name = "";
121: }
122:
123: public void discoverCommonDenominators() {
124: wordEntry.accept(new Visitor() {
125: public boolean visit(Object target) {
126: WordEntry we = (WordEntry) target;
127: if (we.descriptor == null && we.name != null
128: && we.name.length() > 0
129: && we.getMasterCount() > 1) {
130: Set methods = we.getCommonMethods();
131: if (!methods.isEmpty()) {
132: InterfaceDescriptor d = new InterfaceDescriptor();
133: d.name = we.name;
134: nameMap.put(d.name, d);
135: descriptors.add(d);
136: d.methods.addAll(methods);
137: d.isCommonDenominator = true;
138: }
139: }
140: return true;
141: }
142: });
143: }
144:
145: public void generateCommonDenominators(String packageName,
146: Consumer consumer) throws GenerationException {
147: Iterator it = descriptors.iterator();
148: while (it.hasNext()) {
149: InterfaceDescriptor d = (InterfaceDescriptor) it.next();
150: if (d.isCommonDenominator && d.isMaster()) {
151: StringBuffer definition = new StringBuffer(
152: "public interface ");
153: if (packageName != null && packageName.length() > 0) {
154: definition.append(packageName);
155: definition.append(".");
156: }
157: definition.append(d.name);
158: Iterator sit = d.getSuperInterfaces(packageName)
159: .iterator();
160: if (sit.hasNext()) {
161: definition.append(" extends ");
162: }
163: while (sit.hasNext()) {
164: definition.append(sit.next());
165: if (sit.hasNext()) {
166: definition.append(", ");
167: }
168: }
169:
170: Interface dif = new Interface(definition.toString(),
171: "Common denominator interface", consumer
172: .getListener());
173: Iterator mit = d.getOwnMethods().iterator();
174: while (mit.hasNext()) {
175: StringBuffer md = new StringBuffer();
176: String signature = (String) mit.next();
177: int idx = signature.indexOf('(');
178: int edx = signature.indexOf(")");
179: md.append(signature.substring(0, idx + 1));
180: StringTokenizer st = new StringTokenizer(signature
181: .substring(idx + 1, edx), ",");
182: for (int i = 1; st.hasMoreTokens(); i++) {
183: md.append(st.nextToken());
184: md.append(" p");
185: md.append(i);
186: if (st.hasMoreTokens()) {
187: md.append(", ");
188: }
189: }
190: md.append(signature.substring(edx));
191: dif.addMethod(md.toString(), null, "Common method",
192: null);
193: }
194: consumer.consume(dif.getJavaClass());
195: }
196: }
197: }
198:
199: public InterfaceDescriptor addInterface(final String name,
200: Map attributes) {
201: String newName = name;
202: for (int i = 0; nameMap.containsKey(newName); i++) {
203: newName = name + "_" + i;
204: }
205:
206: InterfaceDescriptor d = new InterfaceDescriptor();
207: d.name = newName;
208: nameMap.put(d.name, d);
209: descriptors.add(d);
210: d.attributes = attributes;
211:
212: Collection words = new ArrayList();
213: for (int i = 0, j = 0, l = newName.length(); i <= l; i++) {
214: if (i == l && j < i) {
215: words.add(newName.substring(j, i));
216: } else if (Character.isUpperCase(newName.charAt(i))
217: && j < i) {
218: words.add(newName.substring(j, i));
219: j = i;
220: }
221: }
222:
223: WordEntry currentWordEntry = wordEntry;
224: Iterator it = words.iterator();
225: while (it.hasNext()) {
226: String word = (String) it.next();
227: WordEntry nextWordEntry = (WordEntry) currentWordEntry.subWords
228: .get(word);
229: if (nextWordEntry == null) {
230: nextWordEntry = new WordEntry();
231: nextWordEntry.name = currentWordEntry.name + word;
232: currentWordEntry.subWords.put(word, nextWordEntry);
233: }
234: currentWordEntry = nextWordEntry;
235: }
236: currentWordEntry.descriptor = d;
237:
238: return d;
239: }
240:
241: public InterfaceDescriptor getDescriptor(String name) {
242: return (InterfaceDescriptor) nameMap.get(name);
243: }
244:
245: public void addInterface(java.lang.Class theInterface) {
246: InterfaceDescriptor id = new InterfaceDescriptor();
247: id.isExternal = true;
248: id.name = theInterface.getName();
249: id.clazz = theInterface;
250: for (int i = 0, mc = theInterface.getMethods().length; i < mc; i++) {
251: Method method = theInterface.getMethods()[i];
252: StringBuffer sb = new StringBuffer(method.getReturnType()
253: .getName());
254: sb.append(" ");
255: sb.append(method.getName());
256: sb.append("(");
257: for (int j = 0, pc = method.getParameterTypes().length; j < pc; j++) {
258: sb.append(method.getParameterTypes()[j].getName());
259: if (j < pc - 1) {
260: sb.append(",");
261: }
262: }
263: sb.append(")");
264: id.methods.add(sb.toString());
265: }
266: nameMap.put(id.name, id);
267: descriptors.add(id);
268: }
269:
270: public class InterfaceDescriptor {
271:
272: /**
273: * Removes methods implemented by superinterfaces and returns remainder
274: * @param name
275: * @return
276: */
277: public Set getOwnMethods() {
278: Set ret = new HashSet(methods);
279: Iterator sit = getSuperInterfaces().iterator();
280: while (sit.hasNext()) {
281: ret
282: .removeAll(((InterfaceDescriptor) sit.next()).methods);
283: }
284: return ret;
285: }
286:
287: public void addMethod(String signature) {
288: methods.add(signature);
289: }
290:
291: /**
292: *
293: * @param name
294: * @return Attributes from all interfaces for which this interface is master.
295: */
296: public Map getAttributes() {
297: Map ret = new HashMap();
298: Iterator it = descriptors.iterator();
299: while (it.hasNext()) {
300: InterfaceDescriptor id = (InterfaceDescriptor) it
301: .next();
302: if (id.attributes != null && isMaster()) {
303: ret.putAll(id.attributes);
304: }
305: }
306: return ret;
307: }
308:
309: /**
310: * @return Returns the clazz.
311: */
312: public java.lang.Class getInterfaceClass() {
313: return clazz;
314: }
315:
316: /**
317: * @return Returns the isExternal.
318: */
319: public boolean isExternal() {
320: return isExternal;
321: }
322:
323: /**
324: * @return Returns the name.
325: */
326: public String getName() {
327: return name;
328: }
329:
330: private java.lang.Class clazz;
331: String name;
332: boolean isExternal;
333: boolean isCommonDenominator;
334: int counter;
335: Map attributes;
336:
337: /**
338: * Contains method signatures
339: */
340: Set methods = new HashSet();
341:
342: /**
343: *
344: * @return Master interface descriptor
345: */
346: public InterfaceDescriptor getMaster() {
347: Iterator it = descriptors.iterator();
348: while (it.hasNext()) {
349: InterfaceDescriptor id = (InterfaceDescriptor) it
350: .next();
351: if (id.methods.equals(methods)) {
352: return id;
353: }
354: }
355: return this ;
356: }
357:
358: public boolean isMaster() {
359: return this == getMaster();
360: }
361:
362: Collection getSuperInterfaces() {
363: Collection ret = new ArrayList();
364: Iterator it = descriptors.iterator();
365: Z: while (it.hasNext()) {
366: InterfaceDescriptor id = (InterfaceDescriptor) it
367: .next();
368: if (!methods.equals(id.methods)
369: && methods.containsAll(id.methods)) {
370: Iterator rit = ret.iterator();
371: while (rit.hasNext()) {
372: InterfaceDescriptor rid = (InterfaceDescriptor) rit
373: .next();
374: if (rid.methods.containsAll(id.methods)) {
375: continue Z;
376: } else if (id.methods.containsAll(rid.methods)) {
377: rit.remove();
378: }
379: }
380:
381: ret.add(id);
382: }
383: }
384: return ret;
385: }
386:
387: public Collection getSuperInterfaces(String packageName) {
388: Collection ret = new ArrayList();
389: Iterator it = ((InterfaceDescriptor) nameMap.get(name))
390: .getSuperInterfaces().iterator();
391: while (it.hasNext()) {
392: InterfaceDescriptor interfaceDescriptor = (InterfaceDescriptor) it
393: .next();
394: String sname = interfaceDescriptor.getMaster()
395: .getName();
396: if (!interfaceDescriptor.isExternal) {
397: sname = ((packageName == null || packageName
398: .length() == 0) ? "" : packageName + ".")
399: + sname;
400: }
401:
402: if (!ret.contains(sname)) {
403: ret.add(sname);
404: }
405: }
406: return ret;
407: }
408: }
409:
410: public static void main(String[] args) throws GenerationException {
411: InterfacePool pool = new InterfacePool();
412: pool.addInterface(DomSerializable.class);
413:
414: InterfaceDescriptor a = pool.addInterface("PersonA", null);
415: a
416: .addMethod("java.lang.String getName() throws java.sql.SQLException");
417: a.addMethod("int getA()");
418: a.addMethod("void toDom(" + Element.class.getName() + ")");
419:
420: InterfaceDescriptor b = pool.addInterface("PersonB", null);
421: b
422: .addMethod("java.lang.String getName() throws java.sql.SQLException");
423: b.addMethod("int getB()");
424: b.addMethod("void toDom(" + Element.class.getName() + ")");
425:
426: pool.discoverCommonDenominators();
427:
428: pool.generateCommonDenominators("test", new Consumer() {
429:
430: public void consume(JavaClass javaClass) {
431: System.out.println(javaClass.toString());
432: }
433:
434: public GenerationListener getListener() {
435: return null;
436: }
437: });
438: }
439: }
|