KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > jmiimpl > javamodel > ResourceImpl


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.jmiimpl.javamodel;
20
21 import java.beans.PropertyChangeListener JavaDoc;
22 import java.beans.PropertyChangeSupport JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.Reader JavaDoc;
27 import java.lang.reflect.Modifier JavaDoc;
28 import java.util.*;
29 import java.util.regex.Pattern JavaDoc;
30 import javax.jmi.reflect.*;
31 import javax.swing.text.Position JavaDoc;
32 import javax.swing.text.StyledDocument JavaDoc;
33 import org.netbeans.jmi.javamodel.*;
34 import org.netbeans.lib.java.parser.*;
35 import org.netbeans.api.mdr.MDRepository;
36 import org.netbeans.mdr.NBMDRepositoryImpl;
37 import org.netbeans.mdr.handlers.AttrListWrapper;
38 import org.netbeans.mdr.persistence.StorageException;
39 import org.netbeans.mdr.storagemodel.StorableObject;
40 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
41 import org.netbeans.modules.javacore.*;
42 import org.netbeans.modules.javacore.parser.*;
43 import org.netbeans.modules.javacore.parser.Util;
44 import org.openide.ErrorManager;
45 import org.openide.filesystems.FileLock;
46 import org.openide.filesystems.FileObject;
47 import org.openide.loaders.DataObject;
48 import org.openide.text.CloneableEditorSupport;
49 import org.openide.text.NbDocument;
50 import org.openide.text.PositionBounds;
51 import org.openide.text.PositionRef;
52 import org.netbeans.modules.javacore.scanning.ClassUpdater;
53 import org.netbeans.modules.javacore.scanning.JavaUpdater;
54
55 /**
56  * Implementation of Resource interface.
57  *
58  * @author Martin Matula
59  */

60 public abstract class ResourceImpl extends SemiPersistentElement implements Resource {
61     // this switch enable test JavaMetamodel without bridge and persistency behaviour
62
public static boolean READ_ONLY = false;
63     // java features flags
64
public static final int HAS_GENERICS = 1;
65     public static final int HAS_ENUMS = 2;
66     public static final int HAS_ANNOTATIONTYPES = 4;
67     public static final int HAS_ANNOTATION = 8;
68     public static final int HAS_SYNTAX_ERROR = 16;
69     // status indicating that the resource represents a classfile
70
public static final int IS_FROM_CLASSFILE = 0x80000000;
71     
72     public static final String JavaDoc CLASSIFIERS_ATTR = "classifiers"; // NOI18N
73

74     private static final ElementInfo DEFAULT_INFO = new ResourceInfo(null, ResourceInfo.RESOURCE_TYPE, null, null, null);
75     
76     private static final String JavaDoc lineSeparator = System.getProperty("line.separator"); // NOI18N
77
private static final boolean lfOnly = "\n".equals(lineSeparator); // NOI18N
78
private static final Pattern JavaDoc lineSepPattern = Pattern.compile("\r?\n"); // NOI18N
79

80     private LightAttrList classifiers = null;
81     private LightAttrList imports = null;
82     private FileObject fileToDeleteOnRollback = null;
83
84     private MultipartId packageIdentifier = null;
85
86     private boolean elementsInited = false;
87
88     private DiffList invertedDiffs = null;
89     
90     // source text info
91
private String JavaDoc lastSourceText;
92     private boolean isFromDoc;
93     // cached dataobject corresponding to this resource
94
private FileObject fobj;
95     
96     private DiffList extDiffs;
97
98     // rollback related info
99
private String JavaDoc rbText = null;
100     private List rbList = null;
101     
102     private List errors = null;
103
104     /** Creates a new instance of ResourceImpl */
105     public ResourceImpl(StorableObject s) {
106         super(s);
107     }
108
109     private static String JavaDoc lastPackageName = null;
110     private static JavaPackage lastPackage = null;
111     private static JavaPackageClass lastPackageProxy = null;
112
113     public void _setPackageName(String JavaDoc name) {
114         if (JMManager.INCONSISTENCY_DEBUG) System.err.println("ResourceImpl: Setting package name of resource " + getName() + " to " + name);
115         JavaPackage oldPackage = null;
116         try {
117             oldPackage = (JavaPackage) ((NBMDRepositoryImpl) repository()).getHandler(((StorableObject) _getDelegate()).getImmediateComposite());
118         } catch (StorageException e) {
119             ErrorManager.getDefault().notify(e);
120         }
121         JavaPackageClassImpl pkgProxy = (JavaPackageClassImpl) ((JavaModelPackage) refImmediatePackage()).getJavaPackage();
122         if (oldPackage != null) {
123             if (name.equals(oldPackage.getName())) return;
124             oldPackage.getResources().remove(this);
125         }
126         if (lastPackage == null || !name.equals(lastPackageName) || !pkgProxy.equals(lastPackageProxy)) {
127             lastPackage = pkgProxy.resolveRealPackage(name);
128             lastPackageName = name;
129             lastPackageProxy = pkgProxy;
130         }
131         lastPackage.getResources().add(this);
132     }
133
134     public void setPackageName(String JavaDoc name) {
135         String JavaDoc oldName = getPackageName();
136         if (!name.equals(oldName)) {
137             MultipartIdClass proxy = ((JavaModelPackage) refImmediatePackage()).getMultipartId();
138             setPackageIdentifier(proxy.createMultipartId(name, null, null));
139         }
140     }
141
142     private void setPkgNameAndUpdateIdx(String JavaDoc name) {
143         if (isInitialized() && !isNew()) {
144             getElementInfo().hardRefAST();
145         }
146         _setPackageName(name);
147         for (Iterator it = getClassifiers().iterator(); it.hasNext();) {
148             Object JavaDoc temp = it.next();
149             if (temp instanceof JavaClassImpl) {
150                 JavaClassImpl cls = (JavaClassImpl) temp;
151                 String JavaDoc interName = name.length() == 0 ? "" : name + '.';
152                 cls.internalSetName(interName.concat(cls.getSimpleName()));
153             }
154         }
155     }
156     
157     public Collection getReferences() {
158         return Collections.EMPTY_LIST;
159     }
160
161     public boolean classifiersInited() {
162         return classifiers != null;
163     }
164     
165     public void reinitClassifiers() {
166         assert classifiers!=null;
167         classifiers.setInnerList(getPersistentClassifiers(), false);
168     }
169     
170     public List getClassifiers() {
171         if (checkModCount() && !(isSafeTrans() && isPersisted())) checkUpToDate(false,false,true);
172         if (classifiers == null) {
173             classifiers = createChildrenList(CLASSIFIERS_ATTR, (AttrListWrapper) super_getClassifiers(), null, CHANGED_CLASSIFIERS); // NOI18N
174
}
175         return classifiers;
176     }
177
178     public List getPersistentClassifiers() {
179         AttrListWrapper list = (AttrListWrapper) super_getClassifiers();
180         list.setAttrName(CLASSIFIERS_ATTR); // NOI18N
181
return list;
182     }
183
184     protected abstract List super_getClassifiers();
185
186     public List getNakedClassifiers() {
187         try {
188             return (List) ((StorableObject) _getDelegate()).getAttribute(CLASSIFIERS_ATTR); // NOI18N
189
} catch (StorageException e) {
190             throw (GeneralException) ErrorManager.getDefault().annotate(new GeneralException(e.getMessage()), e);
191         }
192     }
193     
194     public String JavaDoc getPackageName() {
195         if (!isSafeTrans() && checkModCount()) checkUpToDate(false,false,true);
196         JavaPackage pkg = (JavaPackage) _realImmediateComposite();
197         return pkg == null ? null : pkg.getName();
198     }
199
200 // protected abstract void super_setPackageName(String name);
201

202     /** Should be overriden by elements that have persistent attributes.
203      * They should implement this method to compare values in newly passed AST info with
204      * values of the persistent attributes and if the values do not match, they should be
205      * updated and proper events should be fired.
206      */

207     protected void matchPersistent(ElementInfo info) {
208         super.matchPersistent(info);
209         if (!isPersisted()) {
210             setPersisted(true);
211         }
212         processMembers(getClassifiers(), ((ResourceInfo) info).classes);
213     }
214     
215     public boolean isPersisted() {
216         return _getDelegate().getSlot1() != null;
217     }
218     
219     public void setPersisted(boolean persisted) {
220         _getDelegate().setSlot1(persisted ? "" : null);
221     }
222
223     protected ElementInfo getDefaultInfo() {
224         return DEFAULT_INFO;
225     }
226
227     /** The method has to make sure that the AST infos of children are also updated.
228      */

229     protected void matchElementInfo(ElementInfo newInfo) {
230         Iterator classIt;
231         ResourceInfo astInfo;
232         int i=0;
233         
234         super.matchElementInfo(newInfo);
235         astInfo=(ResourceInfo)newInfo;
236         if (imports != null) {
237             processMembers(getImports(),astInfo.imports);
238         }
239         resetASTElements();
240     }
241
242     protected void resetChildren() {
243         super.resetChildren();
244         if (childrenInited) {
245             resetASTElements();
246             initChildren(true);
247         }
248     }
249
250     protected List getInitedChildren() {
251         List list=new ArrayList();
252         if (childrenInited) {
253             list.addAll(getImports());
254             list.addAll(getClassifiers());
255         }
256         if (elementsInited) {
257            addIfNotNull(list, packageIdentifier);
258         }
259         return list;
260     }
261     
262     public List getChildren() {
263         List list = new ArrayList();
264         addIfNotNull(list, getPackageIdentifier());
265         list.addAll(getImports());
266         list.addAll(getClassifiers());
267         return list;
268     }
269
270     /**
271      * Returns the value of attribute imports.
272      * @return Value of imports attribute.
273      */

274     public List getImports() {
275         checkUpToDate();
276         if (!childrenInited) {
277             initChildren();
278         }
279         return imports;
280     }
281
282     public void setName(String JavaDoc name) {
283         // [TODO] change the name of the underlying file
284
// [TODO] check for duplicates
285
assert !name.startsWith("/") : "Resource name cannot start with /"; // NOI18N
286
super_setName(name);
287     }
288     
289     public void setTimestamp(long timestamp) {
290         super_setTimestamp(timestamp);
291     }
292     
293     /** Sets the resource timestamp along with an information if it is updated
294      * from memory (i.e. from a file edited in the editor but not saved on the disk.
295      * It is because in this case the timestamp is not sufficient for determining whether
296      * a file is out of date.
297      * @param timestamp Timestamp of the file on the disk.
298      * @param isFromMemory Indicates whether a file is edited in memory and not saved yet.
299      */

300     public void setTimestamp(long timestamp, boolean isFromMemory) {
301         setTimestamp(timestamp);
302         setFromMemory(isFromMemory);
303     }
304     
305     private void setFromMemory(boolean fromMemory) {
306         _getDelegate().setSlot2(fromMemory ? "" : null);
307     }
308     
309     /** Returns true if at the last parse this resource was updated from a document
310      * modified in memory and not saved yet.
311      * @return true if the resource was updated from a document edited in memory and not saved.
312      */

313     public boolean isFromMemory() {
314         return _getDelegate().getSlot2() != null;
315     }
316     
317     protected abstract void super_setTimestamp(long timestamp);
318
319     protected abstract void super_setName(String JavaDoc name);
320
321     protected void initChildren() {
322         initChildren(false);
323     }
324
325     private void initChildren(boolean rebuild) {
326         childrenInited = false;
327
328         ClassInfo classes[] = ((ResourceInfo) getElementInfo()).classes;
329         // create children
330
if (getClassifiers().size() != classes.length) {
331             fixMembers(getPersistentClassifiers(), classes);
332             reinitClassifiers();
333         } else {
334             Iterator it = getClassifiers().iterator();
335             for (int i = 0; i < classes.length; i++) {
336                 SemiPersistentElement element = (SemiPersistentElement) it.next();
337                 if (!element.infoIdenticalTo(classes[i])) {
338                     element.setElementInfo(classes[i]);
339                 }
340             }
341         }
342
343         imports = createChildrenList(imports, "imports", ((ResourceInfo) getElementInfo()).imports, CHANGED_IMPORTS, rebuild); // NOI18N
344

345         childrenInited = true;
346
347         if (elementsInited) {
348             initASTElements();
349         }
350
351         fireImportsInited();
352     }
353
354     protected void initASTElements() {
355         elementsInited = false;
356
357         if (!childrenInited) {
358             initChildren();
359         }
360         ResourceInfo info = (ResourceInfo) getElementInfo();
361         packageIdentifier = (MultipartId) initOrCreate(packageIdentifier, info.getTypeAST(this));
362         elementsInited = true;
363     }
364     
365     protected void resetASTElements() {
366         if (elementsInited) {
367             if (packageIdentifier != null) {
368                 MultipartId temp = packageIdentifier;
369                 packageIdentifier = null;
370                 temp.refDelete();
371             }
372             elementsInited = false;
373         }
374     }
375
376     public int getStatus() {
377         _lock(false);
378         try {
379             if (getName().endsWith(".class")) { // NOI18N
380
return IS_FROM_CLASSFILE;
381             } else {
382                 MDRParser parser = getParser();
383                 int res = parser.getJavaFeatures();
384                 if (parser.hasSyntaxError()) {
385                     res |= HAS_SYNTAX_ERROR;
386                 }
387                 return res;
388             }
389         } finally {
390             _unlock();
391         }
392     }
393
394     public List getErrors() {
395         _lock(false);
396         try {
397             if (errors == null) {
398                 errors = new ErrorList();
399             }
400             return errors;
401         } finally {
402             _unlock();
403         }
404     }
405
406     public void resetErrors() {
407         if (errors != null) {
408             _lock(false);
409             try {
410                 errors = null;
411             } finally {
412                 _unlock();
413             }
414         }
415     }
416     
417     private ResourceInfo getResInfoFromClassFile() {
418         Iterator iter = getPersistentClassifiers().iterator();
419         FileObject resFile = JavaMetamodel.getManager().getFileObject(this);
420         FileObject folder = resFile.getParent();
421         ArrayList clsInfo = new ArrayList();
422         ClassFileInfoUtil cfiu = new ClassFileInfoUtil();
423         while (iter.hasNext()) {
424             Object JavaDoc elem = iter.next();
425             if (elem instanceof JavaClassImpl) {
426                 JavaClassImpl jc = (JavaClassImpl) elem;
427                 ClassInfo inf = cfiu.createClassInfo (folder, jc.getSimpleName(), -1);
428                 if (inf != null)
429                     clsInfo.add(inf);
430             } // if
431
} // while
432
return new ResourceInfo(null, ResourceInfo.RESOURCE_TYPE, this, (ClassInfo[]) clsInfo.toArray(new ClassInfo[clsInfo.size()]), null);
433     }
434     
435     void initResource() {
436         checkUpToDate(false, true, false);
437     }
438
439     protected void objectChanged(int mask) {
440         if (disableChanges) return;
441         if (!isChanged()) {
442             ElementInfo info = getElementInfo();
443             if (info.getASTree() == null && info != getDefaultInfo()) {
444                 throw new UnsupportedOperationException JavaDoc("This object is immutable."); // NOI18N
445
}
446             ((ExclusiveMutex) _getMdrStorage().getRepositoryMutex()).registerChange(this);
447         }
448         super.objectChanged(mask);
449     }
450     
451     public void updateFromFileObject(FileObject fo, boolean force) {
452         boolean fail = true;
453         _lock(true);
454         try {
455             checkUpToDate(fo, force, false, false, false);
456             fail = false;
457         } finally {
458             _unlock(fail);
459         }
460     }
461
462     PositionBounds getFeaturePosition(FeatureImpl feature) {
463         if (!isValid())
464             return null;
465
466         MDRParser parser = getParser();
467         if (parser == null)
468             return null;
469         if (parser.mofidToBounds == null) {
470             // cache position bounds
471
MDRepository repository = repository();
472             repository.beginTrans(false);
473             try {
474                 parser.mofidToBounds = new HashMap();
475                 if (((JMManager) JavaMetamodel.getManager()).getTransactionMutex().getClassPath() == null) {
476                     JavaMetamodel.getManager().setClassPath(this);
477                 }
478                 for (Iterator iter = getClassifiers().iterator(); iter.hasNext(); ) {
479                     cachePositions(parser, (MetadataElement)iter.next());
480                 }
481             } catch (InvalidObjectException e) {
482                 // ignore
483
} finally {
484                 repository.endTrans(false);
485             }
486         }
487         return parser.mofidToBounds == null ? null : (PositionBounds) parser.mofidToBounds.get(feature._getMofId());
488     }
489     
490     private void cachePositions(MDRParser parser, MetadataElement f) {
491         ASTree tree = f.getASTree();
492         if (tree != null)
493             parser.mofidToBounds.put(f._getMofId(), parser.createBounds(tree, tree, false));
494         if (f instanceof JavaClassImpl) {
495             Object JavaDoc[] features=((JavaClassImpl)f).getFeatures().toArray();
496             for (int i=0;i<features.length;i++) {
497                 cachePositions(parser, (MetadataElement)features[i]);
498             }
499         }
500     }
501     
502     public RuntimeException JavaDoc alreadyCheckingStackTrace;
503     
504     private void resetAST(MDRParser parser) {
505         try {
506             alreadyChecking = true;
507             alreadyCheckingStackTrace = new RuntimeException JavaDoc();
508             ClassIndex classIndex=ClassIndex.getIndex((JavaModelPackage)refOutermostPackage());
509             Set ids=new HashSet(60);
510             TokenIterator tokens;
511             int idIndexes[];
512             int token;
513             int i=0;
514             Iterator idIt;
515
516             parser.getASTree();
517             tokens=new TokenIterator(parser);
518             while((token=tokens.getNextTokenType())!=0) {
519                 if (token==ParserTokens.IDENTIFIER) {
520                     ids.add(tokens.getIdentifierText());
521                 }
522             }
523             idIndexes=new int[ids.size()];
524             idIt=ids.iterator();
525             while(idIt.hasNext()) {
526                 idIndexes[i++]=idIt.next().hashCode();
527             }
528             classIndex.setIdentifiers(this,idIndexes);
529             updateMetadata(parser.enterMembers());
530         } catch (IOException JavaDoc ex) {
531             ErrorManager.getDefault().notify(ex);
532         } finally {
533             alreadyChecking = false;
534         }
535     }
536
537     public FileObject getFileObject() {
538         FileObject fo = JMManager.getManager().getFileObject(this);
539         if (fo != null) {
540             if (fo.isVirtual()) {
541                 this.fobj = null;
542                 return null;
543             }
544         }
545         if (fo == null) {
546             fo = this.fobj;
547         } else if (JMManager.PERF_DEBUG && !fo.equals(this.fobj) && this.fobj != null) {
548             System.err.println("FileObject for resource " + getName() + " changed from " + this.fobj.toString() + " to " + fo.toString()); // NOI18N
549
}
550         if (fo != null && !fo.isValid()) fo = null;
551         this.fobj = fo;
552         return fo;
553     }
554     
555     public MDRParser createMDRParser(FileObject fobj, boolean resetSourceText) {
556         if (fobj == null) {
557             fobj = getFileObject();
558             if (fobj == null) {
559                 JMManager.getLog().log(ErrorManager.WARNING, "FileObject not found for resource: " + getName());
560                 return null;
561             }
562         }
563         if (resetSourceText || lastSourceText == null) {
564             if (!resetSourceText && isInitialized()) {
565                 System.err.println("Resource is initialized, but lastSourceText == null.");
566                 Thread.dumpStack();
567             }
568             MDRParser result = new MDRParser(this, fobj, null, false);
569             lastSourceText = result.getSourceText();
570             isFromDoc = result.isFromDocument();
571             return result;
572         } else {
573             return new MDRParser(this, fobj, lastSourceText, isFromDoc);
574         }
575     }
576     
577     /** Method that checks whether this resource is up-to-date and does the scanning/parsing if needed.
578      * @param initIfOutOfDate Forces parsing if the resource is not fully persisted yet or if it is out of date.
579      * This results in synchronizing of the persistent metadata with the source code in the resource.
580      * (Used by checkUpToDate on individual metadata elements.)
581      * @param initialize Forces parsing to initialize this resource (create ResourceInfo). Used by {@link initResource}.
582      * @param canUpdate Indicates whether the resource can be updated if out-of-date. This is unwanted when the resource
583      * and its children are already being used in a running transaction - updating them behind the scenes could have
584      * serious side-effects (InvalidObjectExceptions, ConcurrentModificationExceptions, etc.)
585      */

586     boolean checkUpToDate(boolean initIfOutOfDate, boolean initialize, boolean canUpdate) {
587         FileObject fobj = JavaMetamodel.getManager().getFileObject(this);
588         
589         if (fobj==null) {
590             JMManager.getLog().log(ErrorManager.WARNING, "FileObject not found for resource: " + getName());
591             return true;
592         }
593         return checkUpToDate(fobj, false, initialize, initIfOutOfDate, canUpdate);
594     }
595     
596     public boolean alreadyChecking = false;
597     
598     /** Method that checks whether this resource is up-to-date and does the scanning/parsing if needed.
599      * @param dobj FileObject corresponding to this resource.
600      * @param force Treats the resource as if it was out-of-date (i.e. as if its timestamp would not match timestamp
601      * of the corresponding file) - used for updating of files modified in the editor but not on the disk.
602      * @param initialize Forces parsing to initialize this resource (create ResourceInfo). Used by {@link initResource}.
603      * @param initIfOutOfDate Forces parsing if the resource is not fully persisted yet or if it is out of date.
604      * This results in synchronizing of the persistent metadata with the source code in the resource.
605      * (Used by checkUpToDate on individual metadata elements.)
606      * @param canUpdate Indicates whether the resource can be updated if out-of-date. This is unwanted when the resource
607      * and its children are already being used in a running transaction - updating them behind the scenes could have
608      * serious side-effects (InvalidObjectExceptions, ConcurrentModificationExceptions, etc.)
609      */

610     private boolean checkUpToDate(FileObject fobj, boolean force, boolean initialize, boolean initIfOutOfDate, boolean canUpdate) {
611         // we do not want to update resource when commit is in progress (it will be updated at the end)
612
if (!alreadyChecking && !isChanged()) {
613             canUpdate |= checkAndUpdateModCount();
614             try {
615                 alreadyChecking = true;
616                 alreadyCheckingStackTrace = new RuntimeException JavaDoc();
617                 long timestamp;
618                 if (canUpdate) {
619                     timestamp = fobj.lastModified().getTime();
620                     
621                     // code necessary when a file is parsed sooner that the classpath root is scanned
622
// to properly check whether a file needs to be updated
623
// (to cover the case when it was edited in the editor and on
624
// shutdown the changes were discarded)
625
if (!force && timestamp == getTimestamp()) {
626                         force = isFromMemory() && !Util.isModified(fobj);
627                     }
628                     // ------
629

630                     // TODO: ideally we should parse the document if it is in the "modified" collection
631
// however since the parsing takes too long currently, we will not parse the file
632
// after every modification (because of the performance of the code completion)
633
// that's why this code is commented out for now
634
// force |= JavaMetamodel.getManager().removeModified(dobj);
635
} else {
636                     timestamp = getTimestamp();
637                     if (force) {
638                         // since canUpdate will be false, the resource will not be updated
639
// so I have to make sure that it stays in the needParsing set for the next
640
// transaction
641
JMManager.getTransactionMutex().addModified(fobj);
642                     }
643                 }
644                 
645                 boolean isOutOfDate = force || getTimestamp() != timestamp;
646                 boolean shouldUpdate = canUpdate && isOutOfDate;
647                 boolean shouldParse = initialize || (initIfOutOfDate && !isPersisted()) || (shouldUpdate && (initIfOutOfDate || isInitialized()));
648                 if (shouldUpdate || shouldParse) {
649                     if (getName().endsWith(".java")) { // NOI18N
650
directUpdate(fobj, shouldUpdate, shouldParse, timestamp);
651                     } else {
652                         // updating of class files does not need to be that robust - we will ignore canUpdate
653
// flag and pass isOutOfDate directly
654
directClassFileUpdate(fobj, isOutOfDate, shouldParse);
655                     }
656                     return false;
657                 } else {
658                     if (lastSourceText == null && getName().endsWith(".java")) { // NOI18N
659
createMDRParser(fobj, true);
660                     }
661                 }
662             } finally {
663                 alreadyChecking = false;
664             }
665         }
666         return true;
667     }
668
669     private void directClassFileUpdate(FileObject fobj, boolean isOutOfDate, boolean shouldParse) {
670         if (isOutOfDate) {
671             boolean changes = disableChanges;
672             disableChanges = true;
673             try {
674                 ClassUpdater.updateIndex(this,fobj);
675             } finally {
676                 disableChanges = changes;
677             }
678         }
679         if (shouldParse) {
680             ResourceInfo resInfo=getResInfoFromClassFile();
681             updateMetadata(resInfo);
682         } else {
683             setPersisted(false);
684         }
685     }
686
687     private void directUpdate(FileObject fobj, boolean isOutOfDate, boolean shouldParse, long timestamp) {
688         if (JMManager.INCONSISTENCY_DEBUG) {
689             System.err.println("Direct update of: " + getName());
690             System.err.println("isOutOfDate: " + isOutOfDate + " shouldParse: " + shouldParse);
691             Thread.dumpStack();
692         }
693         
694         MDRParser parser = createMDRParser(fobj, isOutOfDate);
695         
696         TokenIterator tokenIterator = null;
697         Reader JavaDoc reader = null;
698         
699         boolean changes = disableChanges;
700         disableChanges = true;
701         try {
702             if (shouldParse) {
703                 parser.getASTree();
704                 tokenIterator = new TokenIterator(parser);
705             } else if (isOutOfDate) {
706                 reader = parser.getReader();
707                 tokenIterator = new TokenIterator(reader, parser.getSourceLevel());
708             }
709
710             if (isOutOfDate) {
711                 errors = null;
712                 int ids[];
713                 JavaModelPackage pck=(JavaModelPackage)refOutermostPackage();
714                 ClassIndex classIndex=ClassIndex.getIndex(pck);
715                 
716                 boolean isModified = Util.isModified(fobj);
717                 
718                 setTimestamp(timestamp, isModified);
719                 ids=new JavaUpdater(pck, null, null).computeIndex(this, tokenIterator);
720                 classIndex.setIdentifiers(this,ids);
721                 if (!shouldParse) {
722                     setPersisted(false);
723                 }
724             }
725         } catch (IOException JavaDoc e) {
726             ErrorManager.getDefault().notify(e);
727         } finally {
728             disableChanges = changes;
729             try {
730                 if (reader != null) {
731                     reader.close();
732                 }
733             } catch (IOException JavaDoc e) {
734                 ErrorManager.getDefault().notify(e);
735             }
736         }
737         if (shouldParse) {
738             errors = null;
739             ResourceInfo resInfo=parser.enterMembers();
740
741             if (resInfo==null) { // syntax error
742
if (isInitialized()) {
743                     JMManager.fireResourceParsed(_getMofId());
744                     return;
745                 }
746                 Collection javaClasses=getPersistentClassifiers();
747                 ClassInfo classes[]=new ClassInfo[javaClasses.size()];
748                 int i=0;
749                 // the naked collection does not implement clear() method
750
// we need to iterate through it and remove elements one by one
751
for (Iterator it = javaClasses.iterator(); it.hasNext();) {
752                     JavaClassImpl jcls=(JavaClassImpl)it.next();
753                     int infoType=jcls.isInterface()?ClassInfo.INTERFACE_TYPE:ClassInfo.CLASS_TYPE;
754                     ClassInfo clsInfo=new ClassInfo(null, infoType, jcls.getName(), jcls.getModifiers(), null, null, null, null, null);
755
756                     classes[i++]=clsInfo;
757                 }
758                 resInfo=new ResourceInfo(null, ResourceInfo.RESOURCE_TYPE, this, classes, null);
759             }
760             updateMetadata(resInfo);
761             JMManager.fireResourceParsed(_getMofId());
762         }
763     }
764     
765     private void updateMetadata(ResourceInfo info) {
766         if (infoIdenticalTo(info)) return;
767         updatePersistent(info);
768         setElementInfo(info);
769     }
770     
771     void setFileToDeleteOnRollback(FileObject file){
772         this.fileToDeleteOnRollback = file;
773     }
774
775     public void rollbackChanges() {
776         if (fileToDeleteOnRollback != null) {
777             try {
778                 fileToDeleteOnRollback.delete();
779             } catch (IOException JavaDoc ioe) {
780                 ErrorManager.getDefault().notify(ioe);
781             }
782         }
783
784         rollback();
785
786         if (invertedDiffs != null) {
787             rollbackDiff();
788             invertedDiffs = null;
789             MDRParser parser = createMDRParser(null, true);
790             try {
791                 alreadyChecking = true;
792                 alreadyCheckingStackTrace = new RuntimeException JavaDoc();
793                 ResourceInfo resInfo=parser.enterMembers();
794                 uninitialize();
795                 updateMetadata(resInfo);
796             } finally {
797                 alreadyChecking = false;
798             }
799         }
800
801     }
802
803     protected void uninitialize() {
804         super.uninitialize();
805     }
806
807     public void commitChanges() {
808         errors = null;
809         fileToDeleteOnRollback = null;
810         if (!READ_ONLY) {
811             String JavaDoc newSourceText = null;
812             DiffList tmpdiff = new DiffList(getParser().isFromDocument());
813             if (isNew()) {
814                 newSourceText = getSourceText();
815             } else {
816                 getDiff(tmpdiff);
817                 if (isChanged(CHANGED_EXTERNAL)) {
818                     DiffList dl = new DiffList(getParser().isFromDocument());
819                     Iterator external = extDiffs.iterator();
820                     DiffElement extDiff = (DiffElement) external.next();
821                     for (Iterator it = tmpdiff.iterator(); it.hasNext();) {
822                         DiffElement de = (DiffElement) it.next();
823                         while (extDiff != null && extDiff.getStartOffset() < de.getStartOffset()) {
824                             dl.add(extDiff);
825                             extDiff = external.hasNext() ? (DiffElement) external.next() : null;
826                         }
827                         dl.add(de);
828                     }
829
830                     while (extDiff != null) {
831                         dl.add(extDiff);
832                         extDiff = external.hasNext() ? (DiffElement) external.next() : null;
833                     }
834                     
835                     tmpdiff = dl;
836                 }
837             }
838             extDiffs = null;
839             DataObject dobj = JavaMetamodel.getManager().getDataObject(this);
840             final CloneableEditorSupport editor = Util.findCloneableEditorSupport(dobj);
841             StyledDocument JavaDoc doc = null;
842             if (editor != null) {
843                 doc = editor.getDocument();
844                 if (doc == null && getParser().isFromDocument()) {
845                     try {
846                         doc = editor.openDocument();
847                     } catch (IOException JavaDoc ex) {
848                         throw (RuntimeException JavaDoc) ErrorManager.getDefault().annotate(new RuntimeException JavaDoc(), ex);
849                     }
850                 }
851             }
852             if (doc != null) {
853                 if (newSourceText == null) {
854                     final DiffList diff = tmpdiff;
855                     NbDocument.runAtomic(doc, new Runnable JavaDoc() {
856                         public void run() {
857                             applyDiff(diff, editor); // fail
858
}
859                     });
860                 } else {
861                     try {
862                         PositionRef start = editor.createPositionRef(0, Position.Bias.Forward);
863                         PositionRef end = editor.createPositionRef(doc.getLength(), Position.Bias.Backward);
864                         new PositionBounds(start, end).setText(newSourceText);
865                         setTimestamp(getTimestamp(), true);
866                     } catch (Exception JavaDoc e) {
867                         throw (RuntimeException JavaDoc) ErrorManager.getDefault().annotate(new RuntimeException JavaDoc(), e);
868                     }
869                 }
870             } else {
871                 if (newSourceText == null) {
872                     applyDiff(tmpdiff, dobj); // fail
873
} else {
874                     FileObject primaryFile = dobj.getPrimaryFile();
875                     OutputStream JavaDoc stream = null;
876                     FileLock lock = null;
877                     try {
878                         lock = primaryFile.lock();
879                         stream = primaryFile.getOutputStream(lock);
880                         stream.write(newSourceText.getBytes());
881                         stream.close();
882                         setTimestamp(primaryFile.lastModified().getTime(), false);
883                     }
884                     catch (IOException JavaDoc ex) {
885                         throw (RuntimeException JavaDoc) ErrorManager.getDefault().annotate(new RuntimeException JavaDoc(ex.toString()), ex);
886                     }
887                     finally {
888                         if (lock != null)
889                             lock.releaseLock();
890                     }
891                 }
892             }
893         }
894     }
895
896     /** Method called by ExclusiveMutex to confirm that the file is still parsable after commit.
897      */

898     public void parseResource() {
899         if (!READ_ONLY) {
900             FileObject fobj = getFileObject();
901             MDRParser parser = createMDRParser(fobj, true);
902             if (parser.getASTree() == null) {
903                 throw new ConstraintViolationException(null, this, "Cannot parse resource " + getName()); // NOI18N
904
}
905             commit();
906             try {
907                 resetAST(parser);
908             } catch (Exception JavaDoc e) {
909                 ErrorManager.getDefault().notify(e);
910             }
911         }
912     }
913     
914     public void commitConfirmed() {
915         JavaMetamodel.getUndoManager().addItem(this, invertedDiffs);
916         invertedDiffs = null;
917         rbText = null;
918         rbList = null;
919         JMManager.fireResourceParsed(_getMofId());
920     }
921
922     public void applyDiff(DiffList diff) {
923         DataObject dobj = JavaMetamodel.getManager().getDataObject(this);
924         final CloneableEditorSupport editor = Util.findCloneableEditorSupport(dobj);
925         if (diff.isFromDocument()) {
926             if (editor!=null) {
927                 StyledDocument JavaDoc doc = null;
928                 try {
929                     doc = editor.openDocument();
930                 } catch (IOException JavaDoc ex) {
931                     ErrorManager.getDefault().notify(ex);
932                 }
933                 assert doc !=null : this.getName();
934                 final DiffList diffList = diff;
935                 NbDocument.runAtomic(doc, new Runnable JavaDoc() {
936                     public void run() {
937                         applyDiff(diffList, editor);
938                     }
939                 });
940             }
941         } else {
942             if (editor!=null) {
943                 StyledDocument JavaDoc doc = editor.getDocument();
944                 if (doc!=null) {
945                     final DiffList diffList = diff;
946                     NbDocument.runAtomic(doc, new Runnable JavaDoc() {
947                         public void run() {
948                             applyDiff(diffList, editor);
949                         }
950                     });
951                 } else {
952                     applyDiff(diff, dobj);
953                 }
954             }
955         }
956         JavaMetamodel.getUndoManager().addItem(this, invertedDiffs);
957     }
958
959     private void applyDiff(DiffList diffList, CloneableEditorSupport doc) {
960         List diff = new ArrayList(diffList);
961         DiffList tempDiffs = null;
962         List list = new ArrayList(diff.size());
963         try {
964             HashMap positions = new HashMap(diff.size());
965             int[] offsets = new int[diff.size() * 2];
966             int i = 0;
967             MDRParser parser = getParser();
968
969             for (ListIterator it = diff.listIterator(); it.hasNext();) {
970                 DiffElement de = (DiffElement) it.next();
971                 if (de.getText().startsWith("\n")) {
972                     int increment = 0;
973                     String JavaDoc sourceText = parser.getSourceText();
974                     int startOffset = de.getStartOffset();
975                     if (sourceText.length() > startOffset) {
976                         char ch = sourceText.charAt(startOffset);
977                         if (ch == '\n') {
978                             increment = 1;
979                         } else if (ch == '\r') {
980                             if (sourceText.substring(startOffset).startsWith("\r\n")) {
981                                 increment = 2;
982                             }
983                         }
984
985                         if (increment > 0) {
986                             int so = startOffset + increment, eo = de.getEndOffset();
987                             String JavaDoc text = de.getText().substring(1);
988                             if (so > eo) {
989                                 eo = so;
990                                 text += '\n';
991                             }
992                             de = new DiffElement(so, eo, text);
993                             it.set(de);
994                         }
995                     }
996                 }
997                 offsets[i++] = de.getStartOffset();
998                 offsets[i++] = de.getEndOffset();
999             }
1000
1001            if (parser != null && offsets.length > 0 && !diffList.isFromDocument()) {
1002                offsets = parser.convertToDocumentOffsets(offsets);
1003            }
1004            
1005            for (i = 0; i < diff.size(); i++) {
1006                PositionRef start = doc.createPositionRef(offsets[i * 2], Position.Bias.Forward);
1007                PositionRef end = doc.createPositionRef(offsets[i * 2 + 1], Position.Bias.Backward);
1008                positions.put(diff.get(i), new PositionBounds(start, end));
1009            }
1010
1011            tempDiffs = new DiffList(true);
1012            for (Iterator it = diff.iterator(); it.hasNext();) {
1013                DiffElement de = (DiffElement) it.next();
1014                PositionBounds pos = (PositionBounds) positions.get(de);
1015                int startOffset = pos.getBegin().getOffset();
1016                DiffElement diffElement = new DiffElement(startOffset, startOffset+de.getText().length(), pos.getText());
1017                String JavaDoc text = pos.getText();
1018                pos.setText(de.getText());
1019                list.add (new PosInfo(text, pos));
1020                tempDiffs.add(diffElement);
1021            }
1022        } catch (Exception JavaDoc e) {
1023            throw (ConstraintViolationException) ErrorManager.getDefault().annotate(
1024                new ConstraintViolationException(null, this, "Exception thrown when applying diff: " + e.getMessage()), e // NOI18N
1025
);
1026        }
1027        invertedDiffs = tempDiffs;
1028        rbList = list;
1029        // force timestamp change events (#56380)
1030
setTimestamp(getTimestamp(), true);
1031    }
1032
1033    private void applyDiff(DiffList diff, DataObject dobj) {
1034        MDRParser parser = getParser();
1035        String JavaDoc orig = parser.getSourceText();
1036        int lastPrinted = 0;
1037        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1038
1039        invertedDiffs = null;
1040        DiffList tempDiffs = new DiffList(false);
1041        int shift = 0;
1042        int shiftedOffset = 0;
1043
1044        for (Iterator it = diff.iterator(); it.hasNext();) {
1045            DiffElement de = (DiffElement) it.next();
1046            int startOffset = de.getStartOffset();
1047            int endOffset = de.getEndOffset();
1048            buf.append(orig.substring(lastPrinted, startOffset));
1049            String JavaDoc d = lineSepPattern.matcher(de.getText()).replaceAll(lineSeparator);
1050            buf.append(d);
1051            lastPrinted = endOffset;
1052            shiftedOffset = startOffset + shift;
1053            tempDiffs.add(new DiffElement(shiftedOffset, shiftedOffset + d.length(), orig.substring(startOffset, endOffset)));
1054            shift += startOffset + d.length() - endOffset;
1055        }
1056
1057        buf.append(orig.substring(lastPrinted));
1058        FileObject primaryFile = dobj.getPrimaryFile();
1059        OutputStream JavaDoc stream = null;
1060        FileLock lock = null;
1061        try {
1062            lock = primaryFile.lock();
1063            stream = primaryFile.getOutputStream(lock);
1064            String JavaDoc encoding = Util.getFileEncoding(primaryFile);
1065            if (encoding == null) {
1066                stream.write(buf.toString().getBytes());
1067            } else {
1068                stream.write(buf.toString().getBytes(encoding));
1069            }
1070            stream.close();
1071
1072            invertedDiffs = tempDiffs;
1073            rbText = orig;
1074            setTimestamp(primaryFile.lastModified().getTime(), false);
1075        }
1076        catch (IOException JavaDoc ex) {
1077            ex.printStackTrace();
1078            throw (ConstraintViolationException) ErrorManager.getDefault().annotate(
1079                new ConstraintViolationException(null, this, "Exception thrown when applying diff: " + ex.getMessage()), ex // NOI18N
1080
);
1081        }
1082        finally {
1083            if (lock != null)
1084                lock.releaseLock();
1085        }
1086    }
1087
1088    private void rollbackDiff() {
1089        DataObject dobj = JavaMetamodel.getManager().getDataObject(this);
1090        if (rbList != null) {
1091            final CloneableEditorSupport editor = Util.findCloneableEditorSupport(dobj);
1092            StyledDocument JavaDoc doc = editor.getDocument();
1093            final List list = rbList;
1094            rbList = null;
1095            NbDocument.runAtomic(doc, new Runnable JavaDoc() {
1096                public void run() {
1097                    for (Iterator iter = list.iterator(); iter.hasNext();) {
1098                        PosInfo info = (PosInfo) iter.next();
1099                        try {
1100                            info.pos.setText(info.text);
1101                        } catch (Exception JavaDoc ex) {
1102                            ErrorManager.getDefault().notify(ex);
1103                        }
1104                    }
1105                }
1106            });
1107            setTimestamp(getTimestamp(), true);
1108        } else {
1109            FileObject primaryFile = dobj.getPrimaryFile();
1110            OutputStream JavaDoc stream = null;
1111            FileLock lock = null;
1112            try {
1113                lock = primaryFile.lock();
1114                stream = primaryFile.getOutputStream(lock);
1115                stream.write(rbText.getBytes());
1116                stream.close();
1117                setTimestamp(primaryFile.lastModified().getTime(), false);
1118            }
1119            catch (IOException JavaDoc ex) {
1120                ErrorManager.getDefault().notify(ex);
1121            }
1122            finally {
1123                if (lock != null)
1124                    lock.releaseLock();
1125                rbText = null;
1126            }
1127        }
1128    }
1129    
1130    public void getDiff(List diff) {
1131        ResourceInfo astInfo = (ResourceInfo) getElementInfo();
1132        ASTProvider parser = getParser();
1133
1134        // package statement
1135
ASTree tree = getASTree();
1136        String JavaDoc packageName = getPackageName();
1137        int endOffsetAfterRemovePackage = -1;
1138        if (isChanged(CHANGED_PACKAGE_NAME) && tree.getSubTrees()[0] == null) {
1139            if (packageName != null && packageName.length() > 0) {
1140                diff.add(new DiffElement(0, 0, "package " + getPackageName() + ";\n")); // NOI18N
1141
}
1142        } else if (isChanged(CHANGED_PACKAGE_NAME) && (packageName == null || packageName.length() == 0)) {
1143            // remove package statement if the resource is located in default
1144
// package
1145
int startPads = getStartOffset(parser, tree.getSubTrees()[0], false);
1146            // assume there is only package statement with no new line after.
1147
// (value will be rewritten if it is not true)
1148
int endOff = getEndOffset(parser, tree.getSubTrees()[0]);
1149            ASTree[] rscChildren = tree.getSubTrees();
1150            Token newLine = null;
1151            // find the first new line after package statement, if there exists
1152
if (rscChildren[1] != null) {
1153                // there is at least one import
1154
newLine = getFirstEOL(parser, rscChildren[1].getFirstToken());
1155            } else if (rscChildren[2] != null) {
1156                // there is no import, but at least one classifier
1157
newLine = getFirstEOL(parser, rscChildren[2].getFirstToken());
1158            }
1159            if (newLine != null) {
1160                // we knows about first new line after the package statement,
1161
// We will update the end offset character.
1162
endOff = newLine.getEndOffset();
1163            }
1164            diff.add(new DiffElement(startPads, endOff, ""));
1165            endOffsetAfterRemovePackage = endOff;
1166        } else if (tree.getSubTrees()[0] != null) {
1167            getChildDiff(diff, parser, tree.getSubTrees()[0].getSubTrees()[1], (MetadataElement) getPackageIdentifier(), CHANGED_PACKAGE_NAME);
1168        }
1169
1170        // import statements
1171
int endOffset;
1172        int endOffset2 = -1;
1173        ASTree typeDecls = tree.getSubTrees()[2];
1174        if (typeDecls == null) {
1175            endOffset = parser.getSourceText().length();
1176        } else {
1177            if (isChanged(CHANGED_IMPORTS)) {
1178                // find the end of import section.
1179
if (tree.getSubTrees()[0] == null && tree.getSubTrees()[1] == null) {
1180                    // there is not any package or import statement, the
1181
// compilation unit starts with 'class Anything...'.
1182
// start at the beginning of file.
1183
endOffset = 0;
1184                } else if (tree.getSubTrees()[1] == null) {
1185                    if (packageName==null || "".equals(packageName)) {
1186                        endOffset = endOffsetAfterRemovePackage;
1187                    } else {
1188                        // there is package statement but no import
1189
int firstAfterPckg = tree.getSubTrees()[0].getLastToken()+1;
1190                        Token t1 = parser.getToken(firstAfterPckg);
1191                        Token[] pads = t1.getPadding();
1192                        endOffset = getStartOffset(parser, typeDecls, true);
1193                        // look for first EOL token and set the endOffset var.
1194
for (int i = 0; i < pads.length; i++) {
1195                            if (pads[i].getType() == ParserTokens.EOL) {
1196                                endOffset = pads[i].getStartOffset();
1197                                break;
1198                            }
1199                        }
1200                        diff.add(new DiffElement(endOffset, endOffset, "\n\n")); // NOI18N
1201
}
1202                } else {
1203                    // there are imports already.
1204
int lastImp = tree.getSubTrees()[1].getLastToken();
1205                    Token t1 = parser.getToken(lastImp+1);
1206                    Token[] pads = t1.getPadding();
1207                    endOffset = parser.getToken(lastImp).getEndOffset();
1208                    // look for first EOL token and set the endOffset var.
1209
for (int i = 0; i < pads.length; i++) {
1210                        if (pads[i].getType() == ParserTokens.EOL) {
1211                            endOffset = pads[i].getStartOffset();
1212                            if (getImports().isEmpty()) {
1213                                endOffset2 = pads[i].getEndOffset();
1214                            } else {
1215                                int inPos = parser.getText(pads[i]).lastIndexOf('\n');
1216                                endOffset2 = inPos != -1 ? endOffset + inPos : endOffset;
1217                            }
1218                            break;
1219                        }
1220                    }
1221                }
1222            } else {
1223                endOffset = getStartOffset(parser, typeDecls, true);
1224            }
1225        }
1226        int diff_size = diff.size();
1227        
1228        getImportsDiff(diff, parser, astInfo.imports, getImports(), endOffset, endOffset2, "\n", false, CHANGED_IMPORTS); // NOI18N
1229

1230        // there was neither package nor import statement in source, put
1231
// new line after new imports when imports where changed.
1232
if (isChanged(CHANGED_IMPORTS) && tree.getSubTrees()[0] == null && tree.getSubTrees()[1] == null || endOffset == endOffsetAfterRemovePackage) {
1233            diff.add(new DiffElement(endOffset, endOffset, "\n")); // NOI18N
1234
}
1235
1236        // classes
1237
endOffset = parser.getSourceText().length();
1238        getCollectionDiff(diff, parser, CHANGED_CLASSIFIERS, astInfo.classes, getClassifiers(), endOffset, "\n\n"); // NOI18N
1239
}
1240
1241    public String JavaDoc getSourceText() {
1242        String JavaDoc origElem;
1243        if ((origElem = checkChange()) != null) {
1244            return origElem;
1245        }
1246        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1247
1248        String JavaDoc packageName = getPackageName();
1249        
1250        if (packageName != null && packageName.length() > 0) {
1251            buf.append("package "); // NOI18N
1252
buf.append(getPackageName());
1253            buf.append(";\n\n"); // NOI18N
1254
}
1255        
1256        for (Iterator importsIt = getImports().iterator(); importsIt.hasNext(); ) {
1257            ImportImpl imp = (ImportImpl) importsIt.next();
1258            buf.append(imp.getSourceText() + "\n"); // NOI18N
1259
}
1260        for (Iterator clazzIt = getClassifiers().iterator(); clazzIt.hasNext(); ) {
1261            JavaClassImpl javaClass = (JavaClassImpl) clazzIt.next();
1262            buf.append('\n' + javaClass.getSourceText() + '\n');
1263        }
1264        return buf.toString();
1265    }
1266
1267    /**
1268     * Overrides default implementation from SemiPersistentElement.
1269     * It guarantees interruption of the getIndentation() calls' chain for
1270     * newly created elements.
1271     * See example below.
1272     *
1273     * Example:
1274     * Consider situation, when you have created new Resource 'Foo.java'.
1275     * You have created JavaClass 'public class Foo' and put it to the
1276     * Resource. In addition to, you have created Field 'int count;'. Now
1277     * when generator starts, it goes through the elements and generates them.
1278     * When getSourceText() method in Field is called, it asks for the
1279     * indentation. Default implementation in SemiPersistentElement.getIndentation()
1280     * asks for indentation of its parent, which is JavaClass. It calls the
1281     * same default implementation, which asks for the parents (in this case Resource)
1282     * implementation. It is empty string, so it stops the getIndentation()
1283     * calls' chain.
1284     *
1285     * @return empty string, see comment above.
1286     */

1287    protected String JavaDoc getIndentation() {
1288        return "";
1289    }
1290
1291    // ..........................................................................
1292

1293    protected void _delete() {
1294        // --- delete from package -----------------------------------------
1295
JavaPackage parent = (JavaPackage) _realImmediateComposite();
1296        if (parent != null) {
1297            parent.getResources().remove(this);
1298        }
1299        // --- delete components -------------------------------------------
1300
// delete all classifiers
1301
for (Iterator it = getPersistentClassifiers().iterator(); it.hasNext();) {
1302            RefObject classifier = (RefObject) it.next();
1303            it.remove();
1304            classifier.refDelete();
1305        }
1306        if (childrenInited) {
1307            deleteChildren(imports);
1308            if (elementsInited)
1309                deleteChild(packageIdentifier);
1310        }
1311        // --- delete from indexes ----------------------------------------
1312
ClassIndex.getIndex((JavaModelPackage) refOutermostPackage()).removeResource(this);
1313        ((ExclusiveMutex) _getMdrStorage().getRepositoryMutex()).unregisterChange(this);
1314
1315        super._delete();
1316    }
1317
1318    public void replaceChild(Element oldElement, Element newElement) {
1319        if (replaceObject(classifiersInited() ? getClassifiers() : getPersistentClassifiers(), oldElement, newElement)) return;
1320        
1321        if (childrenInited) {
1322            if (replaceObject(getImports(), oldElement, newElement)) return;
1323        }
1324        if (elementsInited && oldElement.equals(packageIdentifier)) {
1325            if (newElement != null) { // [PENDING] null value causes that a composite (package) is set
1326
setPackageIdentifier((MultipartId) newElement);
1327            } // [PENDING]
1328
return;
1329        }
1330        super.replaceChild(oldElement, newElement);
1331    }
1332
1333    // ..........................................................................
1334
// a hack allowing the bridge to be informed about imports initialization
1335
// ..........................................................................
1336

1337    // [TODO] synchronization
1338

1339    private PropertyChangeSupport JavaDoc importsSupp;
1340
1341    public boolean importsInited () {
1342        return childrenInited;
1343    }
1344
1345    public void addImportsListener (PropertyChangeListener JavaDoc listener) {
1346        if (childrenInited) {
1347            listener.propertyChange (null);
1348        } else {
1349            synchronized (this) {
1350                if (importsSupp == null) {
1351                    importsSupp = new PropertyChangeSupport JavaDoc (this);
1352                }
1353            }
1354            importsSupp.addPropertyChangeListener(listener);
1355        }
1356    }
1357
1358    private void fireImportsInited () {
1359        if (importsSupp != null)
1360            importsSupp.firePropertyChange (null, null, null);
1361        importsSupp = null;
1362    }
1363
1364    // end of the hack ..........................................................
1365

1366    protected ASTree getPartTree(ElementPartKind part) {
1367        if (ElementPartKindEnum.HEADER.equals(part))
1368            return getASTree().getSubTrees()[0];
1369        throw new IllegalArgumentException JavaDoc("Invalid part for this element: " + part); // NOI18N
1370
}
1371
1372    public MultipartId getPackageIdentifier() {
1373        checkUpToDate();
1374        if (!elementsInited) {
1375            initASTElements();
1376        }
1377        return packageIdentifier;
1378    }
1379
1380    public void setPackageIdentifier(MultipartId packageIdentifier) {
1381        objectChanged(CHANGED_PACKAGE_NAME);
1382        changeChild(getPackageIdentifier(), packageIdentifier);
1383        this.packageIdentifier = packageIdentifier;
1384// doSetPackageIdentifier(packageIdentifier);
1385
setPkgNameAndUpdateIdx(packageIdentifier != null ?
1386            ((MetadataElement) packageIdentifier).getSourceText() : "");
1387    }
1388
1389// private void doSetPackageIdentifier(MultipartId packageIdentifier) {
1390
// objectChanged(CHANGED_PACKAGE_NAME);
1391
// changeChild(getPackageIdentifier(), packageIdentifier);
1392
// this.packageIdentifier = packageIdentifier;
1393
// }
1394

1395    void childChanged(MetadataElement element) {
1396        if (element == getPackageIdentifier()) {
1397            setPkgNameAndUpdateIdx(((MetadataElement) packageIdentifier).getSourceText());
1398        }
1399    }
1400
1401    public boolean containsIdentifier(String JavaDoc identifier) {
1402        return ClassIndex.containsIdentifier(this, identifier.hashCode());
1403    }
1404
1405    /**
1406     * Tries to find first EOL in paddings of provided token. If there are not
1407     * any padding connected to token or there is not any EOL token in its
1408     * paddings, returns null. Otherwise returns EOL token.
1409     *
1410     * @param parser parser which is used for obtaining token by token id
1411     * @param token token id
1412     * @return token representing first EOL token of parameters paddings
1413     * or null if EOL token is not present
1414     */

1415    private static Token getFirstEOL(ASTProvider parser, int token) {
1416        Token[] pads = parser.getToken(token).getPadding();
1417        for (int i = 0; i < pads.length; i++) {
1418            if (pads[i].getType() == ParserTokens.EOL) {
1419                return pads[i];
1420            }
1421        }
1422        return null;
1423    }
1424    
1425    // ..........................................................................
1426

1427    private static class PosInfo {
1428        String JavaDoc text;
1429        PositionBounds pos;
1430        
1431        PosInfo(String JavaDoc text, PositionBounds pos) {
1432            this.text = text;
1433            this.pos = pos;
1434        }
1435    }
1436
1437    private class ErrorList extends AbstractList implements ErrConsumer {
1438        private List errors = null;
1439        private String JavaDoc name;
1440        
1441        public ErrorList() {
1442            name = getName().replace('/', File.separatorChar);
1443        }
1444
1445        public Object JavaDoc get(int index) {
1446            initCheck();
1447            return errors.get(index);
1448        }
1449
1450        private void initCheck() {
1451            synchronized (this) {
1452                if (errors != null) {
1453                    return;
1454                }
1455            }
1456            MDRParser provider;
1457            _getRepository().beginTrans(false);
1458            try {
1459                provider = getParser();
1460            } finally {
1461                _getRepository().endTrans();
1462            }
1463            synchronized (this) {
1464                if (errors == null && provider != null) {
1465                    try {
1466                        ECRequestDesc desc = new ECRequestDescImpl(name, provider, this);
1467                        Factory.getDefault().getErrorChecker(desc).parse();
1468                    } catch (CompilerException ex) {
1469                        ErrorManager.getDefault().log(ErrorManager.WARNING, "ErrorChecker: " + ex.getMessage()); // NOI18N
1470
}
1471                }
1472                if (errors == null) {
1473                    errors = Collections.EMPTY_LIST;
1474                }
1475            }
1476        }
1477
1478        public int size() {
1479            initCheck();
1480            return errors.size();
1481        }
1482
1483        public void pushError(Object JavaDoc severity, String JavaDoc errorFileName, int line, int column, String JavaDoc message, String JavaDoc key, String JavaDoc[] args) {
1484            if (errorFileName.equals(name)) {
1485                if (errors == null) {
1486                    errors = new ArrayList();
1487                }
1488                errors.add(new ErrorInfoImpl(severity, line, column, message, key, args));
1489            }
1490        }
1491    }
1492
1493    private static class ErrorInfoImpl implements ErrorInfo {
1494        private final String JavaDoc description;
1495        private final int line, column;
1496        private final ErrorType severity;
1497        private final String JavaDoc errorId;
1498        private final String JavaDoc[] args;
1499
1500        private static List fieldNames = Arrays.asList((Object JavaDoc[]) new String JavaDoc[] {"description", "lineNumber", "column", "severity"}); // NOI18N
1501
private static List typeName = Arrays.asList((Object JavaDoc[]) new String JavaDoc[] {"JavaModel", "ErrorInfo"}); // NOI18N
1502

1503        ErrorInfoImpl(Object JavaDoc severity, int line, int column, String JavaDoc message, String JavaDoc key, String JavaDoc[] args) {
1504            this.description = message;
1505            this.line = line;
1506            this.column = column;
1507            this.errorId = key;
1508            this.args = args;
1509            this.severity = severity == ErrConsumer.WARNING ? ErrorTypeEnum.WARNING : ErrorTypeEnum.ERROR;
1510        }
1511
1512        public String JavaDoc getDescription() {
1513            return description;
1514        }
1515
1516        public int getLineNumber() {
1517            return line;
1518        }
1519
1520        public int getColumn() {
1521            return column;
1522        }
1523
1524        public ErrorType getSeverity() {
1525            return severity;
1526        }
1527
1528        public List refFieldNames() {
1529            return fieldNames;
1530        }
1531
1532        public String JavaDoc getErrorId() {
1533            return errorId;
1534        }
1535
1536        public List getArguments() {
1537            return Arrays.asList(args);
1538        }
1539        
1540        public Object JavaDoc refGetValue(String JavaDoc s) {
1541            if ("description".equals(s)) { // NOI18N
1542
return getDescription();
1543            } else if ("lineNumber".equals(s)) { // NOI18N
1544
return new Integer JavaDoc(getLineNumber());
1545            } else if ("column".equals(s)) { // NOI18N
1546
return new Integer JavaDoc(getColumn());
1547            } else if ("severity".equals(s)) { // NOI18N
1548
return getSeverity();
1549            } else if ("errorId".equals(s)) { // NOI18N
1550
return getErrorId();
1551            } else if ("arguments".equals(s)) { // NOI18N
1552
return getArguments();
1553            } else {
1554                throw new InvalidNameException(s);
1555            }
1556        }
1557
1558        public List refTypeName() {
1559            return typeName;
1560        }
1561    }
1562    
1563    public static class DiffList extends AbstractList {
1564        private final ArrayList delegate = new ArrayList();
1565        private boolean fromDocument;
1566        
1567        public DiffList(boolean isFromDocument) {
1568            fromDocument = isFromDocument;
1569            
1570        }
1571        
1572        public int size() {
1573            return delegate.size();
1574        }
1575        
1576        public boolean isFromDocument() {
1577            return fromDocument;
1578        }
1579        
1580        public Object JavaDoc get(int index) {
1581            return delegate.get(index);
1582        }
1583
1584        public void add(int index, Object JavaDoc object) {
1585            DiffElement element = (DiffElement) object;
1586            if (index == delegate.size()) {
1587                add(object);
1588                return;
1589            }
1590            DiffElement diff = (DiffElement) delegate.get(index);
1591            if (element.getEndOffset() > diff.getStartOffset()) {
1592                throw new IllegalArgumentException JavaDoc("Start offset of the diff element is lower than end offset of the previous diff element. (previous: " + diff + ", this: " + element + ")"); // NOI18N
1593
} else if (element.getEndOffset() == diff.getStartOffset()) {
1594                delegate.remove(index);
1595                element = new DiffElement(element.getStartOffset(), diff.getEndOffset(), element.getText() + diff.getText());
1596            }
1597            if (index > 0) {
1598                diff = (DiffElement) delegate.get(index - 1);
1599                if (diff.getEndOffset() > element.getStartOffset()) {
1600                    throw new IllegalArgumentException JavaDoc("Start offset of the diff element is lower than end offset of the previous diff element. (previous: " + diff + ", this: " + element + ")"); // NOI18N
1601
} else if (diff.getEndOffset() == element.getStartOffset()) {
1602                    delegate.set(index - 1, new DiffElement(diff.getStartOffset(), element.getEndOffset(), diff.getText() + element.getText()));
1603                    return;
1604                }
1605            }
1606            delegate.add(index, element);
1607        }
1608        
1609        public Object JavaDoc remove(int index) {
1610            return delegate.remove(index);
1611        }
1612        
1613        public Object JavaDoc set(int index, Object JavaDoc object) {
1614            Object JavaDoc result = remove(index);
1615            add(index, object);
1616            return result;
1617        }
1618
1619        public boolean add(Object JavaDoc object) {
1620            DiffElement element = (DiffElement) object;
1621            if (!delegate.isEmpty()) {
1622                int lastIndex = delegate.size() - 1;
1623                DiffElement diff = (DiffElement) delegate.get(lastIndex);
1624                if (diff.getEndOffset() > element.getStartOffset()) {
1625                    throw new IllegalArgumentException JavaDoc("Start offset of the diff element is lower than end offset of the previous diff element. (previous: " + diff + ", this: " + element); // NOI18N
1626
} else if (diff.getEndOffset() == element.getStartOffset()) {
1627                    delegate.set(lastIndex, new DiffElement(diff.getStartOffset(), element.getEndOffset(), diff.getText() + element.getText()));
1628                    return true;
1629                }
1630            }
1631            return delegate.add(element);
1632        }
1633    }
1634
1635    protected void hardRefParent(boolean enabled) {
1636    }
1637
1638    protected void parentChanged() {
1639    }
1640    
1641    public Element duplicate(JavaModelPackage targetExtent) {
1642        throw new UnsupportedOperationException JavaDoc("The operation is intentionally unsupported at this element."); // NOI18N
1643
}
1644    
1645    /** Returns true if a given offset points into a comment in a source file.
1646     */

1647    public boolean isComment(int offset) {
1648        MDRParser parser = getParser();
1649        Token token = parser.getTokenByOffset(offset);
1650        if (token == null) return false;
1651        return token.getType() == ParserTokens.COMMENT || token.getType() == ParserTokens.EOL_COMMENT;
1652    }
1653    
1654    public void addExtDiff(DiffElement diff) {
1655        objectChanged(CHANGED_EXTERNAL);
1656        if (extDiffs == null) {
1657            extDiffs = new DiffList(getParser().isFromDocument());
1658        }
1659        extDiffs.add(diff);
1660    }
1661    
1662    public Element getElementByOffset(int offset) {
1663        _lock(false);
1664        try {
1665            ElementFinder finder = new ElementFinder(this);
1666
1667            return finder.getElementByOffset(offset);
1668        } finally {
1669            _unlock();
1670        }
1671    }
1672
1673    public boolean addImport(Import newImport) {
1674        boolean fail = true;
1675        _lock(true);
1676        try {
1677            String JavaDoc name=newImport.getName();
1678            ListIterator it = getImports().listIterator();
1679
1680            while (it.hasNext()) {
1681                Import imp =(Import)it.next();
1682                String JavaDoc impName=imp.getName();
1683                
1684                if (impName!=null && name.compareTo(impName)<0) {
1685                    it.previous();
1686                    break;
1687                }
1688            }
1689            it.add(newImport);
1690            fail = false;
1691            return true;
1692        } finally {
1693            _unlock(fail);
1694        }
1695    }
1696
1697    public List getMain() {
1698        _lock(false);
1699        try {
1700            if (getName().endsWith(".class") || containsIdentifier("main")) { //NOI18N
1701
List mainClasses=new ArrayList(1);
1702                for (Iterator i = getClassifiers().iterator(); i.hasNext();) {
1703                    findMainIn((JavaClass) i.next(), mainClasses);
1704                }
1705                return mainClasses;
1706            }
1707            return Collections.EMPTY_LIST;
1708        } finally {
1709            _unlock();
1710        }
1711    }
1712
1713    private void findMainIn(final JavaClass clazz, final Collection mainClasses) {
1714        if (clazz.isInterface())
1715            return;
1716        final int correctMods = (Modifier.PUBLIC | Modifier.STATIC);
1717        Object JavaDoc[] features = clazz.getContents().toArray();
1718        boolean mainFound = false;
1719        
1720        for (int j = 0; j<features.length;j++) {
1721            ClassMember feature = (ClassMember)features[j];
1722            
1723            if (feature instanceof JavaClass)
1724                findMainIn((JavaClass)feature, mainClasses);
1725            if (mainFound)
1726                continue;
1727            // if it is not a method, continue with next feature
1728
if (!(feature instanceof Method))
1729                continue;
1730
1731            Method m = (Method) feature;
1732            // check that method is named 'main' and has set public
1733
// and static modifiers! Method has to also return
1734
// void type.
1735
if (!"main".equals(m.getName()) || // NOI18N
1736
((m.getModifiers() & correctMods) != correctMods) ||
1737               (!"void".equals(m.getType().getName()))) // NOI18N
1738
continue;
1739
1740            // check parameters - it has to be one of type String[]
1741
// or String...
1742
Iterator parIt=m.getParameters().iterator();
1743            if (parIt.hasNext()) {
1744                Parameter par = (Parameter) parIt.next();
1745                if (parIt.hasNext()) // more than one parameter
1746
continue;
1747                String JavaDoc typeName = par.getType().getName();
1748                if (par.isVarArg() && ("java.lang.String".equals(typeName) || "String".equals(typeName))) { // NOI18N
1749
// Main methods written with variable arguments parameter:
1750
// public static main(String... args) {
1751
// }
1752
mainClasses.add(clazz);
1753                    mainFound = true;
1754                } else if ("java.lang.String[]".equals(typeName) || "String[]".equals(typeName)) { // NOI18N
1755
// Main method written with array parameter:
1756
// public static main(String[] args) {
1757
// }
1758
mainClasses.add(clazz);
1759                    mainFound = true;
1760                }
1761            } // end if parameters
1762
} // end features cycle
1763
}
1764
1765    void setData() {
1766        imports = createChildrenList("imports",Collections.EMPTY_LIST, CHANGED_IMPORTS); // NOI18N
1767
}
1768}
1769
Popular Tags