KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > core > sync > SyncSupport


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.xml.core.sync;
20
21 import java.io.*;
22
23 import org.openide.loaders.*;
24 import org.openide.cookies.*;
25 import org.openide.nodes.*;
26 import org.openide.filesystems.*;
27 import org.openide.util.*;
28 import java.util.Vector JavaDoc;
29 import java.util.Arrays JavaDoc;
30
31 /**
32  * A generic support for synchronizing text, tree and file representation
33  * of a <b>DataObject</b>. It can be notifified about a change in any of the above
34  * representations by:
35  * <li>treeChanged() at TreeEditorSupport
36  * <li>textChanged() at TextEditorSupport
37  * <li>fileChanged() at FileObject
38  * it then propagates change to other representation by calling ...Impl methods
39  * of above (vitrual methods of extending classes). This support should
40  * break possible cycles in ...Impl methods if <b>synchronous</b> implementation is used.
41  *
42  * <p>
43  * It is passive object it must be controlled by calling <code>representationChanged()</code>
44  * from e.g. listeners.
45  *
46  * @author Petr Kuzel
47  * @version 1.0
48  */

49 public abstract class SyncSupport {
50
51     private /*final*/ DataObject dobj;
52     
53     /** Just performing synchronization. */
54     protected static final int JUST_SYNCHRONIZING = 1;
55     
56     /** Conflict alleared, waiting for user selection. */
57     protected static final int JUST_RESOLVING_CONFLICT = 2;
58     
59     /** Inactive */
60     protected static final int NOP = 0;
61     
62     private int syncOperation; // current operation
63

64     // lock that synchronizes access to all above fields
65
private final Object JavaDoc syncOperationLock = new SyncSupportLock();
66     
67 //~~~~~~~~~~~~~~~~~~ INIT ~~~~~~~~~~~~~~~~~~~~~~~~~
68

69     /** Creates new SyncSupport */
70     public SyncSupport (DataObject dobj) throws IllegalArgumentException JavaDoc {
71         if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("Creating sychronizator " + System.identityHashCode(this) + " for: " + dobj.getPrimaryFile() ); // NOI18N
72

73         this.dobj = dobj;
74         syncOperation = NOP;
75     }
76
77
78     // wait until
79
private void waitFor(int state) throws InterruptedException JavaDoc {
80         while (getSyncOp() != NOP) syncOperationLock.wait();
81     }
82
83     // change state
84
private void setSyncOp(int op) {
85         synchronized (syncOperationLock) {
86             
87             if (op == syncOperation) return;
88             
89             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ( "" + System.identityHashCode(this) + " syncOperation " + syncOperation + " => " + op + " Thread:" + Thread.currentThread().getName()); // NOI18N
90

91             syncOperation = op;
92             syncOperationLock.notifyAll();
93         }
94     }
95
96     private int getSyncOp() {
97         synchronized (syncOperationLock) {
98             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("" + System.identityHashCode(this) + " syncOperation = " + syncOperation + " Thread:" + Thread.currentThread().getName()); // NOI18N
99

100             return syncOperation;
101         }
102     }
103
104
105     /**
106      * @return true if just synchronizing i.e. no other sync call would succed
107      */

108     public boolean isInSync() {
109         return getSyncOp() == JUST_SYNCHRONIZING;
110     }
111
112     
113     /**
114      * It is thread save way how to enter synchronizator.
115      */

116     public void postRequest(Runnable JavaDoc task) {
117
118         boolean leave = false;
119         
120         try {
121             synchronized (syncOperationLock) {
122                 waitFor(NOP);
123                 leave = true;
124                 setSyncOp(JUST_SYNCHRONIZING);
125             }
126             
127             task.run();
128         } catch (InterruptedException JavaDoc ex) {
129             // let finally does it
130
} finally {
131             if (leave) setSyncOp(NOP);
132         }
133     }
134     
135     /**
136      * Retrieve cookie from associated DataObject.
137      */

138     protected final Node.Cookie getCookie(Class JavaDoc klass) {
139         return getDO().getCookie(klass);
140     }
141     
142     /**
143      * @return DataObject this object is serving for
144      */

145     protected final DataObject getDO() {
146         return dobj;
147     }
148
149     
150 // ~~~~~~~~~~~~~~~~~~ Representations management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151

152     /**
153      * A new model appeared.
154      * It may my change result returned by getRepresentations().
155      */

156     public abstract void addRepresentation(Representation rep);
157     
158     /**
159      * Some model disppeared.
160      * It may my change result returned by getRepresentations().
161      */

162     public abstract void removeRepresentation(Representation rep);
163     
164     /**
165      * Propagate change to other representations.
166      */

167     protected void representationChanged(Class JavaDoc type) {
168         if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("" + System.identityHashCode(this) + " entering synchronizator: " + type); // NOI18N
169

170         if (isInSync()) return; //??? prevent double enter if update() fires
171

172         try {
173             setSyncOp(JUST_SYNCHRONIZING);
174         
175             Representation master = null;
176             Representation all[] = getRepresentations(null);
177
178             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\tReps: " + Arrays.asList(all)); // NOI18N
179

180             // look for comodifications
181

182             Vector JavaDoc modified = new Vector JavaDoc();
183             for (int i=0; i<all.length; i++) {
184                 if (all[i].represents(type)) {
185                     master = all[i];
186                     modified.add(all[i]);
187                     continue;
188                 }
189
190                 if (all[i].isModified()) {
191                     modified.add(all[i]);
192                 }
193             }
194             
195             if (modified.size() > 1) {
196                 master = selectMasterRepresentation((Representation[])modified.toArray(new Representation[0]));
197             }
198
199             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\t" + System.identityHashCode(this) + " master: " + master); // NOI18N
200

201             if (master == null) return;
202
203             // propagate
204

205             for (int i=0; i<all.length; i++) {
206                 if (all[i] == master) continue;
207                 
208                 // try prefered update then arbitrary
209
if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("\tpreffered update class: " + all[i].getUpdateClass()); // NOI18N
210

211                 Object JavaDoc change = master.getChange(all[i].getUpdateClass());
212                 if (change == null) change = master.getChange(null);
213                 
214                 if (change != null) {
215                     if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\t" + System.identityHashCode(this) + " updating: " + all[i] + " with:" + change.getClass()); // NOI18N
216

217                     all[i].update(change);
218                 }
219             }
220         } finally {
221             setSyncOp(NOP);
222         }
223     }
224     
225         
226     /**
227      * Return all loaded representations (ordered). The order is importent for
228      * all subsequent calls It is guaranteed that all SyncSupport callbacks
229      * will be in the same order.
230      */

231     protected abstract Representation[] getRepresentations();
232             
233     /**
234      * Return given representations.
235      * @param type (FileObject, TreeDocumentRoot, Document)
236      */

237     protected Representation[] getRepresentations(Class JavaDoc type) {
238         
239         Representation[] all = getRepresentations();
240         if (type == null) {
241             return all;
242         } else {
243             throw new RuntimeException JavaDoc("Not Implemened."); // NOI18N
244
}
245     }
246     
247     
248     
249     /**
250      * A comodification occured resolve conflict by selecting new master or
251      * null on user cancel.
252      */

253     protected Representation selectMasterRepresentation(Representation[] choices){
254         if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("COMODIFICATION:"); // NOI18N
255
// for (int i = 0; i<choices.length; i++) {
256
// if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ((i == 0 ? "=>" : " ") + choices[i]); // NOI18N
257
// }
258

259         return choices[0];
260     }
261     
262     
263     /** Just for better thread dumps. */
264     private static class SyncSupportLock {
265     }
266     
267 }
268
Popular Tags