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