|
Lines 40-45
Link Here
|
| 40 |
import org.eclipse.core.runtime.IPath; |
40 |
import org.eclipse.core.runtime.IPath; |
| 41 |
import org.eclipse.core.runtime.IStatus; |
41 |
import org.eclipse.core.runtime.IStatus; |
| 42 |
import org.eclipse.core.runtime.NullProgressMonitor; |
42 |
import org.eclipse.core.runtime.NullProgressMonitor; |
|
|
43 |
import org.eclipse.core.runtime.OperationCanceledException; |
| 43 |
import org.eclipse.core.runtime.Path; |
44 |
import org.eclipse.core.runtime.Path; |
| 44 |
import org.eclipse.core.runtime.Platform; |
45 |
import org.eclipse.core.runtime.Platform; |
| 45 |
import org.eclipse.core.runtime.QualifiedName; |
46 |
import org.eclipse.core.runtime.QualifiedName; |
|
Lines 47-55
Link Here
|
| 47 |
import org.eclipse.core.runtime.content.IContentDescription; |
48 |
import org.eclipse.core.runtime.content.IContentDescription; |
| 48 |
import org.eclipse.core.runtime.jobs.ILock; |
49 |
import org.eclipse.core.runtime.jobs.ILock; |
| 49 |
import org.eclipse.core.runtime.jobs.Job; |
50 |
import org.eclipse.core.runtime.jobs.Job; |
|
|
51 |
import org.eclipse.core.runtime.preferences.ConfigurationScope; |
| 52 |
import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
| 53 |
import org.eclipse.core.runtime.preferences.IPreferencesService; |
| 54 |
import org.eclipse.core.runtime.preferences.IScopeContext; |
| 55 |
import org.eclipse.core.runtime.preferences.InstanceScope; |
| 56 |
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; |
| 50 |
import org.eclipse.jface.text.BadLocationException; |
57 |
import org.eclipse.jface.text.BadLocationException; |
| 51 |
import org.eclipse.jface.text.IDocument; |
58 |
import org.eclipse.jface.text.IDocument; |
| 52 |
import org.eclipse.jface.text.IRegion; |
59 |
import org.eclipse.jface.text.IRegion; |
|
|
60 |
import org.eclipse.osgi.util.NLS; |
| 53 |
import org.eclipse.text.edits.MultiTextEdit; |
61 |
import org.eclipse.text.edits.MultiTextEdit; |
| 54 |
import org.eclipse.text.edits.ReplaceEdit; |
62 |
import org.eclipse.text.edits.ReplaceEdit; |
| 55 |
import org.eclipse.text.edits.TextEdit; |
63 |
import org.eclipse.text.edits.TextEdit; |
|
Lines 96-101
Link Here
|
| 96 |
*/ |
104 |
*/ |
| 97 |
public class ModelManagerImpl implements IModelManager { |
105 |
public class ModelManagerImpl implements IModelManager { |
| 98 |
|
106 |
|
|
|
107 |
private static int WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); |
| 108 |
private static boolean ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); |
| 109 |
private static IEclipsePreferences.IPreferenceChangeListener LISTENER; |
| 110 |
static { |
| 111 |
InstanceScope scope = new InstanceScope(); |
| 112 |
IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); |
| 113 |
LISTENER = new IEclipsePreferences.IPreferenceChangeListener() { |
| 114 |
|
| 115 |
public void preferenceChange(PreferenceChangeEvent event) { |
| 116 |
|
| 117 |
if ("modelmanager.maxWaitDuringConcurrentLoad".equals(event.getKey())) { |
| 118 |
WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); |
| 119 |
} |
| 120 |
else if ("modelmanager.allowInterruptsDuringConcurrentLoad".equals(event.getKey())) { |
| 121 |
ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); |
| 122 |
} |
| 123 |
} |
| 124 |
}; |
| 125 |
instancePrefs.addPreferenceChangeListener(LISTENER); |
| 126 |
} |
| 127 |
|
| 99 |
static class ReadEditType { |
128 |
static class ReadEditType { |
| 100 |
ReadEditType(String type) { |
129 |
ReadEditType(String type) { |
| 101 |
} |
130 |
} |
|
Lines 109-115
Link Here
|
| 109 |
int referenceCountForRead; |
138 |
int referenceCountForRead; |
| 110 |
IStructuredModel theSharedModel; |
139 |
IStructuredModel theSharedModel; |
| 111 |
boolean initializing = true; |
140 |
boolean initializing = true; |
| 112 |
boolean doWait = true; |
141 |
volatile boolean doWait = true; |
|
|
142 |
final Object loadLock = new Object(); |
| 113 |
|
143 |
|
| 114 |
SharedObject(IStructuredModel sharedModel) { |
144 |
SharedObject(IStructuredModel sharedModel) { |
| 115 |
theSharedModel = sharedModel; |
145 |
theSharedModel = sharedModel; |
|
Lines 124-136
Link Here
|
| 124 |
* is up-to-date. |
154 |
* is up-to-date. |
| 125 |
*/ |
155 |
*/ |
| 126 |
public synchronized void waitForLoadAttempt() { |
156 |
public synchronized void waitForLoadAttempt() { |
| 127 |
while(initializing) { |
157 |
long start = System.currentTimeMillis(); |
|
|
158 |
// Note: A WAIT_DELAY of 0 is infinite |
| 159 |
int maxTimeMs = Math.max(0, WAIT_DELAY); |
| 160 |
final int waitInterval = Math.min(250, maxTimeMs); |
| 161 |
boolean interrupted = false; |
| 162 |
while (initializing && maxTimeMs >= 0) { |
| 128 |
try { |
163 |
try { |
| 129 |
wait(); |
164 |
wait(waitInterval); |
|
|
165 |
maxTimeMs -= waitInterval; |
| 130 |
} |
166 |
} |
| 131 |
catch (InterruptedException e) { |
167 |
catch (InterruptedException e) { |
| 132 |
// ignore interruption! |
168 |
interrupted = true; |
|
|
169 |
if (ALLOW_INTERRUPT_WAITING_THREAD) { |
| 170 |
break; |
| 171 |
} |
| 172 |
} |
| 173 |
} |
| 174 |
if (initializing) { |
| 175 |
long totalWaitTime = System.currentTimeMillis() - start; |
| 176 |
if (interrupted) { |
| 177 |
throw new OperationCanceledException( |
| 178 |
"Waiting thread interrupted during simultenous model load. Load aborted. (Waited " |
| 179 |
+ totalWaitTime + "ms)"); |
| 133 |
} |
180 |
} |
|
|
181 |
else { |
| 182 |
throw new OperationCanceledException( |
| 183 |
"Waiting thread timed-out during simultenous model load. Load aborted. (Waited " |
| 184 |
+ totalWaitTime + "ms)"); |
| 185 |
} |
| 186 |
} |
| 187 |
if (interrupted) { |
| 188 |
// Propagate (don't swallow) the interrupt |
| 189 |
Thread.currentThread().interrupt(); |
| 134 |
} |
190 |
} |
| 135 |
} |
191 |
} |
| 136 |
|
192 |
|
|
Lines 166-171
Link Here
|
| 166 |
return instance; |
222 |
return instance; |
| 167 |
} |
223 |
} |
| 168 |
|
224 |
|
|
|
225 |
public void removePreferenceListener() { |
| 226 |
InstanceScope scope = new InstanceScope(); |
| 227 |
IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); |
| 228 |
instancePrefs.removePreferenceChangeListener(LISTENER); |
| 229 |
} |
| 230 |
|
| 169 |
/** |
231 |
/** |
| 170 |
* Our cache of managed objects |
232 |
* Our cache of managed objects |
| 171 |
*/ |
233 |
*/ |
|
Lines 183-191
Link Here
|
| 183 |
ModelManagerImpl() { |
245 |
ModelManagerImpl() { |
| 184 |
super(); |
246 |
super(); |
| 185 |
fManagedObjects = new HashMap(); |
247 |
fManagedObjects = new HashMap(); |
| 186 |
// To prevent deadlocks: always acquire multiple locks in this order: SYNC, sharedObject. |
248 |
/** |
| 187 |
// DO NOT acquire a SYNC within a sharedObject lock, unless you already own the SYNC lock |
249 |
* NOTES: To prevent deadlocks: always acquire multiple locks in this |
| 188 |
// Tip: Try to hold the smallest number of locks you can |
250 |
* order: SYNC->sharedObject.loadLock->sharedObject DO NOT acquire a |
|
|
251 |
* SYNC within a sharedObject lock, unless you already own the SYNC lock |
| 252 |
* Tip: Try to hold the smallest number of locks you can |
| 253 |
*/ |
| 189 |
} |
254 |
} |
| 190 |
|
255 |
|
| 191 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
256 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
|
Lines 262-268
Link Here
|
| 262 |
SharedObject sharedObject) throws CoreException, IOException { |
327 |
SharedObject sharedObject) throws CoreException, IOException { |
| 263 |
// XXX: Does not integrate with FileBuffers |
328 |
// XXX: Does not integrate with FileBuffers |
| 264 |
boolean doRemove = false; |
329 |
boolean doRemove = false; |
| 265 |
synchronized(sharedObject) { |
330 |
synchronized (sharedObject.loadLock) { |
| 266 |
InputStream inputStream = null; |
331 |
InputStream inputStream = null; |
| 267 |
IStructuredModel model = null; |
332 |
IStructuredModel model = null; |
| 268 |
try { |
333 |
try { |
|
Lines 283-291
Link Here
|
| 283 |
} |
348 |
} |
| 284 |
} |
349 |
} |
| 285 |
if (model != null) { |
350 |
if (model != null) { |
|
|
351 |
synchronized (sharedObject) { |
| 286 |
// add to our cache |
352 |
// add to our cache |
| 287 |
sharedObject.theSharedModel=model; |
353 |
sharedObject.theSharedModel=model; |
| 288 |
_initCount(sharedObject, rwType); |
354 |
_initCount(sharedObject, rwType); |
|
|
355 |
} |
| 289 |
} else { |
356 |
} else { |
| 290 |
doRemove = true; |
357 |
doRemove = true; |
| 291 |
} |
358 |
} |
|
Lines 348-354
Link Here
|
| 348 |
URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter, |
415 |
URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter, |
| 349 |
SharedObject sharedObject) throws IOException { |
416 |
SharedObject sharedObject) throws IOException { |
| 350 |
boolean doRemove = false; |
417 |
boolean doRemove = false; |
| 351 |
synchronized(sharedObject) { |
418 |
synchronized (sharedObject.loadLock) { |
| 352 |
IStructuredModel model = null; |
419 |
IStructuredModel model = null; |
| 353 |
try { |
420 |
try { |
| 354 |
model = _commonCreateModel(id, handler, resolver); |
421 |
model = _commonCreateModel(id, handler, resolver); |
|
Lines 380-388
Link Here
|
| 380 |
((AbstractStructuredModel) model).setContentTypeIdentifier(description.getContentType().getId()); |
447 |
((AbstractStructuredModel) model).setContentTypeIdentifier(description.getContentType().getId()); |
| 381 |
} |
448 |
} |
| 382 |
} |
449 |
} |
| 383 |
|
450 |
synchronized (sharedObject) { |
| 384 |
sharedObject.theSharedModel = model; |
451 |
sharedObject.theSharedModel = model; |
| 385 |
_initCount(sharedObject, rwType); |
452 |
_initCount(sharedObject, rwType); |
|
|
453 |
} |
| 386 |
} else { |
454 |
} else { |
| 387 |
doRemove = true; |
455 |
doRemove = true; |
| 388 |
} |
456 |
} |
|
Lines 492-504
Link Here
|
| 492 |
|
560 |
|
| 493 |
private void _doCommonGetModel(IFile file, String id, SharedObject sharedObject,ReadEditType rwType) { |
561 |
private void _doCommonGetModel(IFile file, String id, SharedObject sharedObject,ReadEditType rwType) { |
| 494 |
boolean doRemove = false; |
562 |
boolean doRemove = false; |
| 495 |
synchronized(sharedObject) { |
563 |
synchronized (sharedObject.loadLock) { |
| 496 |
sharedObject.doWait=false; |
564 |
sharedObject.doWait=false; |
| 497 |
IStructuredModel model = FileBufferModelManager.getInstance().getModel(file); |
565 |
IStructuredModel model = FileBufferModelManager.getInstance().getModel(file); |
| 498 |
sharedObject.doWait=true; |
566 |
sharedObject.doWait=true; |
| 499 |
if (model != null) { |
567 |
if (model != null) { |
|
|
568 |
synchronized (sharedObject) { |
| 500 |
sharedObject.theSharedModel=model; |
569 |
sharedObject.theSharedModel=model; |
| 501 |
_initCount(sharedObject, rwType); |
570 |
_initCount(sharedObject, rwType); |
|
|
571 |
} |
| 502 |
} else { |
572 |
} else { |
| 503 |
doRemove = true; |
573 |
doRemove = true; |
| 504 |
} |
574 |
} |
|
Lines 582-591
Link Here
|
| 582 |
sharedObject = new SharedObject(null); |
652 |
sharedObject = new SharedObject(null); |
| 583 |
fManagedObjects.put(id, sharedObject); |
653 |
fManagedObjects.put(id, sharedObject); |
| 584 |
SYNC.release(); |
654 |
SYNC.release(); |
| 585 |
synchronized(sharedObject) { |
655 |
synchronized (sharedObject.loadLock) { |
| 586 |
sharedObject.theSharedModel = FileBufferModelManager.getInstance().getModel(document); |
656 |
IStructuredModel model = FileBufferModelManager.getInstance() |
|
|
657 |
.getModel(document); |
| 658 |
synchronized (sharedObject) { |
| 659 |
sharedObject.theSharedModel = model; |
| 587 |
_initCount(sharedObject, accessType); |
660 |
_initCount(sharedObject, accessType); |
| 588 |
sharedObject.setLoaded(); |
661 |
sharedObject.setLoaded(); |
|
|
662 |
} |
| 589 |
} |
663 |
} |
| 590 |
break; |
664 |
break; |
| 591 |
} else if (sharedObject == testObject) { |
665 |
} else if (sharedObject == testObject) { |
|
Lines 2098-2101
Link Here
|
| 2098 |
SYNC.release(); |
2172 |
SYNC.release(); |
| 2099 |
return inUse; |
2173 |
return inUse; |
| 2100 |
} |
2174 |
} |
|
|
2175 |
|
| 2176 |
private static String getProperty(String property) { |
| 2177 |
// Preference overrides system property overrides env-var |
| 2178 |
|
| 2179 |
IPreferencesService preferencesService = Platform.getPreferencesService(); |
| 2180 |
IScopeContext[] lookupOrder = new IScopeContext[] { |
| 2181 |
new InstanceScope(), new ConfigurationScope() |
| 2182 |
}; |
| 2183 |
String key = property; |
| 2184 |
if (property != null && property.startsWith(SSECorePlugin.ID)) { |
| 2185 |
// +1, include the "." |
| 2186 |
key = property.substring(SSECorePlugin.ID.length() + 1, property.length()); |
| 2187 |
} |
| 2188 |
String value = preferencesService.getString(SSECorePlugin.ID, key, null, lookupOrder); |
| 2189 |
if (value == null) { |
| 2190 |
value = System.getProperty(property); |
| 2191 |
} |
| 2192 |
if (value == null) { |
| 2193 |
value = System.getenv(property); |
| 2194 |
} |
| 2195 |
return value; |
| 2196 |
} |
| 2197 |
|
| 2198 |
private static String getDefault(String property) { |
| 2199 |
// this is the "default-default" |
| 2200 |
if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) { |
| 2201 |
return "0"; |
| 2202 |
} |
| 2203 |
else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad" |
| 2204 |
.equals(property)) { |
| 2205 |
return "false"; |
| 2206 |
} |
| 2207 |
return null; |
| 2208 |
} |
| 2209 |
|
| 2210 |
private static boolean getBoolean(String key) { |
| 2211 |
String property = getProperty(key); |
| 2212 |
// if (property != null) { |
| 2213 |
// System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2214 |
// } |
| 2215 |
return property != null ? Boolean.parseBoolean(property) : Boolean |
| 2216 |
.parseBoolean(getDefault(key)); |
| 2217 |
} |
| 2218 |
|
| 2219 |
private static int getInt(String key) { |
| 2220 |
String property = getProperty(key); |
| 2221 |
int size = 0; |
| 2222 |
if (property != null) { |
| 2223 |
try { |
| 2224 |
size = Integer.parseInt(property); |
| 2225 |
// System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2226 |
} |
| 2227 |
catch (NumberFormatException e) { |
| 2228 |
size = getDefaultInt(key, property, size); |
| 2229 |
} |
| 2230 |
} |
| 2231 |
else { |
| 2232 |
size = getDefaultInt(key, property, size); |
| 2233 |
} |
| 2234 |
return size; |
| 2235 |
} |
| 2236 |
|
| 2237 |
private static int getDefaultInt(String key, String property, int size) { |
| 2238 |
// ignored |
| 2239 |
try { |
| 2240 |
size = Integer.parseInt(getDefault(key)); |
| 2241 |
} |
| 2242 |
catch (NumberFormatException e1) { |
| 2243 |
handleIntParseException(key, property, e1); |
| 2244 |
size = 0; |
| 2245 |
} |
| 2246 |
return size; |
| 2247 |
} |
| 2248 |
|
| 2249 |
private static void handleIntParseException(String key, String property, |
| 2250 |
NumberFormatException e1) { |
| 2251 |
Exception n = new Exception( |
| 2252 |
NLS |
| 2253 |
.bind( |
| 2254 |
"Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$ |
| 2255 |
key, property), e1); |
| 2256 |
n.printStackTrace(); |
| 2257 |
} |
| 2101 |
} |
2258 |
} |