|
Lines 40-53
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.Status; |
46 |
import org.eclipse.core.runtime.Status; |
| 46 |
import org.eclipse.core.runtime.jobs.ILock; |
47 |
import org.eclipse.core.runtime.jobs.ILock; |
| 47 |
import org.eclipse.core.runtime.jobs.Job; |
48 |
import org.eclipse.core.runtime.jobs.Job; |
|
|
49 |
import org.eclipse.core.runtime.preferences.ConfigurationScope; |
| 50 |
import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
| 51 |
import org.eclipse.core.runtime.preferences.IPreferencesService; |
| 52 |
import org.eclipse.core.runtime.preferences.IScopeContext; |
| 53 |
import org.eclipse.core.runtime.preferences.InstanceScope; |
| 54 |
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; |
| 48 |
import org.eclipse.jface.text.BadLocationException; |
55 |
import org.eclipse.jface.text.BadLocationException; |
| 49 |
import org.eclipse.jface.text.IDocument; |
56 |
import org.eclipse.jface.text.IDocument; |
| 50 |
import org.eclipse.jface.text.IRegion; |
57 |
import org.eclipse.jface.text.IRegion; |
|
|
58 |
import org.eclipse.osgi.util.NLS; |
| 51 |
import org.eclipse.text.edits.MultiTextEdit; |
59 |
import org.eclipse.text.edits.MultiTextEdit; |
| 52 |
import org.eclipse.text.edits.ReplaceEdit; |
60 |
import org.eclipse.text.edits.ReplaceEdit; |
| 53 |
import org.eclipse.text.edits.TextEdit; |
61 |
import org.eclipse.text.edits.TextEdit; |
|
Lines 94-99
Link Here
|
| 94 |
*/ |
102 |
*/ |
| 95 |
public class ModelManagerImpl implements IModelManager { |
103 |
public class ModelManagerImpl implements IModelManager { |
| 96 |
|
104 |
|
|
|
105 |
private static int WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); |
| 106 |
private static boolean ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); |
| 107 |
private static IEclipsePreferences.IPreferenceChangeListener LISTENER; |
| 108 |
static { |
| 109 |
InstanceScope scope = new InstanceScope(); |
| 110 |
IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); |
| 111 |
LISTENER = new IEclipsePreferences.IPreferenceChangeListener() { |
| 112 |
|
| 113 |
public void preferenceChange(PreferenceChangeEvent event) { |
| 114 |
|
| 115 |
if ("modelmanager.maxWaitDuringConcurrentLoad".equals(event.getKey())) { |
| 116 |
WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad"); |
| 117 |
} |
| 118 |
else if ("modelmanager.allowInterruptsDuringConcurrentLoad".equals(event.getKey())) { |
| 119 |
ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"); |
| 120 |
} |
| 121 |
} |
| 122 |
}; |
| 123 |
instancePrefs.addPreferenceChangeListener(LISTENER); |
| 124 |
} |
| 125 |
|
| 97 |
static class ReadEditType { |
126 |
static class ReadEditType { |
| 98 |
ReadEditType(String type) { |
127 |
ReadEditType(String type) { |
| 99 |
} |
128 |
} |
|
Lines 107-113
Link Here
|
| 107 |
int referenceCountForRead; |
136 |
int referenceCountForRead; |
| 108 |
IStructuredModel theSharedModel; |
137 |
IStructuredModel theSharedModel; |
| 109 |
boolean initializing = true; |
138 |
boolean initializing = true; |
| 110 |
boolean doWait = true; |
139 |
volatile boolean doWait = true; |
|
|
140 |
final Object loadCondition = new Object(); |
| 111 |
|
141 |
|
| 112 |
SharedObject(IStructuredModel sharedModel) { |
142 |
SharedObject(IStructuredModel sharedModel) { |
| 113 |
theSharedModel = sharedModel; |
143 |
theSharedModel = sharedModel; |
|
Lines 119-133
Link Here
|
| 119 |
* Waits until this shared object has been attempted to be loaded. |
149 |
* Waits until this shared object has been attempted to be loaded. |
| 120 |
* The load is "attempted" because not all loads result in a model. |
150 |
* The load is "attempted" because not all loads result in a model. |
| 121 |
* However, upon leaving this method, theShareModel variable |
151 |
* However, upon leaving this method, theShareModel variable |
| 122 |
* is up-to-date. |
152 |
* is up-to-date. Should not be called if holding a lock on this object. |
| 123 |
*/ |
153 |
*/ |
| 124 |
public synchronized void waitForLoadAttempt() { |
154 |
public void waitForLoadAttempt() { |
| 125 |
while(initializing) { |
155 |
synchronized(loadCondition) { |
| 126 |
try { |
156 |
long start = System.currentTimeMillis(); |
| 127 |
wait(); |
157 |
// Note: A WAIT_DELAY of 0 is infinite |
|
|
158 |
int maxTimeMs = Math.max(0, WAIT_DELAY); |
| 159 |
final int waitInterval = Math.min(250, maxTimeMs); |
| 160 |
boolean interrupted = false; |
| 161 |
while (initializing && maxTimeMs >= 0) { |
| 162 |
try { |
| 163 |
loadCondition.wait(waitInterval); |
| 164 |
maxTimeMs -= waitInterval; |
| 165 |
} |
| 166 |
catch (InterruptedException e) { |
| 167 |
interrupted = true; |
| 168 |
if (ALLOW_INTERRUPT_WAITING_THREAD) { |
| 169 |
break; |
| 170 |
} |
| 171 |
} |
| 128 |
} |
172 |
} |
| 129 |
catch (InterruptedException e) { |
173 |
if (initializing) { |
| 130 |
// ignore interruption! |
174 |
long totalWaitTime = System.currentTimeMillis() - start; |
|
|
175 |
if (interrupted) { |
| 176 |
throw new OperationCanceledException( |
| 177 |
"Waiting thread interrupted during simultenous model load. Load aborted. (Waited " |
| 178 |
+ totalWaitTime + "ms)"); |
| 179 |
} |
| 180 |
else { |
| 181 |
throw new OperationCanceledException( |
| 182 |
"Waiting thread timed-out during simultenous model load. Load aborted. (Waited " |
| 183 |
+ totalWaitTime + "ms)"); |
| 184 |
} |
| 185 |
} |
| 186 |
if (interrupted) { |
| 187 |
// Propagate (don't swallow) the interrupt |
| 188 |
Thread.currentThread().interrupt(); |
| 131 |
} |
189 |
} |
| 132 |
} |
190 |
} |
| 133 |
} |
191 |
} |
|
Lines 137-145
Link Here
|
| 137 |
* {@link #waitForLoadAttempt()} will proceed after this |
195 |
* {@link #waitForLoadAttempt()} will proceed after this |
| 138 |
* method returns. |
196 |
* method returns. |
| 139 |
*/ |
197 |
*/ |
| 140 |
public synchronized void setLoaded() { |
198 |
public void setLoaded() { |
| 141 |
initializing = false; |
199 |
synchronized(loadCondition) { |
| 142 |
notifyAll(); |
200 |
initializing = false; |
|
|
201 |
loadCondition.notifyAll(); |
| 202 |
} |
| 143 |
} |
203 |
} |
| 144 |
} |
204 |
} |
| 145 |
|
205 |
|
|
Lines 164-169
Link Here
|
| 164 |
return instance; |
224 |
return instance; |
| 165 |
} |
225 |
} |
| 166 |
|
226 |
|
|
|
227 |
public void removePreferenceListener() { |
| 228 |
InstanceScope scope = new InstanceScope(); |
| 229 |
IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID); |
| 230 |
instancePrefs.removePreferenceChangeListener(LISTENER); |
| 231 |
} |
| 232 |
|
| 167 |
/** |
233 |
/** |
| 168 |
* Our cache of managed objects |
234 |
* Our cache of managed objects |
| 169 |
*/ |
235 |
*/ |
|
Lines 181-189
Link Here
|
| 181 |
ModelManagerImpl() { |
247 |
ModelManagerImpl() { |
| 182 |
super(); |
248 |
super(); |
| 183 |
fManagedObjects = new HashMap(); |
249 |
fManagedObjects = new HashMap(); |
| 184 |
// To prevent deadlocks: always acquire multiple locks in this order: SYNC, sharedObject. |
250 |
/** |
| 185 |
// DO NOT acquire a SYNC within a sharedObject lock, unless you already own the SYNC lock |
251 |
* NOTES: To prevent deadlocks: always acquire multiple locks in this |
| 186 |
// Tip: Try to hold the smallest number of locks you can |
252 |
* order: SYNC->sharedObject->sharedObject.loadCondition DO NOT acquire a |
|
|
253 |
* SYNC within a sharedObject lock, unless you already own the SYNC lock |
| 254 |
* Tip: Try to hold the smallest number of locks you can |
| 255 |
*/ |
| 187 |
} |
256 |
} |
| 188 |
|
257 |
|
| 189 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
258 |
private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException { |
|
Lines 376-382
Link Here
|
| 376 |
} |
445 |
} |
| 377 |
|
446 |
|
| 378 |
private IStructuredModel _commonCreateModel(String id, IModelHandler handler, URIResolver resolver) throws ResourceInUse { |
447 |
private IStructuredModel _commonCreateModel(String id, IModelHandler handler, URIResolver resolver) throws ResourceInUse { |
| 379 |
|
|
|
| 380 |
IModelLoader loader = handler.getModelLoader(); |
448 |
IModelLoader loader = handler.getModelLoader(); |
| 381 |
IStructuredModel result = loader.createModel(); |
449 |
IStructuredModel result = loader.createModel(); |
| 382 |
// in the past, id was null for "unmanaged" case, so we won't |
450 |
// in the past, id was null for "unmanaged" case, so we won't |
|
Lines 1138-1147
Link Here
|
| 1138 |
// and return the object. |
1206 |
// and return the object. |
| 1139 |
SYNC.release(); |
1207 |
SYNC.release(); |
| 1140 |
doRelease=false; |
1208 |
doRelease=false; |
|
|
1209 |
if (sharedObject.doWait) { |
| 1210 |
sharedObject.waitForLoadAttempt(); |
| 1211 |
} |
| 1141 |
synchronized(sharedObject) { |
1212 |
synchronized(sharedObject) { |
| 1142 |
if (sharedObject.doWait) { |
|
|
| 1143 |
sharedObject.waitForLoadAttempt(); |
| 1144 |
} |
| 1145 |
if (sharedObject.theSharedModel!=null) { |
1213 |
if (sharedObject.theSharedModel!=null) { |
| 1146 |
_incrCount(sharedObject, EDIT); |
1214 |
_incrCount(sharedObject, EDIT); |
| 1147 |
} |
1215 |
} |
|
Lines 1220-1230
Link Here
|
| 1220 |
// and return the object. |
1288 |
// and return the object. |
| 1221 |
SYNC.release(); |
1289 |
SYNC.release(); |
| 1222 |
doRelease=false; |
1290 |
doRelease=false; |
| 1223 |
|
1291 |
if (sharedObject.doWait) { |
|
|
1292 |
sharedObject.waitForLoadAttempt(); |
| 1293 |
} |
| 1224 |
synchronized(sharedObject) { |
1294 |
synchronized(sharedObject) { |
| 1225 |
if (sharedObject.doWait) { |
|
|
| 1226 |
sharedObject.waitForLoadAttempt(); |
| 1227 |
} |
| 1228 |
if (sharedObject.theSharedModel!=null) { |
1295 |
if (sharedObject.theSharedModel!=null) { |
| 1229 |
_incrCount(sharedObject, READ); |
1296 |
_incrCount(sharedObject, READ); |
| 1230 |
} |
1297 |
} |
|
Lines 2073-2076
Link Here
|
| 2073 |
SYNC.release(); |
2140 |
SYNC.release(); |
| 2074 |
return inUse; |
2141 |
return inUse; |
| 2075 |
} |
2142 |
} |
|
|
2143 |
|
| 2144 |
private static String getProperty(String property) { |
| 2145 |
// Importance order is: |
| 2146 |
// default-default < instanceScope < configurationScope < systemProperty < envVar |
| 2147 |
String value=null; |
| 2148 |
|
| 2149 |
if (value == null) { |
| 2150 |
value = System.getenv(property); |
| 2151 |
} |
| 2152 |
if (value == null) { |
| 2153 |
value = System.getProperty(property); |
| 2154 |
} |
| 2155 |
if (value==null) { |
| 2156 |
IPreferencesService preferencesService = Platform.getPreferencesService(); |
| 2157 |
IScopeContext[] lookupOrder = new IScopeContext[] { |
| 2158 |
new ConfigurationScope(), new InstanceScope() |
| 2159 |
}; |
| 2160 |
String key = property; |
| 2161 |
if (property != null && property.startsWith(SSECorePlugin.ID)) { |
| 2162 |
// +1, include the "." |
| 2163 |
key = property.substring(SSECorePlugin.ID.length() + 1, property.length()); |
| 2164 |
} |
| 2165 |
preferencesService.getString(SSECorePlugin.ID, key, null, lookupOrder); |
| 2166 |
} |
| 2167 |
|
| 2168 |
return value; |
| 2169 |
} |
| 2170 |
|
| 2171 |
private static String getDefault(String property) { |
| 2172 |
// this is the "default-default" |
| 2173 |
if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) { |
| 2174 |
return "0"; |
| 2175 |
} |
| 2176 |
else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad" |
| 2177 |
.equals(property)) { |
| 2178 |
return "false"; |
| 2179 |
} |
| 2180 |
return null; |
| 2181 |
} |
| 2182 |
|
| 2183 |
private static boolean getBoolean(String key) { |
| 2184 |
String property = getProperty(key); |
| 2185 |
// if (property != null) { |
| 2186 |
// System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2187 |
// } |
| 2188 |
return property != null ? Boolean.parseBoolean(property) : Boolean |
| 2189 |
.parseBoolean(getDefault(key)); |
| 2190 |
} |
| 2191 |
|
| 2192 |
private static int getInt(String key) { |
| 2193 |
String property = getProperty(key); |
| 2194 |
int size = 0; |
| 2195 |
if (property != null) { |
| 2196 |
try { |
| 2197 |
size = Integer.parseInt(property); |
| 2198 |
// System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$ |
| 2199 |
} |
| 2200 |
catch (NumberFormatException e) { |
| 2201 |
size = getDefaultInt(key, property, size); |
| 2202 |
} |
| 2203 |
} |
| 2204 |
else { |
| 2205 |
size = getDefaultInt(key, property, size); |
| 2206 |
} |
| 2207 |
return size; |
| 2208 |
} |
| 2209 |
|
| 2210 |
private static int getDefaultInt(String key, String property, int size) { |
| 2211 |
// ignored |
| 2212 |
try { |
| 2213 |
size = Integer.parseInt(getDefault(key)); |
| 2214 |
} |
| 2215 |
catch (NumberFormatException e1) { |
| 2216 |
handleIntParseException(key, property, e1); |
| 2217 |
size = 0; |
| 2218 |
} |
| 2219 |
return size; |
| 2220 |
} |
| 2221 |
|
| 2222 |
private static void handleIntParseException(String key, String property, |
| 2223 |
NumberFormatException e1) { |
| 2224 |
Exception n = new Exception( |
| 2225 |
NLS |
| 2226 |
.bind( |
| 2227 |
"Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$ |
| 2228 |
key, property), e1); |
| 2229 |
n.printStackTrace(); |
| 2230 |
} |
| 2076 |
} |
2231 |
} |