1 19 package org.netbeans.modules.javacore.scanning; 20 21 import java.io.*; 22 import java.util.*; 23 import javax.jmi.reflect.RefObject; 24 import org.netbeans.jmi.javamodel.AnnotationType; 25 import org.netbeans.jmi.javamodel.ClassMember; 26 import org.netbeans.jmi.javamodel.EnumConstant; 27 import org.netbeans.jmi.javamodel.JavaEnum; 28 import org.netbeans.jmi.javamodel.JavaModelPackage; 29 import org.netbeans.jmi.javamodel.Resource; 30 import org.netbeans.modules.classfile.Access; 31 import org.netbeans.modules.classfile.ClassFile; 32 import org.netbeans.modules.classfile.ClassName; 33 import org.netbeans.modules.classfile.InvalidClassFormatException; 34 import org.netbeans.modules.javacore.ClassIndex; 35 import org.netbeans.modules.javacore.JMManager; 36 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 37 import org.netbeans.modules.javacore.jmiimpl.javamodel.*; 38 import org.openide.ErrorManager; 39 import org.openide.filesystems.FileObject; 40 41 42 46 public class ClassUpdater { 47 private Map fileObjectToClassFile; 48 private Map nameToResource; 49 private Map resourceToSuperCodes; 50 private Map unmodifiedResources; 51 private Map resourceToClasses; 52 private ResourceClassImpl resProxy; 53 private JavaClassClassImpl clsProxy; 54 private JavaEnumClassImpl enumProxy; 55 private AnnotationTypeClassImpl annoProxy; 56 private ClassIndex classIndex; 57 private ResourceImpl updatedResource; 58 private long indexTimestamp; 59 60 61 public ClassUpdater(JavaModelPackage mofModel) { 62 clsProxy = (JavaClassClassImpl) mofModel.getJavaClass(); 63 enumProxy = (JavaEnumClassImpl) mofModel.getJavaEnum(); 64 resProxy = (ResourceClassImpl) mofModel.getResource(); 65 annoProxy = (AnnotationTypeClassImpl) mofModel.getAnnotationType(); 66 classIndex=ClassIndex.getIndex(mofModel); 67 } 68 69 70 public static void updateIndex(ResourceImpl resource,FileObject fobj) { 71 JavaMetamodel.getDefaultRepository().beginTrans(false); 72 try { 73 JavaModelPackage pck=(JavaModelPackage)resource.refOutermostPackage(); 74 Map cls=new HashMap(); 75 String fname=fobj.getNameExt(); 76 String prefix=fobj.getName().concat("$"); 77 String ext=fobj.getExt(); 78 FileObject[] children=fobj.getParent().getChildren(); 79 80 cls.put(fname,new FObjectInfo(fobj)); 81 for (int i=0;i<children.length;i++) { 82 FileObject ch=children[i]; 83 84 if (ext.equals(ch.getExt()) && ch.getName().startsWith(prefix)) { 85 cls.put(ch.getNameExt(),new FObjectInfo(ch)); 86 87 } 88 } 89 ClassUpdater instance=new ClassUpdater(pck); 90 instance.updatedResource=resource; 91 instance.updateResources(Collections.EMPTY_MAP,cls,true); 92 } finally { 93 JavaMetamodel.getDefaultRepository().endTrans(); 94 } 95 } 96 97 public Collection updateResources(Map sources, Map classes) { 98 return updateResources(sources, classes, false); 99 } 100 101 public Collection updateResources(Map sources, Map classes, boolean directUpdate) 102 { 103 Iterator iter, iter2; 104 indexTimestamp=classIndex.getTimestamp(); 105 unmodifiedResources = new HashMap(); 106 fileObjectToClassFile = new HashMap(); 107 nameToResource = new HashMap(); 108 resourceToClasses = new HashMap(); 109 resourceToSuperCodes = new HashMap(); 110 iter = classes.entrySet().iterator(); 111 while (iter.hasNext()) { 112 Map.Entry entry = (Map.Entry) iter.next(); 113 String name = (String ) entry.getKey(); 114 115 int index = name.indexOf('$'); 116 String resName = (index > -1) ? name.substring(0, index) + ".class" : name; 118 String srcName = resName.substring(0, resName.length() - ".class".length()) + ".java"; if (sources.containsKey(srcName)) continue; 121 123 FileInfo file = (FileInfo) entry.getValue(); 124 ClassFile clsFile = getClassFile (file); 125 if ((clsFile == null) || isAnonymous(clsFile)) { 126 continue; 127 } 128 Set superCodes = getSuperCodes(resName, classes); 129 if (superCodes == null) { 130 continue; 131 } 132 addFileToMap (resName, clsFile); 133 addSuperCodes(superCodes, clsFile); 134 } 136 iter = resourceToSuperCodes.entrySet().iterator(); 137 for (int x = 0; iter.hasNext(); x++) { 138 Map.Entry entry = (Map.Entry) iter.next(); 139 Set codes = (Set) entry.getValue(); 140 int size = codes.size(); 141 int[] hc = new int[size]; 142 iter2 = codes.iterator(); 143 for (int y = 0; y < size; y++) { 144 hc[y] = ((Integer ) iter2.next()).intValue(); 145 } 146 ResourceImpl resource = (ResourceImpl) entry.getKey(); 147 classIndex.setIdentifiers(resource,hc); 148 } 150 iter = nameToResource.entrySet().iterator(); 151 while (iter.hasNext()) { 152 Map.Entry entry = (Map.Entry) iter.next(); 153 String resName = (String ) entry.getKey(); 154 ResourceImpl res = (ResourceImpl) entry.getValue(); 155 updateClasses (resName, res, !directUpdate && !res.isInitialized()); 156 } 157 Collection resources=new ArrayList(resourceToSuperCodes.keySet()); 158 resources.addAll(unmodifiedResources.values()); 159 return resources; 160 } 161 162 public void addSuperCodes(Set codes, ClassFile classFile) { 163 ClassName superName = classFile.getSuperClass(); 164 if (superName != null) { 165 codes.add (nameToHashCode(superName)); 166 } 167 Iterator iter = classFile.getInterfaces().iterator(); 168 while (iter.hasNext()) { 169 codes.add (nameToHashCode((ClassName) iter.next())); 170 } 171 } 172 173 private Set getSuperCodes(String name, Map classes) { 174 if (unmodifiedResources.containsKey(name)) { 175 return null; 176 } 177 Resource res = (Resource) nameToResource.get (name); 178 if (res == null) { 179 FileInfo file = (FileInfo) classes.get (name); 180 if (file == null) { 181 unmodifiedResources.put(name,null); 183 JMManager.getLog().log("ClassUpdater, cannot find file object: " + name); return null; 185 } 186 if (updatedResource!=null) { 187 assert updatedResource.getName().endsWith(name): updatedResource.getName()+" "+name; res = updatedResource; 189 } else { 190 res = resProxy.resolveResource(file.getPath(), true, false); 191 } 192 long timestamp = file.lastModified(); 193 if (res.getTimestamp() != timestamp || indexTimestamp<timestamp) { 194 res.setTimestamp(timestamp); 195 nameToResource.put (name, res); 196 Set set = new HashSet(); 197 resourceToSuperCodes.put (res, set); 198 return set; 199 } else { 200 unmodifiedResources.put(name,res); 201 return null; 202 } 203 } 204 return (Set) resourceToSuperCodes.get (res); 205 } 206 207 public String getSimpleName (ClassName clsName) { 208 String name = clsName.getSimpleName(); 209 int index = name.lastIndexOf ('.'); 210 if (index > -1) { 211 name = name.substring (index + 1); 212 } 213 return name; 214 } 215 216 public Integer nameToHashCode (ClassName clsName) { 217 return new Integer (getSimpleName (clsName).hashCode()); 218 } 219 220 public boolean isAnonymous (ClassFile clsFile) { 221 String name = clsFile.getName().getSimpleName(); 222 int index = name.lastIndexOf ('.') + 1; 223 if (name.length() == index) { 224 JMManager.getLog().log("ClassUpdater, class name ends with a dot: " + name); } 226 return (index > 0) && (name.length() > index) && Character.isDigit(name.charAt (index)); 227 } 228 229 public ClassFile getClassFile (FileInfo file) { 230 ClassFile clsFile = (ClassFile) fileObjectToClassFile.get (file); 231 if (clsFile == null) { 232 try { 233 InputStream stream=new BufferedInputStream(file.getInputStream()); 234 try { 235 clsFile = new ClassFile (stream, false); 236 fileObjectToClassFile.put (file, clsFile); 237 } finally { 238 stream.close(); 239 } 240 } catch (InvalidClassFormatException ex) { 241 ErrorManager errmgr = ErrorManager.getDefault(); 242 errmgr.log(ErrorManager.INFORMATIONAL, 243 "invalid class file format: " + file.getCanonicalName()); } catch (IOException ex) { 245 ErrorManager errmgr = ErrorManager.getDefault(); 246 errmgr.annotate(ex, ErrorManager.EXCEPTION, file.getName(), null, null, null); 247 errmgr.notify(ErrorManager.INFORMATIONAL, ex); 248 } 249 } return clsFile; 251 } 252 253 public void addFileToMap (String resName, ClassFile clsFile) { 254 Map map = (Map) resourceToClasses.get (resName); 255 if (map == null) { 256 map = new HashMap (); 257 resourceToClasses.put (resName, map); 258 } 259 map.put (clsFile.getName().getSimpleName(), clsFile); 260 } 261 262 public void updateClasses (String resName, ResourceImpl resource, boolean removeFeatures) { 263 Map map = (Map) resourceToClasses.get (resName); 264 Collection javaClasses = resource.getNakedClassifiers(); 265 if (javaClasses.size() > 0) { 266 if (!newClassesNeeded(resource, map, removeFeatures)) { 267 map.clear(); 268 return; 269 } 270 } 271 Map result = new HashMap (); 272 Iterator classIt=javaClasses.iterator(); 273 274 while(classIt.hasNext()) { 275 RefObject oldJcls=(RefObject)classIt.next(); 276 classIt.remove(); 277 oldJcls.refDelete(); 278 } 279 while (map.size () > 0) { 280 Map.Entry entry = (Map.Entry) map.entrySet().iterator().next(); 281 ClassFile clsFile = (ClassFile) entry.getValue(); 282 createJavaClass (resource, javaClasses, clsFile, map, result); 283 } } 285 286 private boolean newClassesNeeded(ResourceImpl resource, Map classesMap, boolean removeFeatures) { 287 Collection javaClasses = resource.getNakedClassifiers(); 288 Map nameToClass = new HashMap(); 289 for (Iterator iter = javaClasses.iterator(); iter.hasNext();) { 290 JavaClassImpl jc = (JavaClassImpl) iter.next(); 291 if (!isInIndex(jc, resource)) { 292 return true; 293 } 294 nameToClass.put(jc.getName(), jc); 295 collectInnerClasses(nameToClass, resource, jc); 296 } 297 if (classesMap.size() != nameToClass.size()) { 298 return true; 299 } 300 301 for (Iterator iter = classesMap.entrySet().iterator(); iter.hasNext();) { 302 Map.Entry entry = (Map.Entry) iter.next(); 303 ClassFile clsFile = (ClassFile) entry.getValue(); 304 ClassName clsName = clsFile.getName(); 305 String fullName = clsName.getExternalName(); 306 JavaClassImpl jc = (JavaClassImpl)nameToClass.get(fullName); 307 if (jc == null) { 308 return true; 309 } 310 int access = (clsFile.getAccess() & ~Access.SYNCHRONIZED); 311 if (access != jc.getSourceModifiers()) { 312 return true; 313 } 314 int declType = jc instanceof JavaEnum ? 1 : (jc instanceof AnnotationType ? 2 : 0); 315 boolean isEnum = clsFile.isEnum(); 316 boolean isAnnotation = clsFile.isAnnotation(); 317 if ((declType == 1 && !isEnum) || (declType != 1 && isEnum) || 318 (declType == 2 && !isAnnotation) || (declType != 2 && isAnnotation)) { 319 return true; 320 } 321 } 322 if (removeFeatures) { 323 for (Iterator iter = nameToClass.values().iterator(); iter.hasNext();) { 324 removePersisted((JavaClassImpl)iter.next()); 325 } 326 } 327 return false; 328 } 329 330 private boolean isInIndex(JavaClassImpl jc, Resource res) { 331 Iterator innerListIt = classIndex.getClassesByFqn(jc.getName()).iterator(); 332 while (innerListIt.hasNext()) { 333 JavaClassImpl innerJcls = (JavaClassImpl)innerListIt.next(); 334 if (res.equals(innerJcls.getResource())) { 335 return true; 336 } 337 } 338 return false; 339 } 340 341 private void collectInnerClasses(Map nameToClass, Resource res, JavaClassImpl jc) { 342 Iterator innerListIt = classIndex.getClassesByFQNPrefix(jc.getName().concat(".")).iterator(); while (innerListIt.hasNext()) { 344 JavaClassImpl innerJcls = (JavaClassImpl)innerListIt.next(); 345 if (res.equals(innerJcls.getResource())) { 346 nameToClass.put(innerJcls.getName(), innerJcls); 347 collectInnerClasses(nameToClass, res, innerJcls); 348 } 349 } 350 } 351 352 static void removePersisted(JavaClassImpl jcls) { 353 boolean changes = jcls.disableChanges; 354 jcls.disableChanges = true; 355 try { 356 357 Collection fs = jcls.getPersistentContents(); 358 if (!fs.isEmpty()) { 359 int size=fs.size(); 360 ClassMember features[]=(ClassMember[])fs.toArray(new ClassMember[size]); 361 for (int i=0;i<size;i++) { 362 ClassMember f=features[i]; 363 fs.remove(f); 364 if (!(f instanceof JavaClassImpl)) 365 f.refDelete(); 366 } 367 } 368 369 fs = jcls.getPersistentTypeParameters(); 370 if (!fs.isEmpty()) { 371 int size=fs.size(); 372 RefObject paramTypes[]=(RefObject[])fs.toArray(new RefObject[size]); 373 for (int i=0;i<size;i++) { 374 RefObject tp=paramTypes[i]; 375 fs.remove(tp); 376 tp.refDelete(); 377 } 378 } 379 380 fs = jcls.getPersistentAnnotations(); 381 if (!fs.isEmpty()) { 382 int size=fs.size(); 383 RefObject annos[]=(RefObject[])fs.toArray(new RefObject[size]); 384 for (int i=0;i<size;i++) { 385 RefObject anno=annos[i]; 386 fs.remove(anno); 387 anno.refDelete(); 388 } 389 } 390 391 if (jcls instanceof JavaEnumImpl) { 392 Collection ec = ((JavaEnumImpl) jcls).getPersistentConstants(); 393 if (!ec.isEmpty()) { 394 int cSize = ec.size(); 395 EnumConstant constants[] = (EnumConstant[]) ec.toArray(new EnumConstant[cSize]); 396 for (int i = 0; i < cSize; i++) { 397 EnumConstant c = constants[i]; 398 ec.remove(c); 399 c.refDelete(); 400 } 401 } 402 } 403 jcls.setPersisted(false); 404 } finally { 405 jcls.disableChanges = changes; 406 } 407 } 408 409 private JavaClassImpl createJavaClass (ResourceImpl resource, Collection resClassifiers, ClassFile clsFile, Map map, Map createdClasses) { 410 ClassName clsName = clsFile.getName(); 411 String fullName = clsName.getExternalName(); 412 String simpleName = clsName.getSimpleName(); 413 int index = simpleName.lastIndexOf('.'); 414 JavaClassImpl outer = null; 415 if (index > -1) { 416 String outerName = simpleName.substring (0, index); 418 outer = (JavaClassImpl) createdClasses.get (outerName); 419 if (outer == null) { 420 ClassFile outerClassFile = (ClassFile) map.get (outerName); 421 if (outerClassFile == null) { 422 map.remove (simpleName); 423 return null; 424 } 425 outer = createJavaClass (resource, resClassifiers, outerClassFile, map, createdClasses); 426 } 427 } 428 String pkgName = clsName.getPackage(); resource._setPackageName(pkgName); 430 int access = (clsFile.getAccess() & ~Access.SYNCHRONIZED) | (clsFile.isDeprecated() ? FeatureImpl.DEPRECATED : 0); 431 JavaClassImpl jc; 432 if (clsFile.isAnnotation()) { 433 jc = (JavaClassImpl) annoProxy.create(fullName, access, false); 434 } else if (clsFile.isEnum()) { 435 jc = (JavaClassImpl) enumProxy.create(fullName, access, false); 436 } else { 437 jc = (JavaClassImpl) clsProxy.create(fullName, access, null, null, false); 438 } 439 if (outer != null) { 442 if (outer.isPersisted()) { 443 outer.getPersistentContents().add(jc); 444 } else { 445 jc.setParentClass(outer); 446 } 447 } else { 448 resClassifiers.add(jc); 449 } 450 createdClasses.put (simpleName, jc); 451 map.remove (simpleName); 452 return jc; 453 } 454 } 455 | Popular Tags |