1 28 29 package org.jibx.binding.classes; 30 31 import java.io.File ; 32 import java.io.FileFilter ; 33 import java.io.IOException ; 34 import java.util.ArrayList ; 35 import java.util.HashMap ; 36 37 import org.apache.bcel.Constants; 38 39 import org.jibx.binding.def.BindingDefinition; 40 import org.jibx.runtime.JiBXException; 41 42 52 53 public class MungedClass 54 { 55 58 59 private static final ClassFile[] EMPTY_CLASSFILE_ARRAY = {}; 60 61 62 private static final String BINDING_LISTNAME = 63 BindingDefinition.GENERATE_PREFIX + "bindingList"; 64 65 66 private static final String [] EXTRA_METHODS_MATCHES = 67 { 68 "marshal", "(Lorg/jibx/runtime/IMarshallingContext;)V", 69 "unmarshal", "(Lorg/jibx/runtime/IUnmarshallingContext;)V" 70 }; 71 72 75 76 private static ArrayList s_classes; 77 78 79 private static HashMap s_classMap; 80 81 82 private static HashMap s_directories; 83 84 85 private static HashMap s_nameMap; 86 87 88 private static ArrayList s_pendingClasses; 89 90 93 94 private ClassFile m_classFile; 95 96 97 private HashMap m_methodMap; 98 99 100 private ExistingMethod[] m_existingMethods; 101 102 103 private String m_factoryList; 104 105 111 112 private MungedClass(ClassFile cf) { 113 114 m_classFile = cf; 116 m_methodMap = new HashMap (); 117 118 ExistingMethod[] exists = cf.getBindingMethods 120 (BindingDefinition.GENERATE_PREFIX, EXTRA_METHODS_MATCHES); 121 if (exists != null) { 122 for (int i = 0; i < exists.length; i++) { 123 m_methodMap.put(exists[i], exists[i]); 124 } 125 } 126 m_existingMethods = exists; 127 } 128 129 134 135 ClassFile getClassFile() { 136 return m_classFile; 137 } 138 139 144 145 private void purgeUnusedMethods() throws JiBXException { 146 if (m_existingMethods != null) { 147 for (int i = 0; i < m_existingMethods.length; i++) { 148 ExistingMethod method = m_existingMethods[i]; 149 if (!method.isUsed()) { 150 method.delete(); 151 } 152 } 153 } 154 } 155 156 168 169 BindingMethod getUniqueMethod(MethodBuilder builder, 170 boolean suffix) throws JiBXException { 171 172 if (builder.getClassFile() != m_classFile) { 174 throw new IllegalStateException 175 ("Internal error: wrong class for call"); 176 } 177 builder.codeComplete(suffix); 178 BindingMethod method = (BindingMethod)m_methodMap.get(builder); 179 if (method == null) { 180 184 builder.addMethod(); 186 m_methodMap.put(builder, builder); 187 return builder; 188 189 } else if (method instanceof ExistingMethod) { 190 ((ExistingMethod)method).setUsed(); 191 } 192 return method; 195 } 196 197 206 207 public static ClassFile getUniqueSupportClass(ClassFile cf) 208 throws JiBXException { 209 cf.codeComplete(); 210 Object value = s_classMap.get(cf); 211 if (value == null) { 212 s_classes.add(cf); 213 s_classMap.put(cf, cf); 214 return cf; 216 } else { 217 ClassFile prior = (ClassFile)value; 218 prior.incrementUseCount(); 219 return prior; 222 } 223 } 224 225 234 235 private static void checkDirectory(File root, String pack) 236 throws JiBXException { 237 try { 238 File directory = new File 239 (root, pack.replace('.', File.separatorChar)); 240 String cpath = directory.getCanonicalPath(); 241 if (s_directories.get(cpath) == null) { 242 File [] matches = new File (cpath).listFiles(new JiBXFilter()); 243 for (int i = 0; i < matches.length; i++) { 244 File file = matches[i]; 245 String name = file.getName(); 246 int split = name.indexOf('.'); 247 if (split >= 0) { 248 name = name.substring(0, split); 249 } 250 if (pack.length() > 0) { 251 name = pack + '.' + name; 252 } 253 ClassFile cf = ClassCache.getClassFile(name); 254 s_classes.add(cf); 255 s_classMap.put(cf, cf); 256 } 257 s_directories.put(cpath, cpath); 258 } 259 } catch (IOException ex) { 260 throw new JiBXException("Error loading class file", ex); 261 } 262 } 263 264 271 272 void addFactory(String fact) { 273 if (m_factoryList == null) { 274 m_factoryList = "|" + fact + "|"; 275 } else { 276 m_factoryList = m_factoryList + fact + "|"; 277 } 278 } 279 280 286 287 void setFactoryList() throws JiBXException { 288 if (m_factoryList != null) { 289 short access = Constants.ACC_PUBLIC | Constants.ACC_FINAL | 290 Constants.ACC_STATIC; 291 m_classFile.updateField("java.lang.String", BINDING_LISTNAME, 292 access, m_factoryList); 293 } 294 } 295 296 303 304 static MungedClass getInstance(ClassFile cf) 305 throws JiBXException { 306 MungedClass inst = (MungedClass)s_nameMap.get(cf.getName()); 307 if (inst == null) { 308 inst = new MungedClass(cf); 309 s_nameMap.put(cf.getName(), inst); 310 if (cf.isComplete()) { 311 if (s_classMap.get(cf) == null) { 312 s_classes.add(inst); 313 s_classMap.put(cf, cf); 314 } else { 315 throw new IllegalStateException 316 ("Existing class conflicts with load"); 317 } 318 String pack = cf.getPackage(); 319 checkDirectory(cf.getRoot(), pack); 320 } 321 } 322 inst.m_classFile.incrementUseCount(); 323 return inst; 324 } 325 326 336 337 public static void delayedAddUnique(ClassFile cf) throws JiBXException { 338 s_pendingClasses.add(cf); 339 } 340 341 349 350 public static ClassFile[][] fixChanges(boolean write) throws JiBXException { 351 try { 352 for (int i = 0; i < s_pendingClasses.size(); i++) { 353 getUniqueSupportClass((ClassFile)s_pendingClasses.get(i)); 354 } 355 ArrayList writes = new ArrayList (); 356 ArrayList keeps = new ArrayList (); 357 ArrayList deletes = new ArrayList (); 358 for (int i = 0; i < s_classes.size(); i++) { 359 Object obj = s_classes.get(i); 360 ClassFile cf; 361 if (obj instanceof MungedClass) { 362 MungedClass inst = (MungedClass)obj; 363 inst.purgeUnusedMethods(); 364 inst.setFactoryList(); 365 cf = inst.getClassFile(); 366 } else { 367 cf = (ClassFile)obj; 368 } 369 if (cf.isModified()) { 370 if (write) { 371 cf.writeFile(); 372 } 373 writes.add(cf); 374 } else if (cf.getUseCount() > 0) { 376 keeps.add(cf); 377 } else { 379 cf.delete(); 380 deletes.add(cf); 381 } 383 } 384 ClassFile[][] results = new ClassFile[3][]; 385 results[0] = (ClassFile[])writes.toArray(EMPTY_CLASSFILE_ARRAY); 386 results[1] = (ClassFile[])keeps.toArray(EMPTY_CLASSFILE_ARRAY); 387 results[2] = (ClassFile[])deletes.toArray 388 (EMPTY_CLASSFILE_ARRAY); 389 return results; 390 } catch (IOException ex) { 391 throw new JiBXException("Error writing to file", ex); 392 } 393 } 394 395 398 399 private static class JiBXFilter implements FileFilter 400 { 401 public boolean accept(File file) { 402 String name = file.getName(); 403 return name.startsWith(BindingDefinition.GENERATE_PREFIX) && 404 name.endsWith(".class"); 405 } 406 } 407 408 412 413 public static void reset() { 414 s_classes = new ArrayList (); 415 s_classMap = new HashMap (); 416 s_directories = new HashMap (); 417 s_nameMap = new HashMap (); 418 s_pendingClasses = new ArrayList (); 419 } 420 } | Popular Tags |