1 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 ; 27 import java.beans.PropertyChangeEvent ; 28 import java.io.IOException ; 29 30 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); private FileLock updateLock = null; 47 48 private final RequestProcessor.Task updateTask = requestProcessor.create(new Runnable () { 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 () { 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 () { 74 public void run() { 75 reloadModel(); 76 } 77 }); 78 private final XmlMultiViewDataObject.DataCache dataCache; 79 80 85 public XmlMultiViewDataSynchronizer(XmlMultiViewDataObject dataObject, int delay) { 86 this.dataObject = dataObject; 87 dataCache = dataObject.getDataCache(); 88 updateDelay = delay; 89 this.dataObject.addPropertyChangeListener(new PropertyChangeListener () { 90 public void propertyChange(PropertyChangeEvent evt) { 91 if (XmlMultiViewDataObject.PROPERTY_DATA_MODIFIED.equals(evt.getPropertyName())) { 92 dataModified(((Long ) evt.getNewValue()).longValue()); 93 } else if (XmlMultiViewDataObject.PROPERTY_DATA_UPDATED.equals(evt.getPropertyName())) { 94 dataUpdated(((Long ) 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 117 public FileLock takeLock() throws IOException { 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 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 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 161 protected abstract boolean mayUpdateData(boolean allowDialog); 162 163 170 protected abstract void updateDataFromModel(Object model, FileLock lock, boolean modify); 171 172 176 protected abstract Object getModel(); 177 178 179 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 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 216 public Transaction openTransaction() { 217 try { 218 FileLock lock = takeLock(); 219 if (lock != null) { 220 return new Transaction(lock); 221 } 222 } catch (IOException e) { 223 ErrorManager.getDefault().annotate(e, NbBundle.getMessage(XmlMultiViewDataSynchronizer.class, 224 "START_TRANSACTION_FAILED")); 225 } 226 return null; 227 } 228 229 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 252 public class Transaction { 253 private FileLock lock; 254 255 private Transaction(FileLock lock) { 256 this.lock = lock; 257 } 258 259 262 public void rollback() { 263 if (lock != null) { 264 reloadModel(); 265 lock.releaseLock(); 266 lock = null; 267 } 268 } 269 270 273 public void commit() throws IOException { 274 dataCache.testLock(lock); 275 updateData(lock, false); 276 lock.releaseLock(); 277 lock = null; 278 } 279 } 280 } 281 | Popular Tags |