KickJava   Java API By Example, From Geeks To Geeks.

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


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
20 package org.netbeans.modules.javacore.scanning;
21 import java.io.InputStream JavaDoc;
22 import java.io.BufferedInputStream JavaDoc;
23 import java.lang.reflect.Modifier JavaDoc;
24 import java.util.*;
25 import org.netbeans.jmi.javamodel.*;
26 import org.netbeans.jmi.javamodel.JavaEnum;
27 import org.netbeans.lib.java.parser.ParserTokens;
28 import org.netbeans.modules.javacore.ClassIndex;
29 import org.netbeans.modules.javacore.JMManager;
30 import org.netbeans.modules.javacore.jmiimpl.javamodel.*;
31 import org.netbeans.modules.javacore.parser.TokenIterator;
32 import org.netbeans.modules.javacore.parser.MDRParser;
33 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
34 import org.openide.ErrorManager;
35
36 /**
37  *
38  * @author Tomas Hurka
39  */

40 public class JavaUpdater {
41     private final JavaClassClassImpl jclsClass;
42     private final JavaEnumClassImpl enumClass;
43     private final AnnotationTypeClassImpl annTypeClass;
44     private final ResourceClassImpl resourceClass;
45     private final ClassIndex classIndex;
46     private final String JavaDoc sourceLevel;
47     private final FileScanner fileScanner;
48     private static final int[] NULL_INTS=new int[0];
49     
50     /** Creates a new instance of JavaUpdater */
51     public JavaUpdater(JavaModelPackage mofModel,String JavaDoc srcLevel, FileScanner fileScanner) {
52         jclsClass = (JavaClassClassImpl) mofModel.getJavaClass();
53         enumClass = (JavaEnumClassImpl) mofModel.getJavaEnum();
54         resourceClass = (ResourceClassImpl) mofModel.getResource();
55         annTypeClass = (AnnotationTypeClassImpl) mofModel.getAnnotationType();
56         sourceLevel = srcLevel;
57         classIndex=ClassIndex.getIndex(mofModel);
58         this.fileScanner = fileScanner;
59     }
60
61     public int[] computeIndex(ResourceImpl resource,TokenIterator tokens) {
62         JavaMetamodel.getDefaultRepository().beginTrans(false);
63         try {
64             return makeIndex(resource,tokens,false);
65         } finally {
66             JavaMetamodel.getDefaultRepository().endTrans();
67         }
68     }
69
70     private int[] makeIndex(ResourceImpl resource,TokenIterator tokens, boolean removeFeatures) {
71         int idIndexes[]=NULL_INTS;
72         boolean resInited=resource.isInitialized();
73         HashSet reinitToDo = new HashSet();
74         List javaClasses;
75         Set remainingClasses;
76         Set usedClasses = new HashSet();
77         
78         javaClasses=resource.getPersistentClassifiers();
79
80         remainingClasses=getAllClassesFromResource(resource,javaClasses);
81         if (!resInited) {
82             javaClasses.clear();
83         }
84         try {
85             final int S_NORMAL=0;
86             final int S_PACKAGE=1;
87             final int S_CLASS=2;
88
89             String JavaDoc id;
90             IntSet ids=new IntSet();
91             Iterator idIt;
92             int i=0;
93             int token;
94             int last_token=0;
95             int state=S_NORMAL;
96             int modifiers=0;
97             String JavaDoc pack="";
98             Stack classes=new Stack();
99             int br_level=0;
100             boolean packageSet = false;
101
102             while((token=tokens.getNextTokenType())!=0) {
103                 String JavaDoc text=null;
104
105                 if (token==ParserTokens.IDENTIFIER) {
106                     int hash=tokens.getIdentifierHash();
107                     ids.add(hash);
108                 }
109         if (tokens.isDeprecated())
110             modifiers|=FeatureImpl.DEPRECATED;
111                 switch (token) {
112                     case ParserTokens.PUBLIC:
113                         modifiers|=Modifier.PUBLIC;
114                         break;
115                     case ParserTokens.PROTECTED:
116                         modifiers|=Modifier.PROTECTED;
117                         break;
118                     case ParserTokens.PRIVATE:
119                         modifiers|=Modifier.PRIVATE;
120                         break;
121                     case ParserTokens.ABSTRACT:
122                         modifiers|=Modifier.ABSTRACT;
123                         break;
124                     case ParserTokens.STATIC:
125                         modifiers|=Modifier.STATIC;
126                         break;
127                     case ParserTokens.FINAL:
128                         modifiers|=Modifier.FINAL;
129                         break;
130                     case ParserTokens.SYNCHRONIZED:
131                         modifiers|=Modifier.SYNCHRONIZED;
132                         break;
133                     case ParserTokens.NATIVE:
134                         modifiers|=Modifier.NATIVE;
135                         break;
136                     case ParserTokens.STRICTFP:
137                         modifiers|=Modifier.STRICT;
138                         break;
139                     case ParserTokens.TRANSIENT:
140                         modifiers|=Modifier.TRANSIENT;
141                         break;
142                     case ParserTokens.VOLATILE:
143                         modifiers|=Modifier.VOLATILE;
144                         break;
145                     case ParserTokens.SEMICOLON:
146                         modifiers=tokens.isDeprecated() ?
147                 FeatureImpl.DEPRECATED : 0;
148                         break;
149                     case ParserTokens.L_CURLY:
150                         br_level++;
151                         modifiers=tokens.isDeprecated() ?
152                 FeatureImpl.DEPRECATED : 0;
153                         break;
154                     case ParserTokens.R_CURLY:
155                         if (br_level==classes.size() && !classes.isEmpty())
156                             classes.pop();
157                         br_level--;
158                         break;
159                 }
160         if (last_token==ParserTokens.MONKEYS_AT &&
161             token==ParserTokens.IDENTIFIER) {
162                     String JavaDoc s=tokens.getIdentifierText();
163             if (s.equals("Deprecated") || // NOI18N
164
s.equals("java.lang.Deprecated")) // NOI18N
165
// @Deprecated annotation found
166
modifiers|=FeatureImpl.DEPRECATED;
167         }
168                 switch (state) {
169                     case S_NORMAL:
170                         if (token==ParserTokens.PACKAGE)
171                             state=S_PACKAGE;
172                         else if ((token==ParserTokens.CLASS || token==ParserTokens.INTERFACE || token==ParserTokens.ENUM) && last_token!=ParserTokens.DOT) {
173                             if (!packageSet) {
174                                 if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: Setting package name of resource " + resource.getName() + " to " + pack);
175                                 resource._setPackageName(pack);
176                                 packageSet = true;
177                             }
178                             if (last_token==ParserTokens.MONKEYS_AT && token==ParserTokens.INTERFACE) {
179                                 modifiers|=MDRParser.M_ANNOTATION; // we have found an annotation
180
ids.add("Annotation".hashCode()); // NOI18N
181
}
182                             state=S_CLASS;
183                         }
184                         break;
185                     case S_PACKAGE:
186             if (token==ParserTokens.IDENTIFIER)
187                 text=tokens.getIdentifierText();
188                         if (text!=null) {
189                             if (pack.length()==0)
190                                 pack=text;
191                             else
192                                 pack=pack + '.' + text; // NOI18N
193
}
194                         if (token==ParserTokens.SEMICOLON) {
195                             state=S_NORMAL;
196                         }
197                         break;
198                     case S_CLASS:
199             if (token==ParserTokens.IDENTIFIER)
200                 text=tokens.getIdentifierText();
201                         if (br_level==classes.size() && text!=null) {
202                             String JavaDoc fqn;
203                             JavaClassImpl jcls;
204                             JavaClassImpl enclosingClass=null;
205
206                             if (!classes.empty())
207                                 enclosingClass=(JavaClassImpl)classes.peek();
208                             fqn=constructFqn(pack,classes,text);
209                             if (last_token==ParserTokens.INTERFACE) {
210                                 modifiers|=Modifier.INTERFACE;
211                             } else if (last_token == ParserTokens.ENUM) {
212                                 modifiers |= MDRParser.M_ENUM;
213                                 ids.add("Enum".hashCode()); // NOI18N
214
}
215                             jcls=createJavaClass(fqn,modifiers,removeFeatures,text,remainingClasses,usedClasses,enclosingClass);
216                             usedClasses.add(jcls);
217                             classes.push(jcls);
218                             remainingClasses.remove(jcls);
219                             if (jcls.refImmediateComposite() == null) {
220                                 if (enclosingClass!=null) {
221                                     boolean contentsInited = enclosingClass.contentsInited();
222                                     boolean persisted = enclosingClass.isPersisted();
223                                     if (persisted) {
224                                         enclosingClass.getPersistentContents().add(jcls);
225                                         if (contentsInited) {
226                                             reinitToDo.add(enclosingClass);
227                                         }
228                                     } else {
229                                         jcls.setParentClass(enclosingClass);
230                                     }
231                                 } else {
232                                     javaClasses.add(jcls);
233                                 }
234                             }
235                         }
236                         state=S_NORMAL;
237                 }
238                 last_token=token;
239             }
240             if (!packageSet) {
241                 if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: Setting package name of resource " + resource.getName() + " to " + pack);
242                 resource._setPackageName(pack);
243             }
244             idIndexes=ids.toArray();
245             // the removal has to be done always, to avoid duplicate classes in index
246
// if (!resInited) {
247
for (Iterator it = remainingClasses.iterator(); it.hasNext();) {
248                     JavaClassImpl cls = (JavaClassImpl) it.next();
249                     // if some of the classes was deleted and it contained innerclasses,
250
// these innerclasses were automatically deleted too
251
// so we need to check for validity to make sure refDelete is not called
252
// on classes that have already been deleted
253
if (cls.isValid()) {
254                         Object JavaDoc parent = cls.refImmediateComposite();
255                         if (parent == resource) {
256                             javaClasses.remove(cls);
257                         } else if (parent instanceof JavaClassImpl) {
258                             JavaClassImpl enclosingClass = (JavaClassImpl) parent;
259                             boolean contentsInited = enclosingClass.contentsInited();
260                             boolean persisted = enclosingClass.isPersisted();
261                             if (persisted) {
262                                 enclosingClass.getPersistentContents().remove(cls);
263                                 if (contentsInited) {
264                                     reinitToDo.add(enclosingClass);
265                                 }
266                             } else {
267                                 cls.setParentClass(null);
268                             }
269                         }
270                         cls.refDelete();
271                     }
272                 }
273 // }
274
if (resource.classifiersInited())
275                 resource.reinitClassifiers();
276             for (Iterator it = reinitToDo.iterator(); it.hasNext();) {
277                 // if during the deletion an innerclass was deleted first (so the outerclass
278
// was added to the reinitToDo) and then its outerclass was deleted too,
279
// we can have an invalid object in this collection -> validity check is necessary
280
JavaClassImpl cls = (JavaClassImpl) it.next();
281                 if (cls.isValid()) {
282                     cls.reinitContents();
283                 }
284             }
285         } catch (Exception JavaDoc ex) {
286             ErrorManager.getDefault().notify(ex);
287         }
288         return idIndexes;
289     }
290
291     private JavaClassImpl createJavaClass(String JavaDoc fqn, int modifiers,boolean removeFeatures, String JavaDoc simpleName,Set remainingClasses,Set usedClasses,JavaClass enclosingClass) {
292         Collection classes = classIndex.getClassesByFqn(fqn);
293         JavaClass jcls = null;
294
295         if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: Looking for class: " + fqn);
296         for (Iterator it = classes.iterator(); it.hasNext();) {
297             JavaClass temp = (JavaClass) it.next();
298             if ((!removeFeatures && enclosingClass != null && enclosingClass.equals(temp.refImmediateComposite()) && !usedClasses.contains(temp)) || remainingClasses.contains(temp)) {
299                 if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: Existing class found in index.");
300                 
301                 // if the temp exists test for the change of declaration type. E.g.
302
// Used when user changes enum declaration to class and vice versa.
303
int declType = temp instanceof JavaEnum ? 1 : (temp instanceof AnnotationType ? 2 : 0);
304                 if ((declType == 1 && !isEnum(modifiers)) || (declType != 1 && isEnum(modifiers)) ||
305                     (declType == 2 && !isAnnotation(modifiers)) || (declType != 2 && isAnnotation(modifiers)))
306                 {
307                     // class type changed
308
if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: The found class is of wrong type: " + temp.getClass().getName() + " -> deleting...");
309                     // make sure the class is in remainingClasses so it gets deleted
310
// at the end
311
remainingClasses.add(temp);
312                 } else {
313                     jcls = temp;
314                 }
315                 break;
316             }
317         }
318
319         if (jcls==null) {
320             if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaUpdater: No suitable class found -> creating...");
321             if (isEnum(modifiers)) {
322                 jcls = enumClass.create(fqn, modifiers, false);
323             } else if (isAnnotation(modifiers)) {
324                 jcls = annTypeClass.create(fqn, modifiers, false);
325             } else {
326                 jcls = jclsClass.create(fqn, modifiers, null, null, false);
327             }
328             // should not add the class to the index - it is already done in the create method
329
//classIndex.addClass(jcls, fqn, simpleName);
330
} else {
331             if (removeFeatures) {
332                 ClassUpdater.removePersisted((JavaClassImpl) jcls);
333             }
334         }
335         return (JavaClassImpl) jcls;
336     }
337
338     private Set getAllClassesFromResource(Resource res,Collection topLevelClasses) {
339         Iterator topIt=topLevelClasses.iterator();
340         Set allClasses=new HashSet();
341         
342         while(topIt.hasNext()) {
343             JavaClass topJcls=(JavaClass)topIt.next();
344             Iterator innerListIt=classIndex.getClassesByFQNPrefix(topJcls.getName().concat(".")).iterator(); // NOI18N
345

346             allClasses.add(topJcls);
347             while (innerListIt.hasNext()) {
348                 JavaClass innerJcls=(JavaClass)innerListIt.next();
349                 
350                 if (res.equals(innerJcls.getResource())) {
351                     allClasses.add(innerJcls);
352                 }
353             }
354         }
355         return allClasses;
356     }
357     
358     private static boolean isEnum(int modifiers) {
359         return (modifiers & MDRParser.M_ENUM) != 0;
360     }
361     
362     private static boolean isAnnotation(int modifiers) {
363         return (modifiers & MDRParser.M_ANNOTATION) != 0;
364     }
365
366     private String JavaDoc constructFqn(String JavaDoc pack,Stack names,String JavaDoc simpleName) {
367         String JavaDoc name;
368
369         if (names.isEmpty()) {
370             if (pack.length()>0) {
371                 name=pack+'.';
372             } else {
373                 name="";
374             }
375         } else {
376             name=((JavaClass)names.peek()).getName()+'.';
377         }
378         return name.concat(simpleName);
379     }
380
381     public Collection updateResources(Map javaFiles)
382     {
383         JavaMetamodel.getDefaultRepository().beginTrans(false);
384         try {
385             Iterator resIt=javaFiles.values().iterator();
386             List resList=new ArrayList();
387             long indexTimestamp;
388
389             indexTimestamp=classIndex.getTimestamp();
390             while(resIt.hasNext()) {
391                 FileInfo file=(FileInfo)resIt.next();
392                 try {
393                     String JavaDoc name=file.getPath();
394                     long timestamp=file.lastModified();
395                     ResourceImpl resource=(ResourceImpl) resourceClass.resolveResource(name,true,false);
396
397                     resList.add(resource);
398                     if (resource.getTimestamp()!=timestamp || resource.isFromMemory() || indexTimestamp<timestamp) {
399                         resource.setTimestamp(timestamp, false);
400                         if (fileScanner != null) fileScanner.checkParseEagerly(resource);
401                         InputStream JavaDoc stream=new BufferedInputStream JavaDoc(file.getInputStream());
402
403                         try {
404                             int ids[]=makeIndex(resource, new TokenIterator(stream,sourceLevel,true), !resource.isInitialized());
405                             classIndex.setIdentifiers(resource,ids);
406                         } finally {
407                             stream.close();
408                         }
409                     }
410                 } catch (Exception JavaDoc ex) {
411                     ErrorManager.getDefault().notify(ex);
412                 }
413             }
414             return resList;
415         } finally {
416             JavaMetamodel.getDefaultRepository().endTrans();
417         }
418     }
419 }
420
Popular Tags