KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > scanning > ClassUpdater


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

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 /**
43  *
44  * @author Tomas Hurka
45  */

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     /** Creates a new instance of ClassUpdater */
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 JavaDoc fname=fobj.getNameExt();
76             String JavaDoc prefix=fobj.getName().concat("$");
77             String JavaDoc 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 JavaDoc name = (String JavaDoc) entry.getKey();
114             
115             int index = name.indexOf('$');
116             String JavaDoc resName = (index > -1) ? name.substring(0, index) + ".class" : name; //NOI18N
117

118             // ignore classes with correcponding java files in the same directory
119
String JavaDoc srcName = resName.substring(0, resName.length() - ".class".length()) + ".java"; // NOI18N
120
if (sources.containsKey(srcName)) continue;
121             // ------------------------
122

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         } // while
135

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 JavaDoc) iter2.next()).intValue();
145             }
146             ResourceImpl resource = (ResourceImpl) entry.getKey();
147             classIndex.setIdentifiers(resource,hc);
148         } // for
149

150         iter = nameToResource.entrySet().iterator();
151         while (iter.hasNext()) {
152             Map.Entry entry = (Map.Entry) iter.next();
153             String JavaDoc resName = (String JavaDoc) 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 JavaDoc 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                 // ignore this class [PENDING]
182
unmodifiedResources.put(name,null);
183                 JMManager.getLog().log("ClassUpdater, cannot find file object: " + name); // NOI18N
184
return null;
185             }
186             if (updatedResource!=null) {
187                 assert updatedResource.getName().endsWith(name): updatedResource.getName()+" "+name; // NOI18N
188
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 JavaDoc getSimpleName (ClassName clsName) {
208         String JavaDoc 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 JavaDoc nameToHashCode (ClassName clsName) {
217         return new Integer JavaDoc (getSimpleName (clsName).hashCode());
218     }
219
220     public boolean isAnonymous (ClassFile clsFile) {
221         String JavaDoc 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); // NOI18N
225
}
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()); // NOI18N
244
} 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         } // if
250
return clsFile;
251     }
252
253     public void addFileToMap (String JavaDoc 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 JavaDoc 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         } // while
284
}
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 JavaDoc 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(); // NOI18N
343
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 JavaDoc fullName = clsName.getExternalName();
412         String JavaDoc simpleName = clsName.getSimpleName();
413         int index = simpleName.lastIndexOf('.');
414         JavaClassImpl outer = null;
415         if (index > -1) {
416             // obtain outerclass
417
String JavaDoc 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 JavaDoc pkgName = clsName.getPackage(); // [PENDING] ?? should be obtained only once (globally)
429
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         // should not add to class to the index - > it is added in the create method
440
//classIndex.addClass(jc, fullName, getSimpleName(clsName));
441
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