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 }