|
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 loadCondition = new Object(); |
| 113 |
|
143 |
|
| 114 |
SharedObject(IStructuredModel sharedModel) { |
144 |
SharedObject(IStructuredModel sharedModel) { |
| 115 |
theSharedModel = sharedModel; |
145 |
theSharedModel = sharedModel; |
|
Lines 121-135
Link Here
|
| 121 |
* Waits until this shared object has been attempted to be loaded. |
151 |
* Waits until this shared object has been attempted to be loaded. |
| 122 |
* The load is "attempted" because not all loads result in a model. |
152 |
* The load is "attempted" because not all loads result in a model. |
| 123 |
* However, upon leaving this method, theShareModel variable |
153 |
* However, upon leaving this method, theShareModel variable |
| 124 |
* is up-to-date. |
154 |
* is up-to-date. Should not be called if holding a lock on this object. |
| 125 |
*/ |
155 |
*/ |
| 126 |
public synchronized void waitForLoadAttempt() { |
156 |
public void waitForLoadAttempt() { |
| 127 |
while(initializing) { |
157 |
synchronized(loadCondition) { |
| 128 |
try { |
158 |
long start = System.currentTimeMillis(); |
| 129 |
wait(); |
159 |
// Note: A WAIT_DELAY of 0 is infinite |
|
|
160 |
int maxTimeMs = Math.max(0, WAIT_DELAY); |
| 161 |
final int waitInterval = Math.min(250, maxTimeMs); |
| 162 |
boolean interrupted = false; |
| 163 |
while (initializing && maxTimeMs >= 0) { |
| 164 |
try { |
| 165 |
loadCondition.wait(waitInterval); |
| 166 |
maxTimeMs -= waitInterval; |
| 167 |
} |
| 168 |
catch (InterruptedException e) { |
| 169 |
interrupted = true; |
| 170 |
if (ALLOW_INTERRUPT_WAITING_THREAD) { |
| 171 |
break; |
| 172 |
} |
| 173 |
} |
| 174 |
} |
| 175 |
if (initializing) { |
| 176 |
long totalWaitTime = System.currentTimeMillis() - start; |
| 177 |
if (interrupted) { |
| 178 |
throw new OperationCanceledException( |
| 179 |
"Waiting thread interrupted during simultenous model load. Load aborted. (Waited " |
| 180 |
+ totalWaitTime + "ms)"); |
| 181 |
} |
| 182 |
else { |
| 183 |
throw new OperationCanceledException( |
| 184 |
"Waiting thread timed-out during simultenous model load. Load aborted. (Waited " |
| 185 |
+ totalWaitTime + "ms)"); |
| 186 |
} |
| 130 |
} |
187 |
} |
| 131 |
catch (InterruptedException e) { |
188 |
if (interrupted) { |
| 132 |
// ignore interruption! |
189 |
// Propagate (don't swallow) the interrupt |
|
|
190 |
Thread.currentThread().interrupt(); |
| 133 |
} |
191 |
} |
| 134 |
} |
192 |
} |
| 135 |
} |
193 |
} |
|
Lines 139-147
Link Here
|
| 139 |
* {@link #waitForLoadAttempt()} will proceed after this |
197 |
* {@link #waitForLoadAttempt()} will proceed after this |
| 140 |
* method returns. |
198 |
* method returns. |
| 141 |
*/ |
199 |
*/ |
| 142 |
public synchronized void setLoaded() { |
200 |
public void setLoaded() { |
| 143 |
initializing = false; |
201 |
synchronized(loadCondition) { |
| 144 |
notifyAll(); |
202 |
initializing = false; |
|
|
203 |
loadCondition.notifyAll(); |
| 204 |
} |
| 145 |
} |
205 |
} |
| 146 |
} |
206 |
} |
| 147 |
|
207 |
|
|
Lines 166-171
Link Here
|
| 166 |
return instance; |
226 |
return instance; |
| 167 |
} |
227 |
} |
| 168 |
|
228 |
|
|
|
229 |
public void removePreferenceListener() { |
| 230 |
InstanceScope scope = new InstanceScope(); |
| 231 |
IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); |
| 232 |
instancePrefs.removePreferenceChangeListener(LISTENER); |
| 233 |
} |
| 234 |
|
| 169 |
/** |
235 |
/** |
| 170 |
* Our cache of managed objects |
236 |
* Our cache of managed objects |
| 171 |
*/ |
237 |
*/ |
|
Lines 183-191
Link Here
|
| 183 |
ModelManagerImpl() { |
249 |
ModelManagerImpl() { |
| 184 |
super(); |
250 |
super(); |
| 185 |
fManagedObjects = new HashMap(); |
251 |
fManagedObjects = new HashMap(); |
| 186 |
// To prevent deadlocks: always acquire multiple locks in this order: SYNC, sharedObject. |
252 |
/** |
| 187 |
// DO NOT acquire a SYNC within a sharedObject lock, unless you already own the SYNC lock |
253 |
* NOTES: To prevent deadlocks: always acquire multiple locks in this |
| 188 |
// Tip: Try to hold the smallest number of locks you can |
254 |
* order: SYNC->sharedObject->sharedObject.loadCondition DO NOT acquire a |
|
|
255 |
* SYNC within a sharedObject lock, unless you already own the SYNC lock |
| 256 |
* Tip: Try to hold the smallest number of locks you can |
| 257 |
*/ |
| 189 |
} |
258 |
} |
| 190 |
|
259 |
|
| 191 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
260 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
|
Lines 380-386
Link Here
|
| 380 |
((AbstractStructuredModel) model).setContentTypeIdentifier(description.getContentType().getId()); |
449 |
((AbstractStructuredModel) model).setContentTypeIdentifier(description.getContentType().getId()); |
| 381 |
} |
450 |
} |
| 382 |
} |
451 |
} |
| 383 |
|
|
|
| 384 |
sharedObject.theSharedModel = model; |
452 |
sharedObject.theSharedModel = model; |
| 385 |
_initCount(sharedObject, rwType); |
453 |
_initCount(sharedObject, rwType); |
| 386 |
} else { |
454 |
} else { |
|
Lines 1159-1168
Link Here
|
| 1159 |
// and return the object. |
1227 |
// and return the object. |
| 1160 |
SYNC.release(); |
1228 |
SYNC.release(); |
| 1161 |
doRelease=false; |
1229 |
doRelease=false; |
|
|
1230 |
if (sharedObject.doWait) { |
| 1231 |
sharedObject.waitForLoadAttempt(); |
| 1232 |
} |
| 1162 |
synchronized(sharedObject) { |
1233 |
synchronized(sharedObject) { |
| 1163 |
if (sharedObject.doWait) { |
|
|
| 1164 |
sharedObject.waitForLoadAttempt(); |
| 1165 |
} |
| 1166 |
if (sharedObject.theSharedModel!=null) { |
1234 |
if (sharedObject.theSharedModel!=null) { |
| 1167 |
_incrCount(sharedObject, EDIT); |
1235 |
_incrCount(sharedObject, EDIT); |
| 1168 |
} |
1236 |
} |
|
Lines 1241-1251
Link Here
|
| 1241 |
// and return the object. |
1309 |
// and return the object. |
| 1242 |
SYNC.release(); |
1310 |
SYNC.release(); |
| 1243 |
doRelease=false; |
1311 |
doRelease=false; |
| 1244 |
|
1312 |
if (sharedObject.doWait) { |
|
|
1313 |
sharedObject.waitForLoadAttempt(); |
| 1314 |
} |
| 1245 |
synchronized(sharedObject) { |
1315 |
synchronized(sharedObject) { |
| 1246 |
if (sharedObject.doWait) { |
|
|
| 1247 |
sharedObject.waitForLoadAttempt(); |
| 1248 |
} |
| 1249 |
if (sharedObject.theSharedModel!=null) { |
1316 |
if (sharedObject.theSharedModel!=null) { |
| 1250 |
_incrCount(sharedObject, READ); |
1317 |
_incrCount(sharedObject, READ); |
| 1251 |
} |
1318 |
} |
|
Lines 2098-2101
Link Here
|
| 2098 |
SYNC.release(); |
2165 |
SYNC.release(); |
| 2099 |
return inUse; |
2166 |
return inUse; |
| 2100 |
} |
2167 |
} |
|
|
2168 |
|
| 2169 |
private static String getProperty(String property) { |
| 2170 |
// Preference overrides system property overrides env-var |
| 2171 |
|
| 2172 |
IPreferencesService preferencesService = Platform.getPreferencesService(); |
| 2173 |
IScopeContext[] lookupOrder = new IScopeContext[] { |
| 2174 |
new InstanceScope(), new ConfigurationScope() |
| 2175 |
}; |
| 2176 |
String key = property; |
| 2177 |
if (property != null && property.startsWith(SSECorePlugin.ID)) { |
| 2178 |
// +1, include the "." |
| 2179 |
key = property.substring(SSECorePlugin.ID.length() + 1, property.length()); |
| 2180 |
} |
| 2181 |
String value = preferencesService.getString(SSECorePlugin.ID, key, null, lookupOrder); |
| 2182 |
if (value == null) { |
| 2183 |
value = System.getProperty(property); |
| 2184 |
} |
| 2185 |
if (value == null) { |
| 2186 |
value = System.getenv(property); |
| 2187 |
} |
| 2188 |
return value; |
| 2189 |
} |
| 2190 |
|
| 2191 |
private static String getDefault(String property) { |
| 2192 |
// this is the "default-default" |
| 2193 |
if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) { |
| 2194 |
return "0"; |
| 2195 |
} |
| 2196 |
else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad" |
| 2197 |
.equals(property)) { |
| 2198 |
return "false"; |
| 2199 |
} |
| 2200 |
return null; |
| 2201 |
} |
| 2202 |
|
| 2203 |
private static boolean getBoolean(String key) { |
| 2204 |
String property = getProperty(key); |
| 2205 |
// if (property != null) { |
| 2206 |
// System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2207 |
// } |
| 2208 |
return property != null ? Boolean.parseBoolean(property) : Boolean |
| 2209 |
.parseBoolean(getDefault(key)); |
| 2210 |
} |
| 2211 |
|
| 2212 |
private static int getInt(String key) { |
| 2213 |
String property = getProperty(key); |
| 2214 |
int size = 0; |
| 2215 |
if (property != null) { |
| 2216 |
try { |
| 2217 |
size = Integer.parseInt(property); |
| 2218 |
// System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2219 |
} |
| 2220 |
catch (NumberFormatException e) { |
| 2221 |
size = getDefaultInt(key, property, size); |
| 2222 |
} |
| 2223 |
} |
| 2224 |
else { |
| 2225 |
size = getDefaultInt(key, property, size); |
| 2226 |
} |
| 2227 |
return size; |
| 2228 |
} |
| 2229 |
|
| 2230 |
private static int getDefaultInt(String key, String property, int size) { |
| 2231 |
// ignored |
| 2232 |
try { |
| 2233 |
size = Integer.parseInt(getDefault(key)); |
| 2234 |
} |
| 2235 |
catch (NumberFormatException e1) { |
| 2236 |
handleIntParseException(key, property, e1); |
| 2237 |
size = 0; |
| 2238 |
} |
| 2239 |
return size; |
| 2240 |
} |
| 2241 |
|
| 2242 |
private static void handleIntParseException(String key, String property, |
| 2243 |
NumberFormatException e1) { |
| 2244 |
Exception n = new Exception( |
| 2245 |
NLS |
| 2246 |
.bind( |
| 2247 |
"Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$ |
| 2248 |
key, property), e1); |
| 2249 |
n.printStackTrace(); |
| 2250 |
} |
| 2101 |
} |
2251 |
} |