KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > ExclusiveMutex


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;
21 import java.util.ArrayList JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import org.netbeans.jmi.javamodel.Element;
24 import org.netbeans.jmi.javamodel.JavaModelPackage;
25 import org.netbeans.jmi.javamodel.Resource;
26 import org.netbeans.mdr.util.TransactionMutex;
27 import org.netbeans.modules.javacore.api.JavaModel;
28 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceClassImpl;
29 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceImpl;
30 import org.netbeans.modules.javacore.jmiimpl.javamodel.SemiPersistentElement;
31 import org.openide.ErrorManager;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Set JavaDoc;
37 import org.netbeans.mdr.NBMDRepositoryImpl;
38 import org.netbeans.mdr.persistence.MOFID;
39 import org.netbeans.modules.javacore.jmiimpl.javamodel.BehavioralFeatureImpl;
40 import org.netbeans.modules.javacore.jmiimpl.javamodel.EnumConstantImpl;
41 import org.netbeans.modules.javacore.jmiimpl.javamodel.FieldImpl;
42 import org.netbeans.modules.javacore.internalapi.ExternalChange;
43 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
44 import org.netbeans.modules.javacore.classpath.FilterClassPathImplementation;
45 import org.netbeans.api.java.classpath.ClassPath;
46 import org.openide.filesystems.FileObject;
47 import javax.swing.SwingUtilities JavaDoc;
48 import org.netbeans.modules.javacore.jmiimpl.javamodel.AttributeImpl;
49 import org.netbeans.modules.javacore.jmiimpl.javamodel.AttributeValueImpl;
50
51 /**
52  *
53  * @author Martin Matula
54  */

55 public class ExclusiveMutex extends TransactionMutex {
56     private static final boolean DEBUG = false;
57     
58     private boolean changes = false;
59     private boolean fail = false;
60     private Thread JavaDoc thread = null;
61     private int counter = 0;
62     private int modCount = 1;
63     private boolean isSafeTrans = false;
64
65     private Set JavaDoc newObjects = new HashSet JavaDoc();
66
67     // set of changed resources
68
private Set JavaDoc changedRscSet = new HashSet JavaDoc();
69     private Set JavaDoc changedExternalSet = new HashSet JavaDoc();
70     private Set JavaDoc undoElementsSet = new HashSet JavaDoc();
71     
72     private Set JavaDoc upToDateElements = new HashSet JavaDoc();
73     private Set JavaDoc invalidClasses = new HashSet JavaDoc();
74
75     // list of BehavioralElements, which has to be reinitialized after commit
76
private List JavaDoc initBodyQueue;
77     
78     // cache used by MDRParser for scopes
79
private Map JavaDoc parserCache;
80
81     private Set JavaDoc needParsing = new HashSet JavaDoc();
82     private Set JavaDoc needDelete = new HashSet JavaDoc();
83     private Set JavaDoc needParsingRW = new HashSet JavaDoc();
84     private Set JavaDoc needTSUpdate = new HashSet JavaDoc();
85     private Set JavaDoc priorityThreads = null;
86
87     private ClassPath classPath = null;
88     private List JavaDoc/*ClassPath*/ searchScope = null;
89     private volatile boolean isSwingWaiting = false;
90     private JMManager manager = (JMManager) JMManager.getManager();
91
92     private boolean modificationsDisabled = false;
93
94     /** Creates a new instance of ExclusiveMutex */
95     public ExclusiveMutex(Object JavaDoc p1, Object JavaDoc p2, Object JavaDoc p3) {
96         super(p1, p2, p3);
97     }
98
99     // can be called only from within a transaction
100
public boolean isSwingWaiting() {
101         return isSwingWaiting;
102     }
103     
104     public int getModCount() {
105         return modCount;
106     }
107     
108     public boolean isSafeTrans() {
109         return isSafeTrans;
110     }
111     
112     void setSafeTrans(boolean safeTrans) {
113         this.isSafeTrans = safeTrans;
114     }
115     
116     public synchronized void addPriorityThread() {
117         if (priorityThreads == null) {
118             priorityThreads = new HashSet JavaDoc();
119         }
120         priorityThreads.add(Thread.currentThread());
121     }
122     
123     public synchronized void enter(boolean writeAccess) {
124         Thread JavaDoc thread = Thread.currentThread();
125
126         // make sure no document is locked upon starting a new transaction
127
assert (counter > 0 && this.thread == thread) || JMManager.getDocumentLocksCounter() == null || JMManager.getDocumentLocksCounter().get() == null : "Document was locked before starting the MDR transaction."; // NOI18N
128

129         if (this.thread != thread) {
130             if (SwingUtilities.isEventDispatchThread()) addPriorityThread();
131             boolean isPriorityThread = priorityThreads != null && priorityThreads.remove(thread);
132             while (!(counter == 0 && (!isSwingWaiting || isPriorityThread))) {
133                 try {
134                     isSwingWaiting |= isPriorityThread;
135     // if (isPriorityThread) {
136
// System.err.println("Priority thread waiting: " + thread.toString());
137
// Thread.dumpStack();
138
// }
139
this.wait();
140                 } catch (InterruptedException JavaDoc e) {
141                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
142                 }
143             }
144     // if (writeAccess && endTransInProgress) {
145
// throw new IllegalStateException("Cannot do modifications while commit/rollback in progress.");
146
// }
147
this.thread = thread;
148
149             if (isPriorityThread) {
150     // System.out.print(".");
151
if (priorityThreads != null && priorityThreads.isEmpty()) {
152                     priorityThreads = null;
153                 }
154                 isSwingWaiting = priorityThreads != null;
155             }
156             
157             modCount++;
158             if (modCount == 0) modCount = 1;
159
160             if (JMManager.TRANS_DEBUG) {
161                 Thread.dumpStack();
162             }
163         }
164         
165         counter++;
166         
167         if (writeAccess) {
168             if (!changes) {
169                 changes = true;
170                 start();
171             }
172         }
173         
174         if (counter == 1) {
175             boolean success = false;
176             try {
177                 parseIfNeeded(writeAccess);
178                 success = true;
179             } finally {
180                 if (!success) {
181                     try {
182                         if (changes && counter == 1) {
183                             end(true);
184                             notifyElements();
185                             ClassIndex.rollback();
186                         }
187                     } catch (RuntimeException JavaDoc x) {
188                         // throw the original exception rather than x
189
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x);
190                     } finally {
191                         finalizeTrans();
192                     }
193                 }
194             }
195             clearClassPath();
196             clearParserCache();
197         }
198     }
199
200     private void clearClassPath() {
201         classPath = null;
202         searchScope = null;
203     }
204     
205     private void clearParserCache() {
206         parserCache=null;
207     }
208
209     private void parseIfNeeded(boolean writeAccess) {
210         boolean isEmpty;
211         FileObject[] fos;
212         
213         synchronized (needDelete) {
214             isEmpty = needDelete.isEmpty();
215         }
216         
217         if (!isEmpty) {
218             synchronized (needDelete) {
219                 fos = (FileObject[]) needDelete.toArray(new FileObject[needDelete.size()]);
220                 if (DEBUG) {
221                     System.err.println("cleaning needDelete"); // NOI18N
222
Thread.dumpStack();
223                 }
224                 needDelete.clear();
225             }
226             for (int i = 0; i < fos.length; i++) {
227                 FileObject fo = fos[i];
228                 ResourceImpl res;
229                 
230                 FileObject cpRoot = Util.getCPRoot(fo);
231                 if (cpRoot == null) return; // ignore fileobjects that are not visible from our merged classpath
232

233                 JavaModelPackage modelPckg = manager.resolveJavaExtent(cpRoot);
234                 if (modelPckg==null) return;
235                 Resource resource = (ResourceImpl) ((ResourceClassImpl) modelPckg.getResource()).resolveResource(
236                         manager.getResourceName(fo), false, false);
237                 
238                 if (resource!=null) {
239                     resource.refDelete();
240                 }
241             }
242         }
243
244         synchronized (needParsingRW) {
245             isEmpty = needParsingRW.isEmpty();
246         }
247         if (!isEmpty) {
248             synchronized (needParsingRW) {
249                 fos = (FileObject[]) needParsingRW.toArray(new FileObject[needParsingRW.size()]);
250                 needParsingRW.clear();
251             }
252
253             for (int i = 0; i < fos.length; i++) {
254                 FileObject fobj=fos[i];
255
256                 if (!fobj.isValid()) continue;
257                 JavaModel.setClassPath(fobj);
258                 RepositoryUpdater.getDefault().createOrUpdateResource(fobj);
259         needParsing.remove(fobj);
260             }
261         }
262
263         if (writeAccess) {
264             synchronized (needParsing) {
265                 isEmpty = needParsing.isEmpty();
266             }
267             
268             if (!isEmpty) {
269                 synchronized (needParsing) {
270                     fos = (FileObject[]) needParsing.toArray(new FileObject[needParsing.size()]);
271                     if (DEBUG) {
272                         System.err.println("cleaning needParsing"); // NOI18N
273
Thread.dumpStack();
274                     }
275                     needParsing.clear();
276                 }
277                 for (int i = 0; i < fos.length; i++) {
278                     FileObject fobj=fos[i];
279                     ResourceImpl res;
280                     
281                     if (!fobj.isValid()) continue;
282                     JavaModel.setClassPath(fobj);
283                     res = (ResourceImpl) ((JMManager) JavaMetamodel.getManager()).getResource(fobj, false);
284                     if (res != null) {
285                         res.updateFromFileObject(fobj,true);
286                     }
287                 }
288             }
289         }
290         
291         synchronized (needTSUpdate) {
292             isEmpty = needTSUpdate.isEmpty();
293         }
294         if (!isEmpty) {
295             synchronized (needTSUpdate) {
296                 fos = (FileObject[]) needTSUpdate.toArray(new FileObject[needTSUpdate.size()]);
297                 needTSUpdate.clear();
298             }
299             
300             for (int i = 0; i < fos.length; i++) {
301                 FileObject fo = fos[i];
302                 if (!fo.isValid()) continue;
303                 RepositoryUpdater.updateTimeStamp(fo);
304             }
305         }
306     }
307     
308     public Thread JavaDoc getThread() {
309         return thread;
310     }
311     
312     public void addModified(FileObject fo) {
313         if (DEBUG) {
314             System.out.println("adding " + fo + " to needParsing"); // NOI18N
315
Thread.dumpStack();
316         }
317         synchronized (needParsing) {
318             needParsing.add(fo);
319         }
320     }
321     
322     void addDeleted(FileObject fo) {
323         synchronized (needDelete) {
324             needDelete.add(fo);
325         }
326     }
327     
328     void addModifiedRW(FileObject fo) {
329         synchronized (needParsingRW) {
330             synchronized (needParsing) {
331                 needParsingRW.add(fo);
332                 needParsing.remove(fo);
333             }
334         }
335     }
336     
337     void addUpdateTS(FileObject fo) {
338         synchronized (needTSUpdate) {
339             needTSUpdate.add(fo);
340         }
341     }
342     
343     public synchronized boolean leave(boolean fail) {
344         assert thread == Thread.currentThread() : "Cannot end transaction from a different thread!"; // NOI18N
345
if (fail) {
346             JMManager.getLog().notify(ErrorManager.INFORMATIONAL,new Exception JavaDoc("rollback!!!")); // NOI18N
347
}
348         boolean result = false;
349         try {
350             if (changes) {
351                 this.fail |= fail;
352             } else {
353                 if (fail) throw new RuntimeException JavaDoc("Cannot fail in read mode."); // NOI18N
354
}
355
356             if (counter == 1) {
357                 result = true;
358                 if (changes) {
359 // endTransInProgress = true;
360
if (this.fail) {
361                         end(true);
362                         notifyElements();
363                         ClassIndex.rollback();
364                     } else {
365                         notifyElements();
366                         end(false);
367                         ClassIndex.commit();
368                     }
369                 }
370             }
371         } catch (RuntimeException JavaDoc x) {
372             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x);
373             this.fail = true;
374             try {
375                 end(true);
376             } catch (RuntimeException JavaDoc e) {
377                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
378             }
379             try {
380                 notifyElements();
381             } catch (RuntimeException JavaDoc e) {
382                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
383             }
384             try {
385                 ClassIndex.rollback();
386             } catch (RuntimeException JavaDoc e) {
387                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
388             }
389         } finally {
390             finalizeTrans();
391         }
392         return result;
393     }
394     
395     private void finalizeTrans() {
396         if (counter > 0) {
397             counter--;
398             if (counter == 0) {
399                 this.modificationsDisabled = false;
400                 this.isSafeTrans = false;
401                 this.thread = null;
402                 this.fail = false;
403                 changes = false;
404                 clearClassPath();
405                 clearParserCache();
406                 this.notifyAll();
407             }
408         } else {
409             throw new RuntimeException JavaDoc("Error: leave() without enter()."); // NOI18N
410
}
411     }
412
413     void setClassPath(List JavaDoc/*<ClassPath>*/ cp, boolean preferSources) {
414         classPath = FilterClassPathImplementation.createClassPath(cp, preferSources);
415     }
416     
417     public void setSearchScope(List JavaDoc/*<ClassPath>*/ cp) {
418         searchScope = cp;
419     }
420     
421     List JavaDoc/*<ClassPath>*/ getSearchScope() {
422         return searchScope;
423     }
424     
425     public ClassPath getClassPath() {
426         return classPath;
427     }
428     
429     public synchronized Map JavaDoc getParserCache() {
430         if (parserCache==null)
431             parserCache=new HashMap JavaDoc();
432         return parserCache;
433     }
434     
435     public void invalidateAtCommit(Element element) {
436         invalidClasses.add(element);
437     }
438
439     public boolean pendingChanges() {
440         return changes;
441     }
442
443     public boolean willFail() {
444         return fail;
445     }
446
447     public void registerChange(ResourceImpl resource) {
448         changedRscSet.add(resource);
449     }
450     
451     public void registerPersisted(SemiPersistentElement element) {
452         upToDateElements.add(element._getMofId());
453     }
454
455     public void unregisterChange(ResourceImpl resource) {
456         changedRscSet.remove(resource);
457     }
458
459     public void registerExtChange(ExternalChange change) {
460         changedExternalSet.add(change);
461     }
462
463     public void registerUndoElement(ExternalChange change) {
464         undoElementsSet.add(change);
465     }
466
467     public void addNew(Element h) {
468         newObjects.add(h);
469     }
470
471     public void removeNew(Element h) {
472         newObjects.remove(h);
473     }
474
475     public void addBFeatureToInitQueue(Object JavaDoc bf) {
476         initBodyQueue.add(bf);
477     }
478
479     private void notifyElements() {
480         if (!upToDateElements.isEmpty()) {
481             for (Iterator JavaDoc it = upToDateElements.iterator(); it.hasNext();) {
482                 Object JavaDoc element = ((NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository()).getByMofId((MOFID) it.next());
483                 if (element != null) {
484                     ((SemiPersistentElement) element).clearPersist(this.fail);
485                 }
486             }
487             if (!this.fail) {
488                 upToDateElements.clear();
489             }
490         }
491         if (!modificationsDisabled && (!changedRscSet.isEmpty() || !changedExternalSet.isEmpty() || !undoElementsSet.isEmpty())) {
492             JavaMetamodel.getUndoManager().transactionStarted();
493         }
494
495         try {
496             if (!modificationsDisabled && !this.fail) {
497                 for (Iterator JavaDoc it = undoElementsSet.iterator(); it.hasNext();) {
498                     JavaMetamodel.getUndoManager().addItem((ExternalChange) it.next());
499                 }
500             }
501             initBodyQueue = new ArrayList JavaDoc();
502             if (this.fail || !modificationsDisabled) {
503                 if (!changedRscSet.isEmpty()) {
504                     JMManager.initIndentation();
505                     for (Iterator JavaDoc resIt = changedRscSet.iterator(); resIt.hasNext(); ) {
506                         ResourceImpl resource = (ResourceImpl) resIt.next();
507                         if (this.fail) {
508                             resource.rollbackChanges();
509                         } else {
510                             resource.commitChanges();
511                             if (!newObjects.isEmpty()) {
512                                 throw new RuntimeException JavaDoc("Some objects were not added to a resource or deleted before commit."); // NOI18N
513
}
514                         }
515                     }
516                 }
517             }
518
519             if (!this.fail) {
520                 for (Iterator JavaDoc it = invalidClasses.iterator(); it.hasNext();) {
521                     Element el = (Element) it.next();
522                     if (el.isValid()) {
523                         el.refDelete();
524                     }
525                     it.remove();
526                 }
527                 ResourceImpl resource;
528                 Iterator JavaDoc resIt;
529                 for (resIt = changedRscSet.iterator(); resIt.hasNext(); ) {
530                     resource = (ResourceImpl) resIt.next();
531                     resource.parseResource();
532                 }
533                 for (resIt = changedRscSet.iterator(); resIt.hasNext(); ) {
534                     resource = (ResourceImpl) resIt.next();
535                     resource.commitConfirmed();
536                     FileObject fo = ((JMManager) JavaMetamodel.getManager()).getFileObject(resource);
537                     if (DEBUG) System.out.println("removing " + fo + " from needParsing"); // NOI18N
538
synchronized (needParsing) {
539                         needParsing.remove(fo);
540                     }
541                     synchronized (needParsing) {
542                         needParsingRW.remove(fo);
543                     }
544                 }
545             }
546             while (!initBodyQueue.isEmpty()) {
547                 Object JavaDoc bf = initBodyQueue.remove(0);
548                 if (bf instanceof BehavioralFeatureImpl) {
549                     ((BehavioralFeatureImpl)bf).initBody();
550                 } else if (bf instanceof FieldImpl) {
551                     ((FieldImpl)bf).initInitValue();
552                 } else if (bf instanceof EnumConstantImpl) {
553                     ((EnumConstantImpl) bf).initInitValue();
554                 } else if (bf instanceof AttributeImpl) {
555                     ((AttributeImpl) bf).initDefaultValue();
556                 } else {
557                     ((AttributeValueImpl) bf).initInitValue();
558                 }
559             }
560         
561             initBodyQueue=null;
562
563             if (!this.fail && !modificationsDisabled) {
564                 for (Iterator JavaDoc it = changedExternalSet.iterator(); it.hasNext(); ) {
565                     ExternalChange change = (ExternalChange) it.next();
566                     JavaMetamodel.getUndoManager().addItem(change);
567                     change.performExternalChange();
568                 }
569             }
570         } finally {
571             if (!modificationsDisabled && (!changedRscSet.isEmpty() || !changedExternalSet.isEmpty() || !undoElementsSet.isEmpty())) {
572                 JavaMetamodel.getUndoManager().transactionEnded(this.fail);
573             }
574             changedExternalSet.clear();
575             undoElementsSet.clear();
576             changedRscSet.clear();
577             newObjects.clear();
578         }
579     }
580
581     public void disableModifications() {
582         modificationsDisabled = true;
583     }
584     
585     boolean isModified(FileObject fileObject) {
586         synchronized(needParsing) {
587             return needParsing.contains(fileObject);
588         }
589     }
590 }
591
Popular Tags