KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > multiview > XmlMultiViewDataSynchronizer


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.multiview;
20
21 import org.openide.filesystems.FileLock;
22 import org.openide.util.RequestProcessor;
23 import org.openide.util.NbBundle;
24 import org.openide.ErrorManager;
25
26 import java.beans.PropertyChangeListener JavaDoc;
27 import java.beans.PropertyChangeEvent JavaDoc;
28 import java.io.IOException JavaDoc;
29
30 /**
31  * Performs synchronization between model and binary data in data object
32  * or rather in {@link XmlMultiViewEditorSupport.XmlEnv}.
33  *
34  * @author pfiala
35  */

36 public abstract class XmlMultiViewDataSynchronizer {
37
38     private final int updateDelay;
39     private long timeStamp;
40     private final XmlMultiViewDataObject dataObject;
41     private int reloading = 0;
42     private int updating = 0;
43
44     protected final RequestProcessor requestProcessor =
45             new RequestProcessor("XmlMultiViewDataSynchronizer RequestProcessor", 1); // NOI18N
46
private FileLock updateLock = null;
47
48     private final RequestProcessor.Task updateTask = requestProcessor.create(new Runnable JavaDoc() {
49         public void run() {
50             if (isUpdateLock()) {
51                 finishUpdateTask.cancel();
52                 updateData(updateLock, true);
53                 synchronized (updateTask) {
54                     if (updateTask.getDelay() <= 0) {
55                         finishUpdateTask.schedule(1);
56                     }
57                 }
58             }
59         }
60     });
61
62     private final RequestProcessor.Task finishUpdateTask = requestProcessor.create(new Runnable JavaDoc() {
63         public void run() {
64             synchronized (updateTask) {
65                 if (isUpdateLock()) {
66                     updateLock.releaseLock();
67                     updateLock = null;
68                 }
69             }
70         }
71     });
72
73     private final RequestProcessor.Task reloadTask = requestProcessor.create(new Runnable JavaDoc() {
74         public void run() {
75             reloadModel();
76         }
77     });
78     private final XmlMultiViewDataObject.DataCache dataCache;
79
80     /**
81      * Creates synchronizer for given data object and sets default delay.
82      * @param dataObject data object containing the binary data
83      * @param delay default delay between model modification and data update
84      */

85     public XmlMultiViewDataSynchronizer(XmlMultiViewDataObject dataObject, int delay) {
86         this.dataObject = dataObject;
87         dataCache = dataObject.getDataCache();
88         updateDelay = delay;
89         this.dataObject.addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
90             public void propertyChange(PropertyChangeEvent JavaDoc evt) {
91                 if (XmlMultiViewDataObject.PROPERTY_DATA_MODIFIED.equals(evt.getPropertyName())) {
92                     dataModified(((Long JavaDoc) evt.getNewValue()).longValue());
93                 } else if (XmlMultiViewDataObject.PROPERTY_DATA_UPDATED.equals(evt.getPropertyName())) {
94                     dataUpdated(((Long JavaDoc) evt.getNewValue()).longValue());
95                 }
96             }
97         });
98     }
99
100     protected void dataModified(long timeStamp) {
101         if (this.timeStamp < timeStamp) {
102             reloadTask.schedule(10);
103         }
104     }
105
106     protected void dataUpdated(long timeStamp) {
107         if (updating == 0 && this.timeStamp < timeStamp) {
108             reloadTask.schedule(10);
109         }
110     }
111
112     /**
113      * Obtains data lock if possible.
114      * @return the lock if success
115      * @throws IOException
116      */

117     public FileLock takeLock() throws IOException JavaDoc {
118         final FileLock lock = dataObject.waitForLock(1000);
119         if (lock != null) {
120             if (mayUpdateData(true)) {
121                 return lock;
122             } else {
123                 lock.releaseLock();
124             }
125         }
126         return null;
127     }
128
129     /**
130      * Schedules update of binary data from model.
131      * Property <I>modified</I> of the data object is true after update.
132      */

133     public final void requestUpdateData() {
134         if (reloading == 0) {
135             synchronized (updateTask) {
136                 finishUpdateTask.cancel();
137                 if (!isUpdateLock()) {
138                     try {
139                         updateLock = takeLock();
140                     } catch (IOException JavaDoc e) {
141                         ErrorManager.getDefault().notify(e);
142                         return;
143                     }
144                 }
145                 updateTask.schedule(dataObject.isModified() ? updateDelay : 1);
146             }
147         }
148     }
149
150     private boolean isUpdateLock() {
151         return updateLock != null && updateLock.isValid();
152     }
153
154     /**
155      * Test whether the synchronizer may update the binary data.
156      *
157      * @return true if the synchronizer may update the binary data, otherwise false
158      * (e.g. in case of invalid xml data)
159      * @param allowDialog allows opening of dialog for confimation if taking a lock could lead to data loss
160      */

161     protected abstract boolean mayUpdateData(boolean allowDialog);
162
163     /**
164      * Updates data from model.
165      * @param model a model
166      * @param lock a lock of the data cache
167      * @param modify indicator whether property <i>modified</i> of the data object
168      * should change after update or not
169      */

170     protected abstract void updateDataFromModel(Object JavaDoc model, FileLock lock, boolean modify);
171
172     /**
173      * Returns model of the synchronizer
174      * @return the model
175      */

176     protected abstract Object JavaDoc getModel();
177
178
179     /**
180      * Reloads model from data.
181      */

182     protected abstract void reloadModelFromData();
183
184     final void reloadingStarted() {
185         reloading++;
186     }
187
188     final void reloadingFinished() {
189         reloading--;
190     }
191
192     public final RequestProcessor.Task getReloadTask() {
193         return reloadTask;
194     }
195
196     /**
197      * Reloads model from binary data in cache
198      */

199     protected void reloadModel() {
200         long newTimeStamp = dataCache.getTimeStamp();
201         if (timeStamp < newTimeStamp) {
202             reloadingStarted();
203             try {
204                 timeStamp = newTimeStamp;
205                 reloadModelFromData();
206             } finally {
207                 reloadingFinished();
208             }
209         }
210     }
211
212     /**
213      * Obtains a binary data lock and crates the {@link Transaction}
214      * @return Transaction object
215      */

216     public Transaction openTransaction() {
217         try {
218             FileLock lock = takeLock();
219             if (lock != null) {
220                 return new Transaction(lock);
221             }
222         } catch (IOException JavaDoc e) {
223             ErrorManager.getDefault().annotate(e, NbBundle.getMessage(XmlMultiViewDataSynchronizer.class,
224                     "START_TRANSACTION_FAILED"));
225         }
226         return null;
227     }
228
229     /**
230      * Updates data from model and updates timeStamp field.
231      * @param dataLock a lock of the data cache. Will be released after updating
232      * has finished (in case it wasn't released already).
233      * @param modify indicator whether property <i>modified</i> of the data object
234      * should change after update or not
235      */

236     public void updateData(FileLock dataLock, boolean modify) {
237         updating++;
238         try {
239             updateDataFromModel(getModel(), dataLock, modify);
240             timeStamp = dataCache.getTimeStamp();
241         } finally {
242             updating--;
243             if (dataLock != null && dataLock.isValid()){
244                 dataLock.releaseLock();
245             }
246         }
247     }
248
249     /**
250      * Serves to controlling complex model changes
251      */

252     public class Transaction {
253         private FileLock lock;
254
255         private Transaction(FileLock lock) {
256             this.lock = lock;
257         }
258
259         /**
260          * Rollback changes made during the transaction.
261          */

262         public void rollback() {
263             if (lock != null) {
264                 reloadModel();
265                 lock.releaseLock();
266                 lock = null;
267             }
268         }
269
270         /**
271          * Commit changes - update binary data from model.
272          */

273         public void commit() throws IOException JavaDoc {
274             dataCache.testLock(lock);
275             updateData(lock, false);
276             lock.releaseLock();
277             lock = null;
278         }
279     }
280 }
281
Popular Tags