Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 287096 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/wst/sse/core/internal/SSECorePlugin.java (+4 lines)
Lines 16-21 Link Here
16
import org.eclipse.core.runtime.Preferences;
16
import org.eclipse.core.runtime.Preferences;
17
import org.eclipse.wst.sse.core.StructuredModelManager;
17
import org.eclipse.wst.sse.core.StructuredModelManager;
18
import org.eclipse.wst.sse.core.internal.encoding.CommonEncodingPreferenceNames;
18
import org.eclipse.wst.sse.core.internal.encoding.CommonEncodingPreferenceNames;
19
import org.eclipse.wst.sse.core.internal.model.ModelManagerImpl;
19
import org.eclipse.wst.sse.core.internal.modelhandler.ModelHandlerRegistry;
20
import org.eclipse.wst.sse.core.internal.modelhandler.ModelHandlerRegistry;
20
import org.eclipse.wst.sse.core.internal.preferences.CommonModelPreferenceNames;
21
import org.eclipse.wst.sse.core.internal.preferences.CommonModelPreferenceNames;
21
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
22
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
Lines 62-71 Link Here
62
	public void stop(BundleContext context) throws Exception {
63
	public void stop(BundleContext context) throws Exception {
63
		savePluginPreferences();
64
		savePluginPreferences();
64
		
65
		
66
		((ModelManagerImpl) ModelManagerImpl.getInstance()).removePreferenceListener();
67
65
		TaskScanningScheduler.shutdown();
68
		TaskScanningScheduler.shutdown();
66
69
67
		FileBufferModelManager.shutdown();
70
		FileBufferModelManager.shutdown();
68
71
72
69
		super.stop(context);
73
		super.stop(context);
70
	}
74
	}
71
75
(-)src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java (-655 / +1084 lines)
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.service.runnable.ParameterizedRunnable;
61
import org.eclipse.osgi.util.NLS;
53
import org.eclipse.text.edits.MultiTextEdit;
62
import org.eclipse.text.edits.MultiTextEdit;
54
import org.eclipse.text.edits.ReplaceEdit;
63
import org.eclipse.text.edits.ReplaceEdit;
55
import org.eclipse.text.edits.TextEdit;
64
import org.eclipse.text.edits.TextEdit;
Lines 83-143 Link Here
83
import org.eclipse.wst.sse.core.internal.util.Utilities;
92
import org.eclipse.wst.sse.core.internal.util.Utilities;
84
93
85
/**
94
/**
86
 * Not intended to be subclassed, referenced or instantiated by clients.
95
 * This class is not intended to be: sub-classed, referenced or instantiated by
96
 * clients.
87
 * 
97
 * 
88
 * This class is responsible for creating, retrieving, and caching
98
 * This class is responsible for creating, retrieving, and caching
89
 * StructuredModels It retrieves the cached objects by an id which is
99
 * StructuredModels It retrieves the cached objects by an id which is typically
90
 * typically a String representing the resources URI. Note: Its important that
100
 * a String representing the resources URI. Note: Its important that all clients
91
 * all clients that share a resource do so using <b>identical </b>
101
 * that share a resource do so using <b>identical </b> identifiers, or else
92
 * identifiers, or else different instances will be created and retrieved,
102
 * different instances will be created and retrieved, even if they all
93
 * even if they all technically point to the same resource on the file system.
103
 * technically point to the same resource on the file system. This class also
94
 * This class also provides a convenient place to register Model Loaders and
104
 * provides a convenient place to register Model Loaders and Dumpers based on
95
 * Dumpers based on 'type'.
105
 * 'type'.
96
 */
106
 */
97
public class ModelManagerImpl implements IModelManager {
107
public class ModelManagerImpl implements IModelManager {
98
108
99
	static class ReadEditType {
109
	private static int WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad");
100
		ReadEditType(String type) {
110
	private static boolean ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad");
111
	private static IEclipsePreferences.IPreferenceChangeListener LISTENER;
112
	static {
113
		InstanceScope scope = new InstanceScope();
114
		IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID);
115
		LISTENER = new IEclipsePreferences.IPreferenceChangeListener() {
116
117
					public void preferenceChange(PreferenceChangeEvent event) {
118
119
				if ("modelmanager.maxWaitDuringConcurrentLoad".equals(event.getKey())) {
120
					WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad");
121
				}
122
				else if ("modelmanager.allowInterruptsDuringConcurrentLoad".equals(event.getKey())) {
123
					ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad");
124
				}
125
			}
126
		};
127
		instancePrefs.addPreferenceChangeListener(LISTENER);
128
	}
129
130
	class FileLoader implements ParameterizedRunnable {
131
		private final IFile file;
132
		private final String id;
133
		private final IModelHandler handler;
134
		private final URIResolver resolver;
135
		private final ReadEditType rwType;
136
		private final EncodingRule encodingRule;
137
138
		public FileLoader(IFile file, String id, IModelHandler handler, URIResolver resolver,
139
				ReadEditType rwType, EncodingRule encodingRule) {
140
			this.file = file;
141
			this.id = id;
142
			this.handler = handler;
143
			this.resolver = resolver;
144
			this.rwType = rwType;
145
			this.encodingRule = encodingRule;
146
147
		}
148
149
		public Object run(Object context) throws Exception {
150
			SharedObject sharedObject = (SharedObject) context;
151
			_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule, sharedObject);
152
			return null;
153
		}
154
	}
155
156
	class InputStreamLoader implements ParameterizedRunnable {
157
158
		private final InputStream inputStream;
159
		private final String id;
160
		private final IModelHandler handler;
161
		private final URIResolver resolver;
162
		private final ReadEditType rwType;
163
		private final String encoding;
164
		private final String lineDelimiter;
165
166
		public InputStreamLoader(InputStream inputStream, String id, IModelHandler handler,
167
				URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter) {
168
			this.inputStream = inputStream;
169
			this.id = id;
170
			this.handler = handler;
171
			this.resolver = resolver;
172
			this.rwType = rwType;
173
			this.encoding = encoding;
174
			this.lineDelimiter = lineDelimiter;
175
		}
176
177
		public Object run(Object context) throws Exception {
178
			SharedObject sharedObject = (SharedObject) context;
179
			_doCommonCreateModel(inputStream, id, handler, resolver, rwType, encoding,
180
					lineDelimiter, sharedObject);
181
			return null;
182
		}
183
	}
184
185
	class FileBufferDocumentLoader implements ParameterizedRunnable {
186
		private final IStructuredDocument document;
187
		private final ReadEditType rwType;
188
189
		public FileBufferDocumentLoader(IStructuredDocument document, ReadEditType rwType) {
190
			this.document = document;
191
			this.rwType = rwType;
192
		}
193
194
		public Object run(Object context) throws Exception {
195
			SharedObject sharedObject = (SharedObject) context;
196
			synchronized (sharedObject.loadLock) {
197
				IStructuredModel model = FileBufferModelManager.getInstance().getModel(document);
198
				synchronized (sharedObject) {
199
					sharedObject.theSharedModel = model;
200
					_initCount(sharedObject, rwType);
201
					sharedObject.setLoaded();
202
				}
203
			}
204
			return null;
205
		}
206
	}
207
208
	class FileBufferIFileLoader implements ParameterizedRunnable {
209
210
		private final IFile file;
211
		private final String id;
212
		private final ReadEditType rwType;
213
214
		public FileBufferIFileLoader(IFile file, String id, ReadEditType rwType) {
215
			this.file = file;
216
			this.id = id;
217
			this.rwType = rwType;
218
219
		}
220
221
		public Object run(Object context) throws Exception {
222
			SharedObject sharedObject = (SharedObject) context;
223
			_doCommonGetModel(file, id, sharedObject, rwType);
224
			return null;
101
		}
225
		}
102
	}
226
	}
103
227
228
	static class ReadEditType {
229
		ReadEditType(String type) {}
230
	}
231
104
	/**
232
	/**
105
	 * A Data class to track our shared objects
233
	 * A Data class to track our shared objects
106
	 */
234
	 */
107
	 static class SharedObject {
235
	static class SharedObject {
108
		int referenceCountForEdit;
236
		int referenceCountForEdit;
109
		int referenceCountForRead;
237
		int referenceCountForRead;
110
		IStructuredModel theSharedModel;
238
		IStructuredModel theSharedModel;
111
		boolean initializing = true;
239
		boolean initializing = true;
112
		boolean doWait = true;
240
		volatile boolean doWait = true;
113
		
241
		final Object loadLock = new Object();
242
114
		SharedObject(IStructuredModel sharedModel) {
243
		SharedObject(IStructuredModel sharedModel) {
115
			theSharedModel = sharedModel;
244
			theSharedModel = sharedModel;
116
			referenceCountForRead = 0;
245
			referenceCountForRead = 0;
117
			referenceCountForEdit = 0;
246
			referenceCountForEdit = 0;
118
		}
247
		}
119
		
248
120
		/**
249
		/**
121
		 * Waits until this shared object has been attempted to be loaded. 
250
		 * Waits until this shared object has been attempted to be loaded. The
122
		 * The load is "attempted" because not all loads result in a model. 
251
		 * load is "attempted" because not all loads result in a model. However,
123
		 * However, upon leaving this method, theShareModel variable
252
		 * upon leaving this method, theShareModel variable is up-to-date.
124
		 * is up-to-date.
125
		 */
253
		 */
126
		public synchronized void waitForLoadAttempt() {
254
		public synchronized void waitForLoadAttempt() {
127
			while(initializing) {
255
			long start = System.currentTimeMillis();
256
			// Note: A WAIT_DELAY of 0 is infinite
257
			int maxTimeMs = Math.max(0, WAIT_DELAY);
258
			final int waitInterval = Math.min(250, maxTimeMs);
259
			boolean interrupted = false;
260
			while (initializing && maxTimeMs >= 0) {
128
				try {
261
				try {
129
					wait();
262
					wait(waitInterval);
263
					maxTimeMs -= waitInterval;
130
				}
264
				}
131
				catch (InterruptedException e) {
265
				catch (InterruptedException e) {
132
					// ignore interruption!
266
					interrupted = true;
267
					if (ALLOW_INTERRUPT_WAITING_THREAD) {
268
						break;
269
					}
133
				}
270
				}
134
			}
271
			}
272
			if (initializing) {
273
				long totalWaitTime = System.currentTimeMillis() - start;
274
				if (interrupted) {
275
					throw new OperationCanceledException(
276
							"Waiting thread interrupted during simultenous model load. Load aborted. (Waited "
277
									+ totalWaitTime + "ms)");
278
				}
279
				else {
280
					throw new OperationCanceledException(
281
							"Waiting thread timed-out during simultenous model load. Load aborted. (Waited "
282
									+ totalWaitTime + "ms)");
283
				}
284
			}
285
			if (interrupted) {
286
				// Propagate (don't swallow) the interrupt
287
				Thread.currentThread().interrupt();
288
			}
135
		}
289
		}
136
		
290
137
		/**
291
		/**
138
		 * Flags this model as loaded. All waiting methods on 
292
		 * Flags this model as loaded. All waiting methods on
139
		 * {@link #waitForLoadAttempt()} will proceed after this 
293
		 * {@link #waitForLoadAttempt()} will proceed after this method returns.
140
		 * method returns. 
141
		 */
294
		 */
142
		public synchronized void setLoaded() {
295
		public synchronized void setLoaded() {
143
			initializing = false;
296
			initializing = false;
Lines 150-156 Link Here
150
	/**
303
	/**
151
	 * Our singleton instance
304
	 * Our singleton instance
152
	 */
305
	 */
153
	private static ModelManagerImpl instance;
306
	private static LotsOfEditsModelManager instance;
154
	private final static int READ_BUFFER_SIZE = 4096;
307
	private final static int READ_BUFFER_SIZE = 4096;
155
308
156
	/**
309
	/**
Lines 161-171 Link Here
161
	public synchronized static IModelManager getInstance() {
314
	public synchronized static IModelManager getInstance() {
162
315
163
		if (instance == null) {
316
		if (instance == null) {
164
			instance = new ModelManagerImpl();
317
			instance = new LotsOfEditsModelManager();
165
		}
318
		}
166
		return instance;
319
		return instance;
167
	}
320
	}
168
321
322
	public void removePreferenceListener() {
323
		InstanceScope scope = new InstanceScope();
324
		IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID);
325
		instancePrefs.removePreferenceChangeListener(LISTENER);
326
	}
327
169
	/**
328
	/**
170
	 * Our cache of managed objects
329
	 * Our cache of managed objects
171
	 */
330
	 */
Lines 174-181 Link Here
174
	private ModelHandlerRegistry fModelHandlerRegistry;
333
	private ModelHandlerRegistry fModelHandlerRegistry;
175
	private final ReadEditType READ = new ReadEditType("read"); //$NON-NLS-1$
334
	private final ReadEditType READ = new ReadEditType("read"); //$NON-NLS-1$
176
	private final ReadEditType EDIT = new ReadEditType("edit"); //$NON-NLS-1$
335
	private final ReadEditType EDIT = new ReadEditType("edit"); //$NON-NLS-1$
177
	
336
178
	private final ILock SYNC = Job.getJobManager().newLock();
337
	private final ILock SYNC = Job.getJobManager().newLock();
338
179
	/**
339
	/**
180
	 * Intentionally default access only.
340
	 * Intentionally default access only.
181
	 * 
341
	 * 
Lines 183-257 Link Here
183
	ModelManagerImpl() {
343
	ModelManagerImpl() {
184
		super();
344
		super();
185
		fManagedObjects = new HashMap();
345
		fManagedObjects = new HashMap();
186
		// To prevent deadlocks:  always acquire multiple locks in this order: SYNC, sharedObject. 
346
		/**
187
		// DO NOT acquire a SYNC within a sharedObject lock, unless you already own the SYNC lock
347
		 * NOTES: To prevent deadlocks: always acquire multiple locks in this
188
		// Tip: Try to hold the smallest number of locks you can
348
		 * order: SYNC->sharedObject.loadLock->sharedObject DO NOT acquire a
349
		 * SYNC within a sharedObject lock, unless you already own the SYNC lock
350
		 * Tip: Try to hold the smallest number of locks you can
351
		 */
189
	}
352
	}
190
353
191
	private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule) throws IOException,CoreException {
354
	private IStructuredModel doLoad(String id, ReadEditType rwType, ParameterizedRunnable loader)
355
			throws CoreException, IOException {
192
		SharedObject sharedObject = null;
356
		SharedObject sharedObject = null;
193
		
357
194
		SYNC.acquire();
358
		SYNC.acquire();
195
		sharedObject = (SharedObject) fManagedObjects.get(id);
359
		try {
196
		SYNC.release();
360
			sharedObject = (SharedObject) fManagedObjects.get(id);
197
		
361
		}
198
		while(true) {
362
		finally {
199
			if (sharedObject!=null) {
363
			SYNC.release();
364
		}
365
366
		while (true) {
367
			if (sharedObject != null) {
200
				sharedObject.waitForLoadAttempt();
368
				sharedObject.waitForLoadAttempt();
201
			}
369
			}
370
			boolean createModel = false;
202
			SYNC.acquire();
371
			SYNC.acquire();
203
			// we know this object's model has passed the load, however, we don't know 
372
			try {
204
			// it's reference count status. It might have already been disposed. Or it could have 
373
				// we know this object's model has passed the load, however, we
205
			// been disposed and a concurrent thread has already begun loading it, in which case
374
				// don't know it's reference count status. It might have already
206
			// we should use the sharedobject they are loading. 
375
				// been disposed. Or it could have been disposed and a
207
			// NOTE: This pattern is applied 3 times in this class, but only doc'd once. The logic is 
376
				// concurrent thread has already begun
208
			// exactly the same. 
377
				// loading it, in which case we should use the SharedObject they
209
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
378
				// are loading.
210
			if (testObject==null) {
379
211
				// null means it's been disposed, we need to do the work to reload it.
380
				SharedObject testObject = (SharedObject) fManagedObjects.get(id);
212
				sharedObject = new SharedObject(null);
381
				if (testObject == null) {
213
				fManagedObjects.put(id, sharedObject);
382
					// null means it's been disposed, we need to do the work to
214
				SYNC.release();
383
					// reload it.
215
				_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule,
384
					sharedObject = new SharedObject(null);
216
						sharedObject);
385
					fManagedObjects.put(id, sharedObject);
217
				break;
386
					createModel = true;
218
			} else if (sharedObject == testObject) {
387
					break;
219
				// if nothing happened, just increment the could and return the shared model
388
				}
220
				synchronized(sharedObject) {
389
				else if (sharedObject == testObject) {
221
					if (sharedObject.theSharedModel!=null) {
390
					// if nothing happened, just increment the could and return
222
						_incrCount(sharedObject, rwType);
391
					// the shared model
392
					synchronized (sharedObject) {
393
						Assert.isTrue(sharedObject.referenceCountForEdit
394
								+ sharedObject.referenceCountForRead > 0);
395
						if (sharedObject.theSharedModel != null) {
396
							_incrCount(sharedObject, rwType);
397
						}
223
					}
398
					}
399
					break;
224
				}
400
				}
401
				else {
402
					// sharedObject != testObject which means the object we were
403
					// waiting on has been disposed a replacement has already
404
					// been placed in the managedObjects table. Through away our
405
					// stale sharedObject and continue on with the one we got
406
					// from the queue. Note: We don't know its state, so
407
					// continue the waitForLoad-check loop.
408
					sharedObject = testObject;
409
				}
410
			}
411
			finally {
225
				SYNC.release();
412
				SYNC.release();
226
				break;
413
				if (createModel) {
227
			} else {
414
					try {
228
				// sharedObject != testObject which means the object we were waiting on has been disposed
415
						loader.run(sharedObject);
229
				// a replacement has already been placed in the managedObjects table. Through away our
416
					}
230
				// stale sharedObject and continue on with the one we got from the queue. Note: We don't know its
417
					catch (CoreException e) {
231
				// state, so continue the waitForLoad-check loop. 
418
						// rethrow, since the exception came from the loader's
232
				SYNC.release();
419
						throw e;
233
				sharedObject = testObject;
420
					}
421
					catch (IOException e) {
422
						// rethrow, since the exception came from the loader
423
						throw e;
424
					}
425
					catch (Exception e) {
426
						// log this unspecified exception
427
						Logger.logException("Exception during load of model", e);
428
					}
429
				}
234
			}
430
			}
235
		}
431
		}
236
		
432
237
		// we expect to always return something
433
		// we expect to always return something
238
		if (sharedObject == null) {
434
		if (sharedObject == null) {
239
			debugException = new Exception("instance only for stack trace"); //$NON-NLS-1$
435
			debugException = new Exception("instance only for stack trace"); //$NON-NLS-1$
240
			Logger.logException("Program Error: no model recorded for id " + id, debugException); //$NON-NLS-1$
436
			Logger.logException("Program Error: no model recorded for id " + id, debugException); //$NON-NLS-1$
241
		}
437
		}
242
		
438
243
		// note: clients must call release for each time they call get.
439
		// note: clients must call release for each time they call get.
244
		return sharedObject==null ? null : sharedObject.theSharedModel;
440
		return sharedObject == null ? null : sharedObject.theSharedModel;
441
	}
442
443
	private IStructuredModel _commonCreateModel(IFile file, String id, IModelHandler handler,
444
			URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule)
445
			throws IOException, CoreException {
446
		FileLoader loader = new FileLoader(file, id, handler, resolver, rwType, encodingRule);
447
		return doLoad(id, rwType, loader);
245
	}
448
	}
246
449
247
	private void _decrCount(SharedObject sharedObject, ReadEditType type) {
450
	private void _decrCount(SharedObject sharedObject, ReadEditType type) {
248
		if (type == READ) {
451
		if (type == READ) {
249
			sharedObject.referenceCountForRead--;
452
			sharedObject.referenceCountForRead--;
250
			FileBufferModelManager.getInstance().disconnect(sharedObject.theSharedModel.getStructuredDocument());
453
			FileBufferModelManager.getInstance().disconnect(
454
					sharedObject.theSharedModel.getStructuredDocument());
251
		}
455
		}
252
		else if (type == EDIT) {
456
		else if (type == EDIT) {
253
			sharedObject.referenceCountForEdit--;
457
			sharedObject.referenceCountForEdit--;
254
			FileBufferModelManager.getInstance().disconnect(sharedObject.theSharedModel.getStructuredDocument());
458
			FileBufferModelManager.getInstance().disconnect(
459
					sharedObject.theSharedModel.getStructuredDocument());
255
		}
460
		}
256
		else
461
		else
257
			throw new IllegalArgumentException();
462
			throw new IllegalArgumentException();
Lines 261-270 Link Here
261
			URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule,
466
			URIResolver resolver, ReadEditType rwType, EncodingRule encodingRule,
262
			SharedObject sharedObject) throws CoreException, IOException {
467
			SharedObject sharedObject) throws CoreException, IOException {
263
		// XXX: Does not integrate with FileBuffers
468
		// XXX: Does not integrate with FileBuffers
264
		boolean doRemove = false;
469
		IStructuredModel model = null;
265
		synchronized(sharedObject) {
470
		synchronized (sharedObject.loadLock) {
266
			InputStream inputStream = null;
471
			InputStream inputStream = null;
267
			IStructuredModel model = null;
472
268
			try {
473
			try {
269
				model = _commonCreateModel(id, handler, resolver);
474
				model = _commonCreateModel(id, handler, resolver);
270
				IModelLoader loader = handler.getModelLoader();
475
				IModelLoader loader = handler.getModelLoader();
Lines 274-362 Link Here
274
			catch (ResourceInUse e) {
479
			catch (ResourceInUse e) {
275
				// impossible, since we've already found
480
				// impossible, since we've already found
276
				handleProgramError(e);
481
				handleProgramError(e);
277
			} finally {
482
			}
278
				if (inputStream!=null) {
483
			finally {
279
					try { 
484
				if (inputStream != null) {
485
					try {
280
						inputStream.close();
486
						inputStream.close();
281
					} catch(IOException e) {
282
					}
487
					}
488
					catch (IOException e) {}
283
				}
489
				}
284
			}
490
			}
285
			if (model != null) {
491
			if (model != null) {
286
				// add to our cache
492
				synchronized (sharedObject) {
287
				sharedObject.theSharedModel=model;
493
					// add to our cache
288
				_initCount(sharedObject, rwType);
494
					sharedObject.theSharedModel = model;
289
			} else {
495
					_initCount(sharedObject, rwType);
290
				doRemove = true;
496
				}
291
			}
497
			}
292
		}
498
		}
293
		if (doRemove) {
499
		if (model == null) {
294
			SYNC.acquire();	
500
			SYNC.acquire();
295
			fManagedObjects.remove(id);	
501
			try {
296
			SYNC.release();
502
				fManagedObjects.remove(id);
503
			}
504
			finally {
505
				SYNC.release();
506
			}
297
		}
507
		}
298
		sharedObject.setLoaded();
508
		sharedObject.setLoaded();
299
	}
509
	}
300
510
301
	private IStructuredModel _commonCreateModel(InputStream inputStream, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter) throws IOException {
511
	private IStructuredModel _commonCreateModel(InputStream inputStream, String id,
302
		
512
			IModelHandler handler, URIResolver resolver, ReadEditType rwType, String encoding,
303
		if (id == null) {
513
			String lineDelimiter) throws IOException {
304
			throw new IllegalArgumentException("Program Error: id may not be null"); //$NON-NLS-1$
514
		org.eclipse.core.runtime.Assert.isLegal(id != null, "Program Error: id may not be null"); //$NON-NLS-1$
515
516
		InputStreamLoader loader = new InputStreamLoader(inputStream, id, handler, resolver,
517
				rwType, encoding, lineDelimiter);
518
		try {
519
			return doLoad(id, rwType, loader);
305
		}
520
		}
306
		SharedObject sharedObject = null;
521
		catch (CoreException e) {
307
	
522
			// This CoreException is a least-common-denominator side effect. The
308
		SYNC.acquire();
523
			// loader needs to call methods that sometimes return CoreException.
309
		sharedObject = (SharedObject) fManagedObjects.get(id);
524
			// However, the CoreException is only possible if it is invoked via
310
		SYNC.release();
525
			// FileLoader.
311
		
526
			return null;
312
		while(true) {
313
			if (sharedObject!=null) {
314
				sharedObject.waitForLoadAttempt();
315
			}
316
			SYNC.acquire();
317
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
318
			if (testObject==null) {
319
				// it was removed ,so lets create it
320
				sharedObject = new SharedObject(null);
321
				fManagedObjects.put(id, sharedObject);
322
				SYNC.release();
323
				_doCommonCreateModel(inputStream, id, handler, resolver, rwType,
324
						encoding, lineDelimiter, sharedObject);
325
				break;
326
			} else if (sharedObject == testObject) {
327
				synchronized(sharedObject) {
328
					if (sharedObject.theSharedModel!=null) {
329
						_incrCount(sharedObject, rwType);
330
					}
331
				}
332
				SYNC.release();
333
				break;
334
			} else {
335
				SYNC.release();
336
				sharedObject = testObject;
337
			}
338
		}
527
		}
339
		
340
		// we expect to always return something
341
		Assert.isNotNull(sharedObject, "Program Error: no model recorded for id " + id); //$NON-NLS-1$
342
		// note: clients must call release for each time they call get.
343
		return sharedObject.theSharedModel;
344
	
345
	}
528
	}
346
529
347
	private void _doCommonCreateModel(InputStream inputStream, String id, IModelHandler handler,
530
	private void _doCommonCreateModel(InputStream inputStream, String id, IModelHandler handler,
348
			URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter,
531
			URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter,
349
			SharedObject sharedObject) throws IOException {
532
			SharedObject sharedObject) throws IOException {
350
		boolean doRemove = false;
533
		IStructuredModel model = null;
351
		synchronized(sharedObject) {
534
		synchronized (sharedObject.loadLock) {
352
			IStructuredModel model = null;
535
353
			try {
536
			try {
354
				model = _commonCreateModel(id, handler, resolver);
537
				model = _commonCreateModel(id, handler, resolver);
355
				IModelLoader loader = handler.getModelLoader();
538
				IModelLoader loader = handler.getModelLoader();
356
				if (inputStream == null) {
539
				if (inputStream == null) {
357
					Logger.log(Logger.WARNING, "model was requested for id " + id + " without a content InputStream"); //$NON-NLS-1$ //$NON-NLS-2$
540
					Logger.log(Logger.WARNING,
541
							"model was requested for id " + id + " without a content InputStream"); //$NON-NLS-1$ //$NON-NLS-2$
358
				}
542
				}
359
				loader.load(id, Utilities.getMarkSupportedStream(inputStream), model, encoding, lineDelimiter);
543
				loader.load(id, Utilities.getMarkSupportedStream(inputStream), model, encoding,
544
						lineDelimiter);
360
			}
545
			}
361
			catch (ResourceInUse e) {
546
			catch (ResourceInUse e) {
362
				// impossible, since we've already found
547
				// impossible, since we've already found
Lines 366-402 Link Here
366
				/**
551
				/**
367
				 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=264228
552
				 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=264228
368
				 * 
553
				 * 
369
				 * Ensure that the content type identifier field of the model
554
				 * Ensure that the content type identifier field of the model is
370
				 * is properly set. This is normally handled by the
555
				 * properly set. This is normally handled by the
371
				 * FileBufferModelManager when working with files as it knows
556
				 * FileBufferModelManager when working with files as it knows
372
				 * the content type in advance; here is where we handle it for
557
				 * the content type in advance; here is where we handle it for
373
				 * streams.
558
				 * streams.
374
				 */
559
				 */
375
				if (model instanceof AbstractStructuredModel) {
560
				if (model instanceof AbstractStructuredModel) {
376
					DocumentReader reader = new DocumentReader(model.getStructuredDocument());
561
					DocumentReader reader = new DocumentReader(model.getStructuredDocument());
377
					IContentDescription description = Platform.getContentTypeManager().getDescriptionFor(reader, id, new QualifiedName[0]);
562
					IContentDescription description = Platform.getContentTypeManager()
563
							.getDescriptionFor(reader, id, new QualifiedName[0]);
378
					reader.close();
564
					reader.close();
379
					if (description != null && description.getContentType() != null) {
565
					if (description != null && description.getContentType() != null) {
380
						((AbstractStructuredModel) model).setContentTypeIdentifier(description.getContentType().getId());
566
						((AbstractStructuredModel) model).setContentTypeIdentifier(description
567
								.getContentType().getId());
381
					}
568
					}
382
				}
569
				}
383
570
				synchronized (sharedObject) {
384
				sharedObject.theSharedModel = model;
571
					sharedObject.theSharedModel = model;
385
				_initCount(sharedObject, rwType);
572
					_initCount(sharedObject, rwType);
386
			} else {
573
				}
387
				doRemove = true;
388
			}
574
			}
389
		}
575
		}
390
		if (doRemove) {
576
		if (model == null) {
391
			SYNC.acquire();
577
			SYNC.acquire();
392
			// remove it if we didn't get one back
578
			try {
393
			fManagedObjects.remove(id);
579
				// remove it if we didn't get one back
394
			SYNC.release();
580
				fManagedObjects.remove(id);
581
			}
582
			finally {
583
				SYNC.release();
584
			}
395
		}
585
		}
396
		sharedObject.setLoaded();
586
		sharedObject.setLoaded();
397
	}
587
	}
398
588
399
	private IStructuredModel _commonCreateModel(String id, IModelHandler handler, URIResolver resolver) throws ResourceInUse {
589
	private IStructuredModel _commonCreateModel(String id, IModelHandler handler,
590
			URIResolver resolver) throws ResourceInUse {
400
591
401
		IModelLoader loader = handler.getModelLoader();
592
		IModelLoader loader = handler.getModelLoader();
402
		IStructuredModel result = loader.createModel();
593
		IStructuredModel result = loader.createModel();
Lines 417-423 Link Here
417
		return result;
608
		return result;
418
	}
609
	}
419
610
420
	private IStructuredModel _commonGetModel(IFile iFile, ReadEditType rwType, EncodingRule encodingRule) throws UnsupportedEncodingException, IOException, CoreException {
611
	private IStructuredModel _commonGetModel(IFile iFile, ReadEditType rwType,
612
			EncodingRule encodingRule) throws UnsupportedEncodingException, IOException,
613
			CoreException {
421
		IStructuredModel model = null;
614
		IStructuredModel model = null;
422
615
423
		if (iFile != null && iFile.exists()) {
616
		if (iFile != null && iFile.exists()) {
Lines 430-517 Link Here
430
		return model;
623
		return model;
431
	}
624
	}
432
625
433
	private IStructuredModel _commonGetModel(IFile iFile, ReadEditType rwType, String encoding, String lineDelimiter) throws UnsupportedEncodingException, IOException, CoreException {
626
	private IStructuredModel _commonGetModel(IFile iFile, ReadEditType rwType, String encoding,
627
			String lineDelimiter) throws UnsupportedEncodingException, IOException, CoreException {
434
		String id = calculateId(iFile);
628
		String id = calculateId(iFile);
435
		IModelHandler handler = calculateType(iFile);
629
		IModelHandler handler = calculateType(iFile);
436
		URIResolver resolver = calculateURIResolver(iFile);
630
		URIResolver resolver = calculateURIResolver(iFile);
437
		IStructuredModel model = _commonGetModel(iFile, id, handler, resolver, rwType, encoding, lineDelimiter);
631
		IStructuredModel model = _commonGetModel(iFile, id, handler, resolver, rwType, encoding,
632
				lineDelimiter);
438
633
439
		return model;
634
		return model;
440
	}
635
	}
441
636
442
	private IStructuredModel _commonGetModel(IFile file, String id, IModelHandler handler, URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter) throws IOException, CoreException {
637
	private IStructuredModel _commonGetModel(IFile file, String id, IModelHandler handler,
443
		if (id == null)
638
			URIResolver resolver, ReadEditType rwType, String encoding, String lineDelimiter)
444
			throw new IllegalArgumentException("Program Error: id may not be null"); //$NON-NLS-1$
639
			throws IOException, CoreException {
640
		org.eclipse.core.runtime.Assert.isLegal(id != null, "Program Error: id may not be null"); //$NON-NLS-1$
445
641
446
		SharedObject sharedObject = null;
447
		if (file != null && file.exists()) {
642
		if (file != null && file.exists()) {
448
			SYNC.acquire();
643
			FileBufferIFileLoader loader = new FileBufferIFileLoader(file, id, rwType);
449
			sharedObject = (SharedObject) fManagedObjects.get(id);
644
			return doLoad(id, rwType, loader);
450
			SYNC.release();
451
			
452
			while(true) {
453
				if (sharedObject!=null) {
454
					sharedObject.waitForLoadAttempt();
455
				}
456
				SYNC.acquire();
457
				SharedObject testObject = (SharedObject) fManagedObjects.get(id);
458
				if (testObject==null) {
459
					// it was removed ,so lets create it
460
					sharedObject = new SharedObject(null);
461
					fManagedObjects.put(id, sharedObject);
462
					
463
					SYNC.release();
464
					_doCommonGetModel(file, id, sharedObject,rwType);
465
					break;
466
				} else if (sharedObject == testObject) {
467
					synchronized(sharedObject) {
468
						if (sharedObject.theSharedModel!=null) {
469
							_incrCount(sharedObject, rwType);
470
						}
471
					}
472
					SYNC.release();
473
					break;
474
				} else {
475
					// we got a different object than what we were expecting
476
					SYNC.release();
477
					// two threads were interested in models for the same id. 
478
					// The other thread one, so lets back off and try again. 
479
					sharedObject = testObject; 
480
				}
481
			}
482
		}
645
		}
483
		
646
484
		// if we don't know how to create a model
647
		return null;
485
		// for this type of file, return null
648
	}
486
	
649
487
		// note: clients must call release for each time they call
650
	private void _doCommonGetModel(IFile file, String id, SharedObject sharedObject,
488
		// get.
651
			ReadEditType rwType) {
489
			
652
490
		return sharedObject==null ? null : sharedObject.theSharedModel;
653
		IStructuredModel model = null;
491
	}
654
		synchronized (sharedObject.loadLock) {
492
655
			sharedObject.doWait = false;
493
	private void _doCommonGetModel(IFile file, String id, SharedObject sharedObject,ReadEditType rwType) {
656
			try {
494
		boolean doRemove = false;
657
				model = FileBufferModelManager.getInstance().getModel(file);
495
		synchronized(sharedObject) {
658
			}
496
			sharedObject.doWait=false;
659
			finally {
497
			IStructuredModel model = FileBufferModelManager.getInstance().getModel(file);
660
				sharedObject.doWait = true;
498
			sharedObject.doWait=true;
661
			}
499
			if (model != null) {
662
			if (model != null) {
500
				sharedObject.theSharedModel=model;
663
				synchronized (sharedObject) {
501
				_initCount(sharedObject, rwType);
664
					sharedObject.theSharedModel = model;
502
			} else {
665
					_initCount(sharedObject, rwType);
503
				doRemove = true;
666
				}
504
			}
667
			}
505
		}
668
		}
506
		if (doRemove) {
669
		if (model == null) {
507
			SYNC.acquire();
670
			SYNC.acquire();
508
			fManagedObjects.remove(id);
671
			try {
509
			SYNC.release();
672
				fManagedObjects.remove(id);
673
			}
674
			finally {
675
				SYNC.release();
676
			}
510
		}
677
		}
511
		sharedObject.setLoaded();
678
		sharedObject.setLoaded();
512
	}
679
	}
513
680
514
	private SharedObject _commonNewModel(IFile iFile, boolean force) throws ResourceAlreadyExists, ResourceInUse, IOException, CoreException {
681
	private SharedObject _commonNewModel(IFile iFile, boolean force) throws ResourceAlreadyExists,
682
			ResourceInUse, IOException, CoreException {
515
		IStructuredModel aSharedModel = null;
683
		IStructuredModel aSharedModel = null;
516
		// First, check if resource already exists on file system.
684
		// First, check if resource already exists on file system.
517
		// if is does, then throw Resource in Use iff force==false
685
		// if is does, then throw Resource in Use iff force==false
Lines 519-554 Link Here
519
		if (iFile.exists() && !force) {
687
		if (iFile.exists() && !force) {
520
			throw new ResourceAlreadyExists();
688
			throw new ResourceAlreadyExists();
521
		}
689
		}
522
		
690
523
		SharedObject sharedObject = null;
691
		SharedObject sharedObject = null;
524
		String id = calculateId(iFile);
692
		String id = calculateId(iFile);
525
		try {
693
		try {
526
			SYNC.acquire();
694
			SYNC.acquire();
527
		
695
528
			 sharedObject = (SharedObject) fManagedObjects.get(id);
696
			sharedObject = (SharedObject) fManagedObjects.get(id);
529
	
697
530
			if (sharedObject != null && !force) {
698
			if (sharedObject != null && !force) {
531
				// if in cache already, and force is not true, then this is an
699
				// if in cache already, and force is not true, then this is an
532
				// error
700
				// error
533
				// in call
701
				// in call
534
				throw new ResourceInUse();
702
				throw new ResourceInUse();
535
			}
703
			}
536
			
704
537
			sharedObject = new SharedObject(null);
705
			sharedObject = new SharedObject(null);
538
			fManagedObjects.put(id, sharedObject);
706
			fManagedObjects.put(id, sharedObject);
539
			
707
540
		} finally {
708
		}
709
		finally {
541
			SYNC.release();
710
			SYNC.release();
542
		}
711
		}
543
		
712
544
		// if we get to here without above exceptions, then all is ok
713
		// if we get to here without above exceptions, then all is ok
545
		// to get model like normal, but set 'new' attribute (where the
714
		// to get model like normal, but set 'new' attribute (where the
546
		// 'new' attribute means this is a model without a corresponding
715
		// 'new' attribute means this is a model without a corresponding
547
		// underlying resource.
716
		// underlying resource.
548
		aSharedModel = FileBufferModelManager.getInstance().getModel(iFile);
717
		aSharedModel = FileBufferModelManager.getInstance().getModel(iFile);
549
		aSharedModel.setNewState(true);
718
		aSharedModel.setNewState(true);
550
		
719
551
		sharedObject.theSharedModel=aSharedModel;
720
		sharedObject.theSharedModel = aSharedModel;
552
		// when resource is provided, we can set
721
		// when resource is provided, we can set
553
		// synchronization stamp ... otherwise client should
722
		// synchronization stamp ... otherwise client should
554
		// Note: one client which does this is FileModelProvider.
723
		// Note: one client which does this is FileModelProvider.
Lines 556-620 Link Here
556
		return sharedObject;
725
		return sharedObject;
557
	}
726
	}
558
727
559
	public IStructuredModel _getModelFor(IStructuredDocument document, ReadEditType accessType) {
728
	public IStructuredModel _getModelFor(IStructuredDocument document, ReadEditType rwType) {
560
729
561
		String id = FileBufferModelManager.getInstance().calculateId(document);
730
		String id = FileBufferModelManager.getInstance().calculateId(document);
562
		if (id == null) {
731
		if (id == null) {
563
			if (READ == accessType)
732
			if (READ == rwType)
564
				return getExistingModelForRead(document);
733
				return getExistingModelForRead(document);
565
			if (EDIT == accessType)
734
			if (EDIT == rwType)
566
				return getExistingModelForEdit(document);
735
				return getExistingModelForEdit(document);
567
			Assert.isNotNull(id, "unknown IStructuredDocument " + document); //$NON-NLS-1$
736
			Assert.isNotNull(id, "unknown IStructuredDocument " + document); //$NON-NLS-1$
568
		}
737
		}
569
		
738
570
		SharedObject sharedObject = null;
739
		FileBufferDocumentLoader loader = new FileBufferDocumentLoader(document, rwType);
571
		SYNC.acquire();
740
		try {
572
		sharedObject = (SharedObject) fManagedObjects.get(id);
741
			return doLoad(id, rwType, loader);
573
		SYNC.release();
742
		}
574
		
743
		catch (Exception e) {
575
		while(true) {
744
			// Safe to ignore. FileBufferDocumentLoader#run does not throw
576
			if (sharedObject!=null) {
745
			// exceptions.
577
				sharedObject.waitForLoadAttempt();
746
			return null;
578
			}
579
			SYNC.acquire();
580
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
581
			if (testObject==null) {
582
				sharedObject = new SharedObject(null);
583
				fManagedObjects.put(id, sharedObject);
584
				SYNC.release();
585
				synchronized(sharedObject) {
586
					sharedObject.theSharedModel = FileBufferModelManager.getInstance().getModel(document);
587
					_initCount(sharedObject, accessType);
588
					sharedObject.setLoaded();
589
				}
590
				break;
591
			} else if (sharedObject == testObject) {
592
				synchronized(sharedObject) {
593
					Assert.isTrue(sharedObject.referenceCountForEdit + sharedObject.referenceCountForRead > 0);
594
					if (sharedObject.theSharedModel!=null) {
595
						_incrCount(sharedObject, accessType);
596
					}
597
				}
598
				SYNC.release();
599
				break;
600
			} else {
601
				SYNC.release();
602
				sharedObject = testObject;
603
			}
604
		}
747
		}
605
		
748
606
		return sharedObject==null ? null : sharedObject.theSharedModel;
607
	}
749
	}
608
750
609
	private void _incrCount(SharedObject sharedObject, ReadEditType type) {
751
	private void _incrCount(SharedObject sharedObject, ReadEditType type) {
610
		synchronized(sharedObject) {
752
		synchronized (sharedObject) {
611
			if (type == READ) {
753
			if (type == READ) {
612
				sharedObject.referenceCountForRead++;
754
				sharedObject.referenceCountForRead++;
613
				FileBufferModelManager.getInstance().connect(sharedObject.theSharedModel.getStructuredDocument());
755
				FileBufferModelManager.getInstance().connect(
756
						sharedObject.theSharedModel.getStructuredDocument());
614
			}
757
			}
615
			else if (type == EDIT) {
758
			else if (type == EDIT) {
616
				sharedObject.referenceCountForEdit++;
759
				sharedObject.referenceCountForEdit++;
617
				FileBufferModelManager.getInstance().connect(sharedObject.theSharedModel.getStructuredDocument());
760
				FileBufferModelManager.getInstance().connect(
761
						sharedObject.theSharedModel.getStructuredDocument());
618
			}
762
			}
619
			else
763
			else
620
				throw new IllegalArgumentException();
764
				throw new IllegalArgumentException();
Lines 622-634 Link Here
622
	}
766
	}
623
767
624
	private void _initCount(SharedObject sharedObject, ReadEditType type) {
768
	private void _initCount(SharedObject sharedObject, ReadEditType type) {
625
		synchronized(sharedObject) {
769
		synchronized (sharedObject) {
626
			if (type == READ) {
770
			if (type == READ) {
627
				FileBufferModelManager.getInstance().connect(sharedObject.theSharedModel.getStructuredDocument());
771
				FileBufferModelManager.getInstance().connect(
772
						sharedObject.theSharedModel.getStructuredDocument());
628
				sharedObject.referenceCountForRead = 1;
773
				sharedObject.referenceCountForRead = 1;
629
			}
774
			}
630
			else if (type == EDIT) {
775
			else if (type == EDIT) {
631
				FileBufferModelManager.getInstance().connect(sharedObject.theSharedModel.getStructuredDocument());
776
				FileBufferModelManager.getInstance().connect(
777
						sharedObject.theSharedModel.getStructuredDocument());
632
				sharedObject.referenceCountForEdit = 1;
778
				sharedObject.referenceCountForEdit = 1;
633
			}
779
			}
634
			else
780
			else
Lines 659-669 Link Here
659
		}
805
		}
660
	}
806
	}
661
807
662
663
	/**
808
	/**
664
	 * Calculate id provides a common way to determine the id from the input
809
	 * Calculate id provides a common way to determine the id from the input ...
665
	 * ... needed to get and save the model. It is a simple class utility, but
810
	 * needed to get and save the model. It is a simple class utility, but is an
666
	 * is an instance method so can be accessed via interface.
811
	 * instance method so can be accessed via interface.
667
	 */
812
	 */
668
	public String calculateId(IFile file) {
813
	public String calculateId(IFile file) {
669
		return FileBufferModelManager.getInstance().calculateId(file);
814
		return FileBufferModelManager.getInstance().calculateId(file);
Lines 677-683 Link Here
677
		return cd;
822
		return cd;
678
	}
823
	}
679
824
680
	private IModelHandler calculateType(String filename, InputStream inputStream) throws IOException {
825
	private IModelHandler calculateType(String filename, InputStream inputStream)
826
			throws IOException {
681
		ModelHandlerRegistry cr = getModelHandlerRegistry();
827
		ModelHandlerRegistry cr = getModelHandlerRegistry();
682
		IModelHandler cd = cr.getHandlerFor(filename, inputStream);
828
		IModelHandler cd = cr.getHandlerFor(filename, inputStream);
683
		return cd;
829
		return cd;
Lines 712-718 Link Here
712
		// Note: calculateType(iFile) returns a default xml model handler if
858
		// Note: calculateType(iFile) returns a default xml model handler if
713
		// content type is null.
859
		// content type is null.
714
		String contentTypeId = calculateType(iFile).getAssociatedContentTypeId();
860
		String contentTypeId = calculateType(iFile).getAssociatedContentTypeId();
715
		String endOfLineCode = ContentBasedPreferenceGateway.getPreferencesString(contentTypeId, CommonEncodingPreferenceNames.END_OF_LINE_CODE);
861
		String endOfLineCode = ContentBasedPreferenceGateway.getPreferencesString(contentTypeId,
862
				CommonEncodingPreferenceNames.END_OF_LINE_CODE);
716
		// endOfLineCode == null means the content type does not support this
863
		// endOfLineCode == null means the content type does not support this
717
		// function (e.g. DTD)
864
		// function (e.g. DTD)
718
		// endOfLineCode == "" means no translation
865
		// endOfLineCode == "" means no translation
Lines 736-743 Link Here
736
883
737
					if (i < lineCount - 1) {
884
					if (i < lineCount - 1) {
738
						String currentLineDelimiter = document.getLineDelimiter(i);
885
						String currentLineDelimiter = document.getLineDelimiter(i);
739
						if (currentLineDelimiter != null && currentLineDelimiter.compareTo(lineDelimiterToUse) != 0)
886
						if (currentLineDelimiter != null
740
							multiTextEdit.addChild(new ReplaceEdit(lineEndOffset, currentLineDelimiter.length(), lineDelimiterToUse));
887
								&& currentLineDelimiter.compareTo(lineDelimiterToUse) != 0)
888
							multiTextEdit.addChild(new ReplaceEdit(lineEndOffset,
889
									currentLineDelimiter.length(), lineDelimiterToUse));
741
					}
890
					}
742
				}
891
				}
743
892
Lines 798-805 Link Here
798
				throw new ResourceInUse();
947
				throw new ResourceInUse();
799
			}
948
			}
800
			sharedObject = new SharedObject(null);
949
			sharedObject = new SharedObject(null);
801
			fManagedObjects.put(newId,sharedObject);
950
			fManagedObjects.put(newId, sharedObject);
802
		} finally {
951
		}
952
		finally {
803
			SYNC.release();
953
			SYNC.release();
804
		}
954
		}
805
		// get loader based on existing type (note the type assumption)
955
		// get loader based on existing type (note the type assumption)
Lines 808-829 Link Here
808
		// IModelLoader loader = (IModelLoader) getModelLoaders().get(type);
958
		// IModelLoader loader = (IModelLoader) getModelLoaders().get(type);
809
		// IModelLoader loader = (IModelLoader) getModelLoaders().get(type);
959
		// IModelLoader loader = (IModelLoader) getModelLoaders().get(type);
810
		// ask the loader to copy
960
		// ask the loader to copy
811
		synchronized(sharedObject) {
961
		synchronized (sharedObject) {
812
			sharedObject.doWait = false;
962
			sharedObject.doWait = false;
813
			newModel = copy(model, newId);
963
			try {
814
			sharedObject.doWait = true;
964
				newModel = copy(model, newId);
965
			}
966
			finally {
967
				sharedObject.doWait = true;
968
			}
815
		}
969
		}
816
		if (newModel != null) {
970
		if (newModel != null) {
817
			// add to our cache
971
			// add to our cache
818
			synchronized(sharedObject) {
972
			synchronized (sharedObject) {
819
				sharedObject.theSharedModel=newModel;
973
				sharedObject.theSharedModel = newModel;
820
				sharedObject.referenceCountForEdit = 1;
974
				sharedObject.referenceCountForEdit = 1;
821
				trace("copied model", newId, sharedObject.referenceCountForEdit); //$NON-NLS-1$
975
				trace("copied model", newId, sharedObject.referenceCountForEdit); //$NON-NLS-1$
822
			}
976
			}
823
		} else {
977
		}
978
		else {
824
			SYNC.acquire();
979
			SYNC.acquire();
825
			fManagedObjects.remove(newId);
980
			try {
826
			SYNC.release();
981
				fManagedObjects.remove(newId);
982
			}
983
			finally {
984
				SYNC.release();
985
			}
827
		}
986
		}
828
		sharedObject.setLoaded();
987
		sharedObject.setLoaded();
829
		return newModel;
988
		return newModel;
Lines 831-838 Link Here
831
990
832
	/**
991
	/**
833
	 * Similar to clone, except the new instance has no content. Note: this
992
	 * Similar to clone, except the new instance has no content. Note: this
834
	 * produces an unmanaged model, for temporary use. If a true shared model
993
	 * produces an unmanaged model, for temporary use. If a true shared model is
835
	 * is desired, use "copy".
994
	 * desired, use "copy".
836
	 */
995
	 */
837
	public IStructuredModel createNewInstance(IStructuredModel oldModel) throws IOException {
996
	public IStructuredModel createNewInstance(IStructuredModel oldModel) throws IOException {
838
		IModelHandler handler = oldModel.getModelHandler();
997
		IModelHandler handler = oldModel.getModelHandler();
Lines 840-846 Link Here
840
		IStructuredModel newModel = loader.createModel(oldModel);
999
		IStructuredModel newModel = loader.createModel(oldModel);
841
		newModel.setModelHandler(handler);
1000
		newModel.setModelHandler(handler);
842
		if (newModel instanceof AbstractStructuredModel) {
1001
		if (newModel instanceof AbstractStructuredModel) {
843
			((AbstractStructuredModel) newModel).setContentTypeIdentifier(oldModel.getContentTypeIdentifier());
1002
			((AbstractStructuredModel) newModel).setContentTypeIdentifier(oldModel
1003
					.getContentTypeIdentifier());
844
		}
1004
		}
845
		URIResolver oldResolver = oldModel.getResolver();
1005
		URIResolver oldResolver = oldModel.getResolver();
846
		newModel.setResolver(oldResolver);
1006
		newModel.setResolver(oldResolver);
Lines 858-872 Link Here
858
1018
859
	/**
1019
	/**
860
	 * Factory method, since a proper IStructuredDocument must have a proper
1020
	 * Factory method, since a proper IStructuredDocument must have a proper
861
	 * parser assigned. Note: its assume that IFile does not actually exist as
1021
	 * parser assigned. Note: its assume that IFile does not actually exist as a
862
	 * a resource yet. If it does, ResourceAlreadyExists exception is thrown.
1022
	 * resource yet. If it does, ResourceAlreadyExists exception is thrown. If
863
	 * If the resource does already exist, then createStructuredDocumentFor is
1023
	 * the resource does already exist, then createStructuredDocumentFor is the
864
	 * the right API to use.
1024
	 * right API to use.
865
	 * 
1025
	 * 
866
	 * @throws ResourceInUse
1026
	 * @throws ResourceInUse
867
	 * 
1027
	 * 
868
	 */
1028
	 */
869
	public  IStructuredDocument createNewStructuredDocumentFor(IFile iFile) throws ResourceAlreadyExists, IOException, CoreException {
1029
	public IStructuredDocument createNewStructuredDocumentFor(IFile iFile)
1030
			throws ResourceAlreadyExists, IOException, CoreException {
870
		if (iFile.exists()) {
1031
		if (iFile.exists()) {
871
			throw new ResourceAlreadyExists(iFile.getFullPath().toOSString());
1032
			throw new ResourceAlreadyExists(iFile.getFullPath().toOSString());
872
		}
1033
		}
Lines 892-898 Link Here
892
	 * 
1053
	 * 
893
	 * @throws ResourceInUse
1054
	 * @throws ResourceInUse
894
	 */
1055
	 */
895
	public  IStructuredDocument createStructuredDocumentFor(IFile iFile) throws IOException, CoreException {
1056
	public IStructuredDocument createStructuredDocumentFor(IFile iFile) throws IOException,
1057
			CoreException {
896
		if (!iFile.exists()) {
1058
		if (!iFile.exists()) {
897
			throw new FileNotFoundException(iFile.getFullPath().toOSString());
1059
			throw new FileNotFoundException(iFile.getFullPath().toOSString());
898
		}
1060
		}
Lines 904-927 Link Here
904
		IDocumentLoader loader = null;
1066
		IDocumentLoader loader = null;
905
		IModelHandler handler = calculateType(iFile);
1067
		IModelHandler handler = calculateType(iFile);
906
		loader = handler.getDocumentLoader();
1068
		loader = handler.getDocumentLoader();
907
		IStructuredDocument result = (IStructuredDocument) loader.createNewStructuredDocument(iFile);
1069
		IStructuredDocument result = (IStructuredDocument) loader
1070
				.createNewStructuredDocument(iFile);
908
		return result;
1071
		return result;
909
	}
1072
	}
910
1073
911
	/**
1074
	/**
912
	 * Conveience method, since a proper IStructuredDocument must have a
1075
	 * Conveience method, since a proper IStructuredDocument must have a proper
913
	 * proper parser assigned. It should only be used when an empty
1076
	 * parser assigned. It should only be used when an empty structuredDocument
914
	 * structuredDocument is needed. Otherwise, use IFile form.
1077
	 * is needed. Otherwise, use IFile form.
915
	 * 
1078
	 * 
916
	 * @deprecated - TODO: to be removed by C4 do we really need this? I
1079
	 * @deprecated - TODO: to be removed by C4 do we really need this? I
917
	 *             recommend to - use createStructuredDocumentFor(filename,
1080
	 *             recommend to - use createStructuredDocumentFor(filename,
918
	 *             null, null) - the filename does not need to represent a
1081
	 *             null, null) - the filename does not need to represent a real
919
	 *             real - file, but can take for form of dummy.jsp, test.xml,
1082
	 *             - file, but can take for form of dummy.jsp, test.xml, etc. -
920
	 *             etc. - That way we don't hard code the handler, but specify
1083
	 *             That way we don't hard code the handler, but specify we -
921
	 *             we - want the handler that "goes with" a certain type of -
1084
	 *             want the handler that "goes with" a certain type of - file.
922
	 *             file.
923
	 */
1085
	 */
924
	public  IStructuredDocument createStructuredDocumentFor(String contentTypeId) {
1086
	public IStructuredDocument createStructuredDocumentFor(String contentTypeId) {
925
		IDocumentLoader loader = null;
1087
		IDocumentLoader loader = null;
926
		ModelHandlerRegistry cr = getModelHandlerRegistry();
1088
		ModelHandlerRegistry cr = getModelHandlerRegistry();
927
		IModelHandler handler = cr.getHandlerForContentTypeId(contentTypeId);
1089
		IModelHandler handler = cr.getHandlerForContentTypeId(contentTypeId);
Lines 933-948 Link Here
933
	}
1095
	}
934
1096
935
	/**
1097
	/**
936
	 * Conveience method, since a proper IStructuredDocument must have a
1098
	 * Conveience method, since a proper IStructuredDocument must have a proper
937
	 * proper parser assigned.
1099
	 * parser assigned.
938
	 * 
1100
	 * 
939
	 * @deprecated -- - TODO: to be removed by C4 I marked as deprecated to
1101
	 * @deprecated -- - TODO: to be removed by C4 I marked as deprecated to
940
	 *             discouage use of this method. It does not really work for
1102
	 *             discouage use of this method. It does not really work for JSP
941
	 *             JSP fragments, since JSP Fragments need an IFile to
1103
	 *             fragments, since JSP Fragments need an IFile to correctly
942
	 *             correctly look up the content settings. Use IFile form
1104
	 *             look up the content settings. Use IFile form instead.
943
	 *             instead.
944
	 */
1105
	 */
945
	public IStructuredDocument createStructuredDocumentFor(String filename, InputStream inputStream, URIResolver resolver) throws IOException {
1106
	public IStructuredDocument createStructuredDocumentFor(String filename,
1107
			InputStream inputStream, URIResolver resolver) throws IOException {
946
		IDocumentLoader loader = null;
1108
		IDocumentLoader loader = null;
947
		InputStream istream = Utilities.getMarkSupportedStream(inputStream);
1109
		InputStream istream = Utilities.getMarkSupportedStream(inputStream);
948
		if (istream != null) {
1110
		if (istream != null) {
Lines 962-977 Link Here
962
1124
963
	/**
1125
	/**
964
	 * Special case method. This method was created for the special case where
1126
	 * Special case method. This method was created for the special case where
965
	 * there is an encoding for input stream that should override all the
1127
	 * there is an encoding for input stream that should override all the normal
966
	 * normal rules for encoding. For example, if there is an encoding
1128
	 * rules for encoding. For example, if there is an encoding (charset)
967
	 * (charset) specified in HTTP response header, then that encoding is used
1129
	 * specified in HTTP response header, then that encoding is used to
968
	 * to translate the input stream to a string, but then the normal encoding
1130
	 * translate the input stream to a string, but then the normal encoding
969
	 * rules are ignored, so that the string is not translated twice (for
1131
	 * rules are ignored, so that the string is not translated twice (for
970
	 * example, if its an HTML "file", then even if it contains a charset in
1132
	 * example, if its an HTML "file", then even if it contains a charset in
971
	 * meta tag, its ignored since its assumed its all correctly decoded by
1133
	 * meta tag, its ignored since its assumed its all correctly decoded by the
972
	 * the HTTP charset.
1134
	 * HTTP charset.
973
	 */
1135
	 */
974
	public  IStructuredDocument createStructuredDocumentFor(String filename, InputStream inputStream, URIResolver resolver, String encoding) throws IOException {
1136
	public IStructuredDocument createStructuredDocumentFor(String filename,
1137
			InputStream inputStream, URIResolver resolver, String encoding) throws IOException {
975
		String content = readInputStream(inputStream, encoding);
1138
		String content = readInputStream(inputStream, encoding);
976
		IStructuredDocument result = createStructuredDocumentFor(filename, content, resolver);
1139
		IStructuredDocument result = createStructuredDocumentFor(filename, content, resolver);
977
		return result;
1140
		return result;
Lines 979-990 Link Here
979
1142
980
	/**
1143
	/**
981
	 * Convenience method. This method can be used when the resource does not
1144
	 * Convenience method. This method can be used when the resource does not
982
	 * really exist (e.g. when content is being created, but hasn't been
1145
	 * really exist (e.g. when content is being created, but hasn't been written
983
	 * written to disk yet). Note that since the content is being provided as
1146
	 * to disk yet). Note that since the content is being provided as a String,
984
	 * a String, it is assumed to already be decoded correctly so no
1147
	 * it is assumed to already be decoded correctly so no transformation is
985
	 * transformation is done.
1148
	 * done.
986
	 */
1149
	 */
987
	public  IStructuredDocument createStructuredDocumentFor(String filename, String content, URIResolver resolver) throws IOException {
1150
	public IStructuredDocument createStructuredDocumentFor(String filename, String content,
1151
			URIResolver resolver) throws IOException {
988
		// TODO: avoid all these String instances
1152
		// TODO: avoid all these String instances
989
		StringBuffer contentBuffer = new StringBuffer(content);
1153
		StringBuffer contentBuffer = new StringBuffer(content);
990
		IDocumentLoader loader = null;
1154
		IDocumentLoader loader = null;
Lines 1017-1033 Link Here
1017
			// (even if it really is in use ... we don't care)
1181
			// (even if it really is in use ... we don't care)
1018
			// this may need to be re-examined.
1182
			// this may need to be re-examined.
1019
			if (Logger.DEBUG_MODELMANAGER)
1183
			if (Logger.DEBUG_MODELMANAGER)
1020
				Logger.log(Logger.INFO, "ModelMangerImpl::createUnManagedStructuredModelFor. Model unexpectedly in use."); //$NON-NLS-1$ //$NON-NLS-2$
1184
				Logger
1185
						.log(Logger.INFO,
1186
								"ModelMangerImpl::createUnManagedStructuredModelFor. Model unexpectedly in use."); //$NON-NLS-1$ //$NON-NLS-2$
1021
		}
1187
		}
1022
1188
1023
		return result;
1189
		return result;
1024
	}
1190
	}
1025
1191
1026
	/**
1192
	/**
1027
	 * Conveience method. It depends on the loaders newModel method to return
1193
	 * Conveience method. It depends on the loaders newModel method to return an
1028
	 * an appropriate StrucuturedModel appropriately initialized.
1194
	 * appropriate StrucuturedModel appropriately initialized.
1029
	 */
1195
	 */
1030
	public IStructuredModel createUnManagedStructuredModelFor(IFile iFile) throws IOException, CoreException {
1196
	public IStructuredModel createUnManagedStructuredModelFor(IFile iFile) throws IOException,
1197
			CoreException {
1031
		IStructuredModel result = null;
1198
		IStructuredModel result = null;
1032
		result = createUnManagedEmptyModelFor(iFile);
1199
		result = createUnManagedEmptyModelFor(iFile);
1033
1200
Lines 1040-1057 Link Here
1040
	}
1207
	}
1041
1208
1042
	/**
1209
	/**
1043
	 * Conveience method. It depends on the loaders newModel method to return
1210
	 * Conveience method. It depends on the loaders newModel method to return an
1044
	 * an appropriate StrucuturedModel appropriately initialized.
1211
	 * appropriate StrucuturedModel appropriately initialized.
1045
	 */
1212
	 */
1046
	public  IStructuredModel createUnManagedStructuredModelFor(String contentTypeId) {
1213
	public IStructuredModel createUnManagedStructuredModelFor(String contentTypeId) {
1047
		return createUnManagedStructuredModelFor(contentTypeId, null);
1214
		return createUnManagedStructuredModelFor(contentTypeId, null);
1048
	}
1215
	}
1049
1216
1050
	/**
1217
	/**
1051
	 * Conveience method. It depends on the loaders newModel method to return
1218
	 * Conveience method. It depends on the loaders newModel method to return an
1052
	 * an appropriate StrucuturedModel appropriately initialized.
1219
	 * appropriate StrucuturedModel appropriately initialized.
1053
	 */
1220
	 */
1054
	public  IStructuredModel createUnManagedStructuredModelFor(String contentTypeId, URIResolver resolver) {
1221
	public IStructuredModel createUnManagedStructuredModelFor(String contentTypeId,
1222
			URIResolver resolver) {
1055
		IStructuredModel result = null;
1223
		IStructuredModel result = null;
1056
		ModelHandlerRegistry cr = getModelHandlerRegistry();
1224
		ModelHandlerRegistry cr = getModelHandlerRegistry();
1057
		IModelHandler handler = cr.getHandlerForContentTypeId(contentTypeId);
1225
		IModelHandler handler = cr.getHandlerForContentTypeId(contentTypeId);
Lines 1063-1133 Link Here
1063
			// (even if it really is in use ... we don't care)
1231
			// (even if it really is in use ... we don't care)
1064
			// this may need to be re-examined.
1232
			// this may need to be re-examined.
1065
			if (Logger.DEBUG_MODELMANAGER)
1233
			if (Logger.DEBUG_MODELMANAGER)
1066
				Logger.log(Logger.INFO, "ModelMangerImpl::createUnManagedStructuredModelFor. Model unexpectedly in use."); //$NON-NLS-1$ //$NON-NLS-2$
1234
				Logger
1235
						.log(Logger.INFO,
1236
								"ModelMangerImpl::createUnManagedStructuredModelFor. Model unexpectedly in use."); //$NON-NLS-1$ //$NON-NLS-2$
1067
		}
1237
		}
1068
		return result;
1238
		return result;
1069
	}
1239
	}
1070
1240
1071
	private IStructuredModel getExistingModel(Object id) {
1241
	private IStructuredModel getExistingModel(Object id) {
1072
		IStructuredModel result = null;
1242
		IStructuredModel result = null;
1073
		
1243
		SharedObject sharedObject = null;
1244
1074
		SYNC.acquire();
1245
		SYNC.acquire();
1075
		/**
1246
		try {
1076
		 * While a good check in theory, it's possible for an event fired to
1247
			/**
1077
		 * cause a listener to access a method that calls this one.
1248
			 * While a good check in theory, it's possible for an event fired to
1078
		 */
1249
			 * cause a listener to access a method that calls this one.
1079
		//Assert.isTrue(SYNC.getDepth()==1, "depth not equal to 1");
1250
			 * Assert.isTrue(SYNC.getDepth()==1, "depth not equal to 1");
1080
		// let's see if we already have it in our cache
1251
			 */
1081
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1252
1082
		// if not, then we'll simply return null
1253
			// let's see if we already have it in our cache
1083
		if (sharedObject != null) {
1254
			// if not, then we'll simply return null
1084
			SYNC.release();
1255
			sharedObject = (SharedObject) fManagedObjects.get(id);
1085
			sharedObject.waitForLoadAttempt();
1256
1086
			result = sharedObject.theSharedModel;
1257
		}
1087
		} else {
1258
		finally {
1088
			SYNC.release();
1259
			SYNC.release();
1260
			if (sharedObject != null) {
1261
				synchronized (sharedObject) {
1262
					sharedObject.waitForLoadAttempt();
1263
					result = sharedObject.theSharedModel;
1264
				}
1265
			}
1089
		}
1266
		}
1090
		
1267
1091
		return result;
1268
		return result;
1092
	}
1269
	}
1093
1270
1094
	/**
1271
	/**
1095
	 * Note: users of this 'model' must still release it when finished.
1272
	 * Note: users of this 'model' must still release it when finished. Returns
1096
	 * Returns null if there's not a model corresponding to document.
1273
	 * null if there's not a model corresponding to document.
1097
	 */
1274
	 */
1098
	public IStructuredModel getExistingModelForEdit(IDocument document) {
1275
	public IStructuredModel getExistingModelForEdit(IDocument document) {
1099
		IStructuredModel result = null;
1276
		IStructuredModel result = null;
1100
		
1277
		Set ids;
1101
		SYNC.acquire();		
1278
1102
		// create a snapshot
1279
		SYNC.acquire();
1103
		Set ids = new HashSet(fManagedObjects.keySet());
1280
		try {
1104
		SYNC.release();
1281
			// create a snapshot
1282
			ids = new HashSet(fManagedObjects.keySet());
1283
		}
1284
		finally {
1285
			SYNC.release();
1286
		}
1105
		for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1287
		for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1106
			Object potentialId = iterator.next();
1288
			Object potentialId = iterator.next();
1107
			SYNC.acquire();	
1289
			boolean containsKey;
1108
			if (fManagedObjects.containsKey(potentialId)) {
1290
			SYNC.acquire();
1109
				// check to see if still valid
1291
			try {
1292
				containsKey = fManagedObjects.containsKey(potentialId);
1293
			}
1294
			finally {
1110
				SYNC.release();
1295
				SYNC.release();
1296
			}
1297
			if (containsKey) {
1111
				IStructuredModel tempResult = getExistingModel(potentialId);
1298
				IStructuredModel tempResult = getExistingModel(potentialId);
1112
				if (tempResult!=null && document == tempResult.getStructuredDocument()) {
1299
				if (tempResult != null && document == tempResult.getStructuredDocument()) {
1113
					result = getExistingModelForEdit(potentialId);
1300
					result = getExistingModelForEdit(potentialId);
1114
					break;
1301
					break;
1115
				}
1302
				}
1116
			} else {
1117
				SYNC.release();
1118
			}
1303
			}
1119
		}
1304
		}
1120
		
1305
1121
		return result;
1306
		return result;
1122
	}
1307
	}
1123
1308
1124
	/**
1309
	/**
1125
	 * This is similar to the getModel method, except this method does not
1310
	 * This is similar to the getModel method, except this method does not
1126
	 * create a model. This method does increment the reference count (if it
1311
	 * create a model. This method does increment the reference count (if it
1127
	 * exists). If the model does not already exist in the cache of models,
1312
	 * exists). If the model does not already exist in the cache of models, null
1128
	 * null is returned.
1313
	 * is returned.
1129
	 */
1314
	 */
1130
	public  IStructuredModel getExistingModelForEdit(IFile iFile) {
1315
	public IStructuredModel getExistingModelForEdit(IFile iFile) {
1131
1316
1132
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1317
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1133
		Object id = calculateId(iFile);
1318
		Object id = calculateId(iFile);
Lines 1138-1145 Link Here
1138
	/**
1323
	/**
1139
	 * This is similar to the getModel method, except this method does not
1324
	 * This is similar to the getModel method, except this method does not
1140
	 * create a model. This method does increment the reference count (if it
1325
	 * create a model. This method does increment the reference count (if it
1141
	 * exists). If the model does not already exist in the cache of models,
1326
	 * exists). If the model does not already exist in the cache of models, null
1142
	 * null is returned.
1327
	 * is returned.
1143
	 * 
1328
	 * 
1144
	 * @deprecated use IFile form - this one will become protected or private
1329
	 * @deprecated use IFile form - this one will become protected or private
1145
	 */
1330
	 */
Lines 1147-1212 Link Here
1147
1332
1148
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1333
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1149
		IStructuredModel result = null;
1334
		IStructuredModel result = null;
1150
		boolean doRelease = true;
1335
		SharedObject sharedObject = null;
1151
		// let's see if we already have it in our cache
1336
		// let's see if we already have it in our cache
1337
		SYNC.acquire();
1152
		try {
1338
		try {
1153
			SYNC.acquire();
1339
			sharedObject = (SharedObject) fManagedObjects.get(id);
1154
			SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1340
			// if not found, then we'll simply return null
1155
			// if not, then we'll simply return null
1341
		}
1342
		finally {
1343
			SYNC.release();
1156
			if (sharedObject != null) {
1344
			if (sharedObject != null) {
1157
				// if shared object is in our cache, then simply increment its ref
1345
				// if shared object is in our cache, then simply increment its
1346
				// ref
1158
				// count,
1347
				// count,
1159
				// and return the object.
1348
				// and return the object.
1160
				SYNC.release();
1349
				synchronized (sharedObject) {
1161
				doRelease=false;
1162
				synchronized(sharedObject) {
1163
					if (sharedObject.doWait) {
1350
					if (sharedObject.doWait) {
1164
						sharedObject.waitForLoadAttempt();
1351
						sharedObject.waitForLoadAttempt();
1165
					}
1352
					}
1166
					if (sharedObject.theSharedModel!=null) {
1353
					if (sharedObject.theSharedModel != null) {
1167
						_incrCount(sharedObject, EDIT);
1354
						_incrCount(sharedObject, EDIT);
1168
					}
1355
					}
1169
					result = sharedObject.theSharedModel;
1356
					result = sharedObject.theSharedModel;
1170
				}
1357
				}
1171
				trace("got existing model for Edit: ", id); //$NON-NLS-1$
1358
				trace("got existing model for Edit: ", id); //$NON-NLS-1$
1172
				trace("   incremented referenceCountForEdit ", id, sharedObject.referenceCountForEdit); //$NON-NLS-1$
1359
				trace(
1173
			}
1360
						"   incremented referenceCountForEdit ", id, sharedObject.referenceCountForEdit); //$NON-NLS-1$
1174
		} finally {
1175
			if (doRelease) {
1176
				SYNC.release();
1177
			}
1361
			}
1178
		}
1362
		}
1179
		
1363
1180
		return result;
1364
		return result;
1181
	}
1365
	}
1182
1366
1183
	/**
1367
	/**
1184
	 * Note: users of this 'model' must still release it when finished.
1368
	 * Note: users of this 'model' must still release it when finished. Returns
1185
	 * Returns null if there's not a model corresponding to document.
1369
	 * null if there's not a model corresponding to document.
1186
	 */
1370
	 */
1187
	public IStructuredModel getExistingModelForRead(IDocument document) {
1371
	public IStructuredModel getExistingModelForRead(IDocument document) {
1188
		IStructuredModel result = null;
1372
		IStructuredModel result = null;
1189
		
1373
1190
		SYNC.acquire();		
1374
		Set ids;
1191
		// create a snapshot
1375
		SYNC.acquire();
1192
		Set ids = new HashSet(fManagedObjects.keySet());
1376
		try {
1193
		SYNC.release();
1377
			// create a snapshot
1378
			ids = new HashSet(fManagedObjects.keySet());
1379
		}
1380
		finally {
1381
			SYNC.release();
1382
		}
1194
		for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1383
		for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1195
			Object potentialId = iterator.next();
1384
			Object potentialId = iterator.next();
1196
			SYNC.acquire();	
1385
			boolean containsKey;
1197
			if (fManagedObjects.containsKey(potentialId)) {
1386
			SYNC.acquire();
1198
				// check to see if still valid
1387
			try {
1388
				containsKey = fManagedObjects.containsKey(potentialId);
1389
			}
1390
			finally {
1199
				SYNC.release();
1391
				SYNC.release();
1392
			}
1393
			if (containsKey) {
1394
				// check to see if still valid
1200
				IStructuredModel tempResult = getExistingModel(potentialId);
1395
				IStructuredModel tempResult = getExistingModel(potentialId);
1201
				if (tempResult!=null && document == tempResult.getStructuredDocument()) {
1396
				if (tempResult != null && document == tempResult.getStructuredDocument()) {
1202
					result = getExistingModelForRead(potentialId);
1397
					result = getExistingModelForRead(potentialId);
1203
					break;
1398
					break;
1204
				}
1399
				}
1205
			} else {
1206
				SYNC.release();
1207
			}
1400
			}
1208
		}
1401
		}
1209
		
1402
1210
		return result;
1403
		return result;
1211
	}
1404
	}
1212
1405
Lines 1221-1260 Link Here
1221
	/**
1414
	/**
1222
	 * This is similar to the getModel method, except this method does not
1415
	 * This is similar to the getModel method, except this method does not
1223
	 * create a model. This method does increment the reference count (if it
1416
	 * create a model. This method does increment the reference count (if it
1224
	 * exists). If the model does not already exist in the cache of models,
1417
	 * exists). If the model does not already exist in the cache of models, null
1225
	 * null is returned.
1418
	 * is returned.
1226
	 * 
1419
	 * 
1227
	 * @deprecated use IFile form - this one will become protected or private
1420
	 * @deprecated use IFile form - this one will become protected or private
1228
	 */
1421
	 */
1229
	public  IStructuredModel getExistingModelForRead(Object id) {
1422
	public IStructuredModel getExistingModelForRead(Object id) {
1230
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1423
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1231
		IStructuredModel result = null;
1424
		IStructuredModel result = null;
1232
		boolean doRelease = true;
1425
		SharedObject sharedObject = null;
1233
		// let's see if we already have it in our cache
1426
		SYNC.acquire();
1234
		try {
1427
		try {
1235
			SYNC.acquire();
1428
			// let's see if we already have it in our cache
1236
			SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1429
			sharedObject = (SharedObject) fManagedObjects.get(id);
1237
			// if not, then we'll simply return null
1430
			// if not found, then we'll simply return null
1431
		}
1432
		finally {
1433
			SYNC.release();
1238
			if (sharedObject != null) {
1434
			if (sharedObject != null) {
1239
				// if shared object is in our cache, then simply increment its ref
1435
				// if shared object is in our cache, then simply increment its
1436
				// ref
1240
				// count,
1437
				// count,
1241
				// and return the object.
1438
				// and return the object.
1242
				SYNC.release();
1439
				SYNC.release();
1243
				doRelease=false;
1244
1440
1245
				synchronized(sharedObject) {
1441
				synchronized (sharedObject) {
1246
					if (sharedObject.doWait) {
1442
					if (sharedObject.doWait) {
1247
						sharedObject.waitForLoadAttempt();
1443
						sharedObject.waitForLoadAttempt();
1248
					}
1444
					}
1249
					if (sharedObject.theSharedModel!=null) {
1445
					if (sharedObject.theSharedModel != null) {
1250
						_incrCount(sharedObject, READ);
1446
						_incrCount(sharedObject, READ);
1251
					}
1447
					}
1252
					result = sharedObject.theSharedModel;
1448
					result = sharedObject.theSharedModel;
1253
				}
1449
				}
1254
			}
1450
			}
1255
		} finally {
1256
			if (doRelease)
1257
				SYNC.release();
1258
		}
1451
		}
1259
		return result;
1452
		return result;
1260
	}
1453
	}
Lines 1262-1278 Link Here
1262
	/**
1455
	/**
1263
	 * @deprecated DMW: Tom, this is "special" for links builder Assuming its
1456
	 * @deprecated DMW: Tom, this is "special" for links builder Assuming its
1264
	 *             still needed, wouldn't it be better to change to
1457
	 *             still needed, wouldn't it be better to change to
1265
	 *             getExistingModels()? -- will be removed. Its not thread
1458
	 *             getExistingModels()? -- will be removed. Its not thread safe
1266
	 *             safe for one thread to get the Enumeration, when underlying
1459
	 *             for one thread to get the Enumeration, when underlying data
1267
	 *             data could be changed in another thread.
1460
	 *             could be changed in another thread.
1268
	 */
1461
	 */
1269
	public  Enumeration getExistingModelIds() {
1462
	public Enumeration getExistingModelIds() {
1270
		try {
1463
		try {
1271
			SYNC.acquire();
1464
			SYNC.acquire();
1272
			// create a copy
1465
			// create a copy
1273
			Vector keys = new Vector( fManagedObjects.keySet() );
1466
			Vector keys = new Vector(fManagedObjects.keySet());
1274
			return keys.elements();
1467
			return keys.elements();
1275
		} finally {
1468
		}
1469
		finally {
1276
			SYNC.release();
1470
			SYNC.release();
1277
		}
1471
		}
1278
	}
1472
	}
Lines 1298-1321 Link Here
1298
	/**
1492
	/**
1299
	 * One of the primary forms to get a managed model
1493
	 * One of the primary forms to get a managed model
1300
	 */
1494
	 */
1301
	public  IStructuredModel getModelForEdit(IFile iFile) throws IOException, CoreException {
1495
	public IStructuredModel getModelForEdit(IFile iFile) throws IOException, CoreException {
1302
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1496
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1303
		return _commonGetModel(iFile, EDIT, null, null);
1497
		return _commonGetModel(iFile, EDIT, null, null);
1304
	}
1498
	}
1305
1499
1306
	public  IStructuredModel getModelForEdit(IFile iFile, EncodingRule encodingRule) throws UnsupportedEncodingException, IOException, CoreException {
1500
	public IStructuredModel getModelForEdit(IFile iFile, EncodingRule encodingRule)
1501
			throws UnsupportedEncodingException, IOException, CoreException {
1307
1502
1308
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1503
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1309
		return _commonGetModel(iFile, EDIT, encodingRule);
1504
		return _commonGetModel(iFile, EDIT, encodingRule);
1310
	}
1505
	}
1311
1506
1312
	public  IStructuredModel getModelForEdit(IFile iFile, String encoding, String lineDelimiter) throws java.io.UnsupportedEncodingException, IOException, CoreException {
1507
	public IStructuredModel getModelForEdit(IFile iFile, String encoding, String lineDelimiter)
1508
			throws java.io.UnsupportedEncodingException, IOException, CoreException {
1313
1509
1314
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1510
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1315
		return _commonGetModel(iFile, EDIT, encoding, lineDelimiter);
1511
		return _commonGetModel(iFile, EDIT, encoding, lineDelimiter);
1316
	}
1512
	}
1317
1513
1318
	public  IStructuredModel getModelForEdit(IStructuredDocument document) {
1514
	public IStructuredModel getModelForEdit(IStructuredDocument document) {
1319
		return _getModelFor(document, EDIT);
1515
		return _getModelFor(document, EDIT);
1320
	}
1516
	}
1321
1517
Lines 1323-1329 Link Here
1323
	 * @see IModelManager
1519
	 * @see IModelManager
1324
	 * @deprecated use IFile or String form
1520
	 * @deprecated use IFile or String form
1325
	 */
1521
	 */
1326
	public  IStructuredModel getModelForEdit(Object id, InputStream inputStream, URIResolver resolver) throws java.io.UnsupportedEncodingException, IOException {
1522
	public IStructuredModel getModelForEdit(Object id, InputStream inputStream, URIResolver resolver)
1523
			throws java.io.UnsupportedEncodingException, IOException {
1327
1524
1328
		Assert.isNotNull(id, "IFile parameter can not be null"); //$NON-NLS-1$
1525
		Assert.isNotNull(id, "IFile parameter can not be null"); //$NON-NLS-1$
1329
		String stringId = id.toString();
1526
		String stringId = id.toString();
Lines 1334-1347 Link Here
1334
	 * @see IModelManager
1531
	 * @see IModelManager
1335
	 * @deprecated - use IFile or String form
1532
	 * @deprecated - use IFile or String form
1336
	 */
1533
	 */
1337
	public  IStructuredModel getModelForEdit(Object id, Object modelType, String encodingName, String lineDelimiter, InputStream inputStream, URIResolver resolver) throws java.io.UnsupportedEncodingException, IOException {
1534
	public IStructuredModel getModelForEdit(Object id, Object modelType, String encodingName,
1535
			String lineDelimiter, InputStream inputStream, URIResolver resolver)
1536
			throws java.io.UnsupportedEncodingException, IOException {
1338
1537
1339
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1538
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1340
		String stringId = id.toString();
1539
		String stringId = id.toString();
1341
		return getModelForEdit(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
1540
		return getModelForEdit(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
1342
	}
1541
	}
1343
1542
1344
	public  IStructuredModel getModelForEdit(String id, InputStream inputStream, URIResolver resolver) throws IOException {
1543
	public IStructuredModel getModelForEdit(String id, InputStream inputStream, URIResolver resolver)
1544
			throws IOException {
1345
		if (id == null) {
1545
		if (id == null) {
1346
			throw new IllegalArgumentException("Program Error: id may not be null"); //$NON-NLS-1$
1546
			throw new IllegalArgumentException("Program Error: id may not be null"); //$NON-NLS-1$
1347
		}
1547
		}
Lines 1361-1383 Link Here
1361
	/**
1561
	/**
1362
	 * One of the primary forms to get a managed model
1562
	 * One of the primary forms to get a managed model
1363
	 */
1563
	 */
1364
	public  IStructuredModel getModelForRead(IFile iFile) throws IOException, CoreException {
1564
	public IStructuredModel getModelForRead(IFile iFile) throws IOException, CoreException {
1365
1565
1366
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1566
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1367
		return _commonGetModel(iFile, READ, null, null);
1567
		return _commonGetModel(iFile, READ, null, null);
1368
	}
1568
	}
1369
1569
1370
	public  IStructuredModel getModelForRead(IFile iFile, EncodingRule encodingRule) throws UnsupportedEncodingException, IOException, CoreException {
1570
	public IStructuredModel getModelForRead(IFile iFile, EncodingRule encodingRule)
1571
			throws UnsupportedEncodingException, IOException, CoreException {
1371
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1572
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1372
		return _commonGetModel(iFile, READ, encodingRule);
1573
		return _commonGetModel(iFile, READ, encodingRule);
1373
	}
1574
	}
1374
1575
1375
	public  IStructuredModel getModelForRead(IFile iFile, String encodingName, String lineDelimiter) throws java.io.UnsupportedEncodingException, IOException, CoreException {
1576
	public IStructuredModel getModelForRead(IFile iFile, String encodingName, String lineDelimiter)
1577
			throws java.io.UnsupportedEncodingException, IOException, CoreException {
1376
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1578
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1377
		return _commonGetModel(iFile, READ, encodingName, lineDelimiter);
1579
		return _commonGetModel(iFile, READ, encodingName, lineDelimiter);
1378
	}
1580
	}
1379
1581
1380
	public  IStructuredModel getModelForRead(IStructuredDocument document) {
1582
	public IStructuredModel getModelForRead(IStructuredDocument document) {
1381
		return _getModelFor(document, READ);
1583
		return _getModelFor(document, READ);
1382
	}
1584
	}
1383
1585
Lines 1385-1391 Link Here
1385
	 * @see IModelManager
1587
	 * @see IModelManager
1386
	 * @deprecated use IFile or String form
1588
	 * @deprecated use IFile or String form
1387
	 */
1589
	 */
1388
	public  IStructuredModel getModelForRead(Object id, InputStream inputStream, URIResolver resolver) throws java.io.UnsupportedEncodingException, IOException {
1590
	public IStructuredModel getModelForRead(Object id, InputStream inputStream, URIResolver resolver)
1591
			throws java.io.UnsupportedEncodingException, IOException {
1389
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1592
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1390
		String stringId = id.toString();
1593
		String stringId = id.toString();
1391
		return getModelForRead(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
1594
		return getModelForRead(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
Lines 1395-1407 Link Here
1395
	 * @see IModelManager
1598
	 * @see IModelManager
1396
	 * @deprecated use IFile form
1599
	 * @deprecated use IFile form
1397
	 */
1600
	 */
1398
	public  IStructuredModel getModelForRead(Object id, Object modelType, String encodingName, String lineDelimiter, InputStream inputStream, URIResolver resolver) throws java.io.UnsupportedEncodingException, IOException {
1601
	public IStructuredModel getModelForRead(Object id, Object modelType, String encodingName,
1602
			String lineDelimiter, InputStream inputStream, URIResolver resolver)
1603
			throws java.io.UnsupportedEncodingException, IOException {
1399
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1604
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1400
		String stringId = id.toString();
1605
		String stringId = id.toString();
1401
		return getModelForRead(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
1606
		return getModelForRead(stringId, Utilities.getMarkSupportedStream(inputStream), resolver);
1402
	}
1607
	}
1403
1608
1404
	public  IStructuredModel getModelForRead(String id, InputStream inputStream, URIResolver resolver) throws IOException {
1609
	public IStructuredModel getModelForRead(String id, InputStream inputStream, URIResolver resolver)
1610
			throws IOException {
1405
		InputStream istream = Utilities.getMarkSupportedStream(inputStream);
1611
		InputStream istream = Utilities.getMarkSupportedStream(inputStream);
1406
		IModelHandler handler = calculateType(id, istream);
1612
		IModelHandler handler = calculateType(id, istream);
1407
		IStructuredModel result = null;
1613
		IStructuredModel result = null;
Lines 1422-1431 Link Here
1422
	/**
1628
	/**
1423
	 * @see IModelManager#getNewModelForEdit(IFile, boolean)
1629
	 * @see IModelManager#getNewModelForEdit(IFile, boolean)
1424
	 */
1630
	 */
1425
	public  IStructuredModel getNewModelForEdit(IFile iFile, boolean force) throws ResourceAlreadyExists, ResourceInUse, IOException, CoreException {
1631
	public IStructuredModel getNewModelForEdit(IFile iFile, boolean force)
1632
			throws ResourceAlreadyExists, ResourceInUse, IOException, CoreException {
1426
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1633
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1427
		SharedObject sharedObject = _commonNewModel(iFile, force);
1634
		SharedObject sharedObject = _commonNewModel(iFile, force);
1428
		synchronized(sharedObject) {
1635
		synchronized (sharedObject) {
1429
			sharedObject.referenceCountForEdit = 1;
1636
			sharedObject.referenceCountForEdit = 1;
1430
		}
1637
		}
1431
		sharedObject.setLoaded();
1638
		sharedObject.setLoaded();
Lines 1435-1451 Link Here
1435
	/**
1642
	/**
1436
	 * @see IModelManager#getNewModelForRead(IFile, boolean)
1643
	 * @see IModelManager#getNewModelForRead(IFile, boolean)
1437
	 */
1644
	 */
1438
	public  IStructuredModel getNewModelForRead(IFile iFile, boolean force) throws ResourceAlreadyExists, ResourceInUse, IOException, CoreException {
1645
	public IStructuredModel getNewModelForRead(IFile iFile, boolean force)
1646
			throws ResourceAlreadyExists, ResourceInUse, IOException, CoreException {
1439
1647
1440
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1648
		Assert.isNotNull(iFile, "IFile parameter can not be null"); //$NON-NLS-1$
1441
		SharedObject sharedObject = _commonNewModel(iFile, force);
1649
		SharedObject sharedObject = _commonNewModel(iFile, force);
1442
		SYNC.acquire();
1650
		SYNC.acquire();
1443
		synchronized(sharedObject) {
1651
		try {
1444
			if (sharedObject.theSharedModel!=null) {
1652
			synchronized (sharedObject) {
1445
				sharedObject.referenceCountForRead = 1;
1653
				if (sharedObject.theSharedModel != null) {
1654
					sharedObject.referenceCountForRead = 1;
1655
				}
1446
			}
1656
			}
1447
		}
1657
		}
1448
		SYNC.release();
1658
		finally {
1659
			SYNC.release();
1660
		}
1449
		sharedObject.setLoaded();
1661
		sharedObject.setLoaded();
1450
		return sharedObject.theSharedModel;
1662
		return sharedObject.theSharedModel;
1451
	}
1663
	}
Lines 1454-1477 Link Here
1454
	 * This function returns the reference count of underlying model.
1666
	 * This function returns the reference count of underlying model.
1455
	 * 
1667
	 * 
1456
	 * @param id
1668
	 * @param id
1457
	 *            Object The id of the model TODO: try to refine the design
1669
	 *            Object The id of the model TODO: try to refine the design not
1458
	 *            not to use this function
1670
	 *            to use this function
1459
	 */
1671
	 */
1460
	public  int getReferenceCount(Object id) {
1672
	public int getReferenceCount(Object id) {
1461
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1673
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1462
		int count = 0;
1674
		int count = 0;
1463
	
1675
1676
		SharedObject sharedObject = null;
1464
		SYNC.acquire();
1677
		SYNC.acquire();
1465
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1678
		try {
1466
		if (sharedObject != null) {
1679
			sharedObject = (SharedObject) fManagedObjects.get(id);
1680
		}
1681
		finally {
1467
			SYNC.release();
1682
			SYNC.release();
1468
			sharedObject.waitForLoadAttempt();
1683
			if (sharedObject != null) {
1469
			SYNC.acquire();
1684
				sharedObject.waitForLoadAttempt();
1470
			synchronized (sharedObject) {
1685
				SYNC.acquire();
1471
				count = sharedObject.referenceCountForRead + sharedObject.referenceCountForEdit;
1686
				try {
1687
					synchronized (sharedObject) {
1688
						count = sharedObject.referenceCountForRead
1689
								+ sharedObject.referenceCountForEdit;
1690
					}
1691
				}
1692
				finally {
1693
					SYNC.release();
1694
				}
1472
			}
1695
			}
1473
		}
1696
		}
1474
		SYNC.release();
1475
		return count;
1697
		return count;
1476
	}
1698
	}
1477
1699
Lines 1479-1500 Link Here
1479
	 * This function returns the reference count of underlying model.
1701
	 * This function returns the reference count of underlying model.
1480
	 * 
1702
	 * 
1481
	 * @param id
1703
	 * @param id
1482
	 *            Object The id of the model TODO: try to refine the design
1704
	 *            Object The id of the model TODO: try to refine the design not
1483
	 *            not to use this function
1705
	 *            to use this function
1484
	 */
1706
	 */
1485
	public int getReferenceCountForEdit(Object id) {
1707
	public int getReferenceCountForEdit(Object id) {
1486
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1708
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1487
		int count = 0;
1709
		int count = 0;
1710
		SharedObject sharedObject = null;
1488
		SYNC.acquire();
1711
		SYNC.acquire();
1489
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1712
		try {
1490
		if (sharedObject != null) {
1713
			sharedObject = (SharedObject) fManagedObjects.get(id);
1714
		}
1715
		finally {
1491
			SYNC.release();
1716
			SYNC.release();
1492
			sharedObject.waitForLoadAttempt();
1717
			if (sharedObject != null) {
1493
			synchronized(sharedObject) {
1718
				sharedObject.waitForLoadAttempt();
1494
				count = sharedObject.referenceCountForEdit;
1719
				synchronized (sharedObject) {
1720
					count = sharedObject.referenceCountForEdit;
1721
				}
1495
			}
1722
			}
1496
		} else {
1497
			SYNC.release();
1498
		}
1723
		}
1499
		return count;
1724
		return count;
1500
	}
1725
	}
Lines 1503-1529 Link Here
1503
	 * This function returns the reference count of underlying model.
1728
	 * This function returns the reference count of underlying model.
1504
	 * 
1729
	 * 
1505
	 * @param id
1730
	 * @param id
1506
	 *            Object The id of the model TODO: try to refine the design
1731
	 *            Object The id of the model TODO: try to refine the design not
1507
	 *            not to use this function
1732
	 *            to use this function
1508
	 */
1733
	 */
1509
	public int getReferenceCountForRead(Object id) {
1734
	public int getReferenceCountForRead(Object id) {
1510
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1735
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1511
		int count = 0;
1736
		int count = 0;
1737
		SharedObject sharedObject = null;
1512
		SYNC.acquire();
1738
		SYNC.acquire();
1513
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1739
		try {
1514
		if (sharedObject != null) {
1740
			sharedObject = (SharedObject) fManagedObjects.get(id);
1741
		}
1742
		finally {
1515
			SYNC.release();
1743
			SYNC.release();
1516
			sharedObject.waitForLoadAttempt();
1744
			if (sharedObject != null) {
1517
			SYNC.acquire();
1745
				sharedObject.waitForLoadAttempt();
1518
			synchronized(sharedObject) {
1746
				SYNC.acquire();
1519
				count = sharedObject.referenceCountForRead;
1747
				try {
1748
					synchronized (sharedObject) {
1749
						count = sharedObject.referenceCountForRead;
1750
					}
1751
				}
1752
				finally {
1753
					SYNC.release();
1754
				}
1520
			}
1755
			}
1521
		}
1756
		}
1522
		SYNC.release();
1523
		return count;
1757
		return count;
1524
	}
1758
	}
1525
1759
1526
	private void handleConvertLineDelimiters(IStructuredDocument structuredDocument, IFile iFile, EncodingRule encodingRule, EncodingMemento encodingMemento) throws CoreException, MalformedOutputExceptionWithDetail, UnsupportedEncodingException {
1760
	private void handleConvertLineDelimiters(IStructuredDocument structuredDocument, IFile iFile,
1761
			EncodingRule encodingRule, EncodingMemento encodingMemento) throws CoreException,
1762
			MalformedOutputExceptionWithDetail, UnsupportedEncodingException {
1527
		if (structuredDocument.getNumberOfLines() > 1) {
1763
		if (structuredDocument.getNumberOfLines() > 1) {
1528
			convertLineDelimiters(structuredDocument, iFile);
1764
			convertLineDelimiters(structuredDocument, iFile);
1529
		}
1765
		}
Lines 1538-1558 Link Here
1538
	 * This function returns true if there are other references to the
1774
	 * This function returns true if there are other references to the
1539
	 * underlying model.
1775
	 * underlying model.
1540
	 */
1776
	 */
1541
	public  boolean isShared(Object id) {
1777
	public boolean isShared(Object id) {
1542
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1778
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1543
		int count = 0;
1779
		int count = 0;
1544
		boolean result = false;
1780
		boolean result = false;
1781
		SharedObject sharedObject = null;
1545
		SYNC.acquire();
1782
		SYNC.acquire();
1546
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1783
		try {
1547
		if (sharedObject != null) {
1784
			sharedObject = (SharedObject) fManagedObjects.get(id);
1785
		}
1786
		finally {
1548
			SYNC.release();
1787
			SYNC.release();
1549
			sharedObject.waitForLoadAttempt();
1788
			if (sharedObject != null) {
1550
			SYNC.acquire();
1789
				sharedObject.waitForLoadAttempt();
1551
			synchronized(sharedObject) {
1790
				SYNC.acquire();
1552
				count = sharedObject.referenceCountForRead + sharedObject.referenceCountForEdit;
1791
				try {
1792
					synchronized (sharedObject) {
1793
						count = sharedObject.referenceCountForRead
1794
								+ sharedObject.referenceCountForEdit;
1795
					}
1796
				}
1797
				finally {
1798
					SYNC.release();
1799
				}
1553
			}
1800
			}
1554
		}
1801
		}
1555
		SYNC.release();
1802
1556
		result = count > 1;
1803
		result = count > 1;
1557
		return result;
1804
		return result;
1558
	}
1805
	}
Lines 1564-1583 Link Here
1564
	 * @param id
1811
	 * @param id
1565
	 *            Object The id of the model
1812
	 *            Object The id of the model
1566
	 */
1813
	 */
1567
	public  boolean isSharedForEdit(Object id) {
1814
	public boolean isSharedForEdit(Object id) {
1568
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1815
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1569
		int count = 0;
1816
		int count = 0;
1570
		boolean result = false;
1817
		boolean result = false;
1818
		SharedObject sharedObject = null;
1571
		SYNC.acquire();
1819
		SYNC.acquire();
1572
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1820
		try {
1573
		if (sharedObject != null) {
1821
			sharedObject = (SharedObject) fManagedObjects.get(id);
1822
		}
1823
		finally {
1574
			SYNC.release();
1824
			SYNC.release();
1575
			sharedObject.waitForLoadAttempt();
1825
			if (sharedObject != null) {
1576
			synchronized(sharedObject) {
1826
				sharedObject.waitForLoadAttempt();
1577
				count = sharedObject.referenceCountForEdit;
1827
				SYNC.acquire();
1828
				try {
1829
					synchronized (sharedObject) {
1830
						count = sharedObject.referenceCountForEdit;
1831
					}
1832
				}
1833
				finally {
1834
					SYNC.release();
1835
				}
1578
			}
1836
			}
1579
		} else {
1580
			SYNC.release();
1581
		}
1837
		}
1582
		result = count > 1;
1838
		result = count > 1;
1583
		return result;
1839
		return result;
Lines 1590-1610 Link Here
1590
	 * @param id
1846
	 * @param id
1591
	 *            Object The id of the model
1847
	 *            Object The id of the model
1592
	 */
1848
	 */
1593
	public  boolean isSharedForRead(Object id) {
1849
	public boolean isSharedForRead(Object id) {
1594
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1850
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1595
		int count = 0;
1851
		int count = 0;
1596
		boolean result = false;
1852
		boolean result = false;
1853
		SharedObject sharedObject = null;
1597
		SYNC.acquire();
1854
		SYNC.acquire();
1598
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
1855
		try {
1599
		if (sharedObject != null) {
1856
			sharedObject = (SharedObject) fManagedObjects.get(id);
1857
		}
1858
		finally {
1600
			SYNC.release();
1859
			SYNC.release();
1601
			sharedObject.waitForLoadAttempt();
1860
			if (sharedObject != null) {
1602
			SYNC.acquire();
1861
				sharedObject.waitForLoadAttempt();
1603
			synchronized(sharedObject) {
1862
				SYNC.acquire();
1604
				count = sharedObject.referenceCountForRead;
1863
				try {
1864
					synchronized (sharedObject) {
1865
						count = sharedObject.referenceCountForRead;
1866
					}
1867
				}
1868
				finally {
1869
					SYNC.release();
1870
				}
1605
			}
1871
			}
1606
		}
1872
		}
1607
		SYNC.release();
1608
		result = count > 1;
1873
		result = count > 1;
1609
		return result;
1874
		return result;
1610
	}
1875
	}
Lines 1626-1644 Link Here
1626
	 * not to use this function
1891
	 * not to use this function
1627
	 */
1892
	 */
1628
	public void moveModel(Object oldId, Object newId) {
1893
	public void moveModel(Object oldId, Object newId) {
1629
		org.eclipse.wst.sse.core.internal.util.Assert.isNotNull(oldId, "id parameter can not be null"); //$NON-NLS-1$
1894
		org.eclipse.wst.sse.core.internal.util.Assert.isNotNull(oldId,
1895
				"id parameter can not be null"); //$NON-NLS-1$
1896
		SharedObject sharedObject = null;
1630
		SYNC.acquire();
1897
		SYNC.acquire();
1631
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(oldId);
1898
		try {
1632
		// if not found in cache, ignore request.
1899
			// if not found in cache, ignore request.
1633
		// this would normally be a program error
1900
			// this would normally be a program error
1634
		if (sharedObject != null) {
1901
			sharedObject = (SharedObject) fManagedObjects.get(oldId);
1635
			fManagedObjects.remove(oldId);
1902
			if (sharedObject != null) {
1636
			fManagedObjects.put(newId, sharedObject);
1903
				fManagedObjects.remove(oldId);
1904
				fManagedObjects.put(newId, sharedObject);
1905
			}
1906
		}
1907
		finally {
1908
			SYNC.release();
1637
		}
1909
		}
1638
		SYNC.release();
1639
	}
1910
	}
1640
1911
1641
	private String readInputStream(InputStream inputStream, String ianaEncodingName) throws UnsupportedEncodingException, IOException {
1912
	private String readInputStream(InputStream inputStream, String ianaEncodingName)
1913
			throws UnsupportedEncodingException, IOException {
1642
1914
1643
		String allText = null;
1915
		String allText = null;
1644
		if ((ianaEncodingName != null) && (ianaEncodingName.length() != 0)) {
1916
		if ((ianaEncodingName != null) && (ianaEncodingName.length() != 0)) {
Lines 1699-1705 Link Here
1699
		return model;
1971
		return model;
1700
	}
1972
	}
1701
1973
1702
	 void releaseFromEdit(IStructuredModel structuredModel) {
1974
	void releaseFromEdit(IStructuredModel structuredModel) {
1703
		Object id = structuredModel.getId();
1975
		Object id = structuredModel.getId();
1704
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1976
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1705
			cleanupDiscardedModel(structuredModel);
1977
			cleanupDiscardedModel(structuredModel);
Lines 1709-1716 Link Here
1709
		}
1981
		}
1710
1982
1711
	}
1983
	}
1712
	
1984
1713
	 void releaseFromRead(IStructuredModel structuredModel) {
1985
	void releaseFromRead(IStructuredModel structuredModel) {
1714
		Object id = structuredModel.getId();
1986
		Object id = structuredModel.getId();
1715
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1987
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1716
			cleanupDiscardedModel(structuredModel);
1988
			cleanupDiscardedModel(structuredModel);
Lines 1720-1730 Link Here
1720
		}
1992
		}
1721
1993
1722
	}
1994
	}
1995
1723
	/**
1996
	/**
1724
	 * default for use in same package, not subclasses
1997
	 * default for use in same package, not subclasses
1725
	 * 
1998
	 * 
1726
	 */
1999
	 */
1727
	 private void releaseFromEdit(Object id) {
2000
	private void releaseFromEdit(Object id) {
1728
		// ISSUE: many of these asserts should be changed to "logs"
2001
		// ISSUE: many of these asserts should be changed to "logs"
1729
		// and continue to limp along?
2002
		// and continue to limp along?
1730
2003
Lines 1736-1759 Link Here
1736
		// to be called on them, for now, but the model manager
2009
		// to be called on them, for now, but the model manager
1737
		// doesn't need to do anything.
2010
		// doesn't need to do anything.
1738
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
2011
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1739
			throw new IllegalArgumentException("Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
2012
			throw new IllegalArgumentException(
2013
					"Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
1740
		}
2014
		}
1741
		else {
2015
		else {
1742
			SYNC.acquire();
2016
			SYNC.acquire();
1743
			sharedObject = (SharedObject) fManagedObjects.get(id);
2017
			try {
1744
			SYNC.release();
2018
				sharedObject = (SharedObject) fManagedObjects.get(id);
1745
			
2019
			}
1746
			Assert.isNotNull(sharedObject, "release was requested on a model that was not being managed"); //$NON-NLS-1$
2020
			finally {
2021
				SYNC.release();
2022
			}
2023
2024
			Assert.isNotNull(sharedObject,
2025
					"release was requested on a model that was not being managed"); //$NON-NLS-1$
1747
			sharedObject.waitForLoadAttempt();
2026
			sharedObject.waitForLoadAttempt();
1748
			
2027
1749
			SYNC.acquire();
2028
			SYNC.acquire();
1750
			synchronized(sharedObject) {
2029
			try {
1751
				_decrCount(sharedObject, EDIT);
2030
				synchronized (sharedObject) {
1752
				if ((sharedObject.referenceCountForRead == 0) && (sharedObject.referenceCountForEdit == 0)) {
2031
					_decrCount(sharedObject, EDIT);
1753
					discardModel(id, sharedObject);
2032
					if ((sharedObject.referenceCountForRead == 0)
2033
							&& (sharedObject.referenceCountForEdit == 0)) {
2034
						discardModel(id, sharedObject);
2035
					}
1754
				}
2036
				}
1755
			}
2037
			}
1756
			SYNC.release();
2038
			finally {
2039
				SYNC.release();
2040
			}
1757
			// if edit goes to zero, but still open for read,
2041
			// if edit goes to zero, but still open for read,
1758
			// then we should reload here, so we are in synch with
2042
			// then we should reload here, so we are in synch with
1759
			// contents on disk.
2043
			// contents on disk.
Lines 1762-1792 Link Here
1762
			// flag for some reason.
2046
			// flag for some reason.
1763
			// we need to address * that * too.
2047
			// we need to address * that * too.
1764
2048
1765
			synchronized(sharedObject) {
2049
			synchronized (sharedObject) {
1766
				if ((sharedObject.referenceCountForRead > 0) && (sharedObject.referenceCountForEdit == 0) && sharedObject.theSharedModel.isDirty()) {
2050
				if ((sharedObject.referenceCountForRead > 0)
2051
						&& (sharedObject.referenceCountForEdit == 0)
2052
						&& sharedObject.theSharedModel.isDirty()) {
1767
					signalPreLifeCycleListenerRevert(sharedObject.theSharedModel);
2053
					signalPreLifeCycleListenerRevert(sharedObject.theSharedModel);
1768
					revertModel(id, sharedObject);
2054
					revertModel(id, sharedObject);
1769
					/*
2055
					/*
1770
					 * Because model events are fired to notify about the
2056
					 * Because model events are fired to notify about the
1771
					 * revert's changes, and listeners can still get/release
2057
					 * revert's changes, and listeners can still get/release the
1772
					 * the model from this thread (locking prevents it being
2058
					 * model from this thread (locking prevents it being done
1773
					 * done from other threads), the reference counts could
2059
					 * from other threads), the reference counts could have
1774
					 * have changed since we entered this if block, and the
2060
					 * changed since we entered this if block, and the model
1775
					 * model could have been discarded.  Check the counts again.
2061
					 * could have been discarded. Check the counts again.
1776
					 */
2062
					 */
1777
					if (sharedObject.referenceCountForRead > 0 && sharedObject.referenceCountForEdit == 0) {
2063
					if (sharedObject.referenceCountForRead > 0
2064
							&& sharedObject.referenceCountForEdit == 0) {
1778
						sharedObject.theSharedModel.setDirtyState(false);
2065
						sharedObject.theSharedModel.setDirtyState(false);
1779
					}
2066
					}
1780
					signalPostLifeCycleListenerRevert(sharedObject.theSharedModel);
2067
					signalPostLifeCycleListenerRevert(sharedObject.theSharedModel);
1781
				}
2068
				}
1782
			}
2069
			}
1783
			
2070
1784
		}
2071
		}
1785
	}
2072
	}
1786
2073
1787
	// private for now, though public forms have been requested, in past.
2074
	// private for now, though public forms have been requested, in past.
1788
	private void revertModel(Object id, SharedObject sharedObject) {
2075
	private void revertModel(Object id, SharedObject sharedObject) {
1789
		IStructuredDocument structuredDocument = sharedObject.theSharedModel.getStructuredDocument();
2076
		IStructuredDocument structuredDocument = sharedObject.theSharedModel
2077
				.getStructuredDocument();
1790
		FileBufferModelManager.getInstance().revert(structuredDocument);
2078
		FileBufferModelManager.getInstance().revert(structuredDocument);
1791
	}
2079
	}
1792
2080
Lines 1806-1817 Link Here
1806
2094
1807
	private void discardModel(Object id, SharedObject sharedObject) {
2095
	private void discardModel(Object id, SharedObject sharedObject) {
1808
		SYNC.acquire();
2096
		SYNC.acquire();
1809
		fManagedObjects.remove(id);
2097
		try {
1810
		SYNC.release();
2098
			fManagedObjects.remove(id);
1811
		IStructuredDocument structuredDocument = sharedObject.theSharedModel.getStructuredDocument();
2099
		}
2100
		finally {
2101
			SYNC.release();
2102
		}
2103
		IStructuredDocument structuredDocument = sharedObject.theSharedModel
2104
				.getStructuredDocument();
1812
2105
1813
		if (structuredDocument == null) {
2106
		if (structuredDocument == null) {
1814
			Platform.getLog(SSECorePlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, SSECorePlugin.ID, IStatus.ERROR, "Attempted to discard a structured model but the underlying document has already been set to null: " + sharedObject.theSharedModel.getBaseLocation(), null));
2107
			Platform
2108
					.getLog(SSECorePlugin.getDefault().getBundle())
2109
					.log(
2110
							new Status(
2111
									IStatus.ERROR,
2112
									SSECorePlugin.ID,
2113
									IStatus.ERROR,
2114
									"Attempted to discard a structured model but the underlying document has already been set to null: "
2115
											+ sharedObject.theSharedModel.getBaseLocation(), null));
1815
		}
2116
		}
1816
2117
1817
		cleanupDiscardedModel(sharedObject.theSharedModel);
2118
		cleanupDiscardedModel(sharedObject.theSharedModel);
Lines 1821-1841 Link Here
1821
		IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
2122
		IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
1822
		/*
2123
		/*
1823
		 * This call (and setting the StructuredDocument to null) were
2124
		 * This call (and setting the StructuredDocument to null) were
1824
		 * previously done within the model itself, but for concurrency it
2125
		 * previously done within the model itself, but for concurrency it must
1825
		 * must be done here during a synchronized release.
2126
		 * be done here during a synchronized release.
1826
		 */
2127
		 */
1827
		structuredModel.getFactoryRegistry().release();
2128
		structuredModel.getFactoryRegistry().release();
1828
2129
1829
		/*
2130
		/*
1830
		 * For structured documents originating from file buffers, disconnect
2131
		 * For structured documents originating from file buffers, disconnect us
1831
		 * us from the file buffer, now.
2132
		 * from the file buffer, now.
1832
		 */
2133
		 */
1833
		FileBufferModelManager.getInstance().releaseModel(structuredDocument);
2134
		FileBufferModelManager.getInstance().releaseModel(structuredDocument);
1834
2135
1835
		/*
2136
		/*
1836
		 * Setting the document to null is required since some subclasses of
2137
		 * Setting the document to null is required since some subclasses of
1837
		 * model might have "cleanup" of listeners, etc., to remove, which
2138
		 * model might have "cleanup" of listeners, etc., to remove, which were
1838
		 * were initialized during the initial setStructuredDocument.
2139
		 * initialized during the initial setStructuredDocument.
1839
		 * 
2140
		 * 
1840
		 * The model itself in particular may have internal listeners used to
2141
		 * The model itself in particular may have internal listeners used to
1841
		 * coordinate the document with its own "structure".
2142
		 * coordinate the document with its own "structure".
Lines 1843-1888 Link Here
1843
		structuredModel.setStructuredDocument(null);
2144
		structuredModel.setStructuredDocument(null);
1844
	}
2145
	}
1845
2146
1846
	
1847
	/**
2147
	/**
1848
	 * default for use in same package, not subclasses
2148
	 * default for use in same package, not subclasses
1849
	 * 
2149
	 * 
1850
	 */
2150
	 */
1851
	 private void releaseFromRead(Object id) {
2151
	private void releaseFromRead(Object id) {
1852
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
2152
		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
1853
		SharedObject sharedObject = null;
2153
		SharedObject sharedObject = null;
1854
2154
1855
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
2155
		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
1856
			throw new IllegalArgumentException("Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
2156
			throw new IllegalArgumentException(
2157
					"Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
1857
		}
2158
		}
1858
		else {
2159
		else {
1859
			SYNC.acquire();
2160
			SYNC.acquire();
1860
			sharedObject = (SharedObject) fManagedObjects.get(id);
2161
			try {
1861
			SYNC.release();
2162
				sharedObject = (SharedObject) fManagedObjects.get(id);
1862
			Assert.isNotNull(sharedObject, "release was requested on a model that was not being managed"); //$NON-NLS-1$
2163
			}
2164
			finally {
2165
				SYNC.release();
2166
			}
2167
			Assert.isNotNull(sharedObject,
2168
					"release was requested on a model that was not being managed"); //$NON-NLS-1$
1863
			sharedObject.waitForLoadAttempt();
2169
			sharedObject.waitForLoadAttempt();
1864
		}
2170
		}
1865
		SYNC.acquire();
2171
		SYNC.acquire();
1866
		synchronized(sharedObject) {
2172
		try {
1867
			_decrCount(sharedObject, READ);
2173
			synchronized (sharedObject) {
1868
			if ((sharedObject.referenceCountForRead == 0) && (sharedObject.referenceCountForEdit == 0)) {
2174
				_decrCount(sharedObject, READ);
1869
				discardModel(id, sharedObject);
2175
				if ((sharedObject.referenceCountForRead == 0)
2176
						&& (sharedObject.referenceCountForEdit == 0)) {
2177
					discardModel(id, sharedObject);
2178
				}
1870
			}
2179
			}
1871
		}
2180
		}
1872
		SYNC.release();
2181
		finally {
2182
			SYNC.release();
2183
		}
1873
	}
2184
	}
1874
2185
1875
	/**
2186
	/**
1876
	 * This is similar to the getModel method, except this method does not use
2187
	 * This is similar to the getModel method, except this method does not use
1877
	 * the cached version, but forces the cached version to be replaced with a
2188
	 * the cached version, but forces the cached version to be replaced with a
1878
	 * fresh, unchanged version. Note: this method does not change any
2189
	 * fresh, unchanged version. Note: this method does not change any reference
1879
	 * reference counts. Also, if there is not already a cached version of the
2190
	 * counts. Also, if there is not already a cached version of the model, then
1880
	 * model, then this call is essentially ignored (that is, it does not put
2191
	 * this call is essentially ignored (that is, it does not put a model in the
1881
	 * a model in the cache) and returns null.
2192
	 * cache) and returns null.
1882
	 * 
2193
	 * 
1883
	 * @deprecated - will become protected, use reload directly on model
2194
	 * @deprecated - will become protected, use reload directly on model
1884
	 */
2195
	 */
1885
	public  IStructuredModel reloadModel(Object id, java.io.InputStream inputStream) throws java.io.UnsupportedEncodingException {
2196
	public IStructuredModel reloadModel(Object id, java.io.InputStream inputStream)
2197
			throws java.io.UnsupportedEncodingException {
1886
2198
1887
		// get the existing model associated with this id
2199
		// get the existing model associated with this id
1888
		IStructuredModel structuredModel = getExistingModel(id);
2200
		IStructuredModel structuredModel = getExistingModel(id);
Lines 1903-1951 Link Here
1903
		return structuredModel;
2215
		return structuredModel;
1904
	}
2216
	}
1905
2217
1906
	public void saveModel(IFile iFile, String id, EncodingRule encodingRule) throws UnsupportedEncodingException, IOException, CoreException {
2218
	public void saveModel(IFile iFile, String id, EncodingRule encodingRule)
2219
			throws UnsupportedEncodingException, IOException, CoreException {
1907
2220
1908
		// let's see if we already have it in our cache
2221
		// let's see if we already have it in our cache
1909
	
2222
		SharedObject sharedObject = null;
1910
		SYNC.acquire();
2223
		SYNC.acquire();
1911
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
2224
		try {
1912
		if (sharedObject == null || sharedObject.theSharedModel == null) {
2225
			sharedObject = (SharedObject) fManagedObjects.get(id);
2226
		}
2227
		finally {
1913
			SYNC.release();
2228
			SYNC.release();
2229
		}
2230
		if (sharedObject == null || sharedObject.theSharedModel == null) {
1914
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
2231
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
1915
		} 
2232
		}
1916
		else {
2233
1917
			SYNC.release();
2234
		// Note to self: not clear if this does anything.
1918
			sharedObject.waitForLoadAttempt();
2235
		// sharedObject.theSharedModel cannot be null, so what are we waiting
1919
			
2236
		// for?
1920
			/**
2237
		sharedObject.waitForLoadAttempt();
1921
			 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=221610
2238
1922
			 * 
2239
		/**
1923
			 * Sync removed from here to prevent deadlock. Although the model
2240
		 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=221610
1924
			 * instance may disappear or be made invalid while the save is
2241
		 * 
1925
			 * happening, the document itself still has the contents we're
2242
		 * Sync removed from here to prevent deadlock. Although the model
1926
			 * trying to save. Simultaneous saves should be throttled by
2243
		 * instance may disappear or be made invalid while the save is
1927
			 * resource locking without our intervention.
2244
		 * happening, the document itself still has the contents we're trying to
1928
			 */
2245
		 * save. Simultaneous saves should be throttled by resource locking
1929
			boolean saved = false;
2246
		 * without our intervention.
1930
			// if this model was based on a File Buffer and we're writing back
2247
		 */
1931
			// to the same location, use the buffer to do the writing
2248
		boolean saved = false;
1932
			if (FileBufferModelManager.getInstance().isExistingBuffer(sharedObject.theSharedModel.getStructuredDocument())) {
2249
		// if this model was based on a File Buffer and we're writing back
1933
				ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(sharedObject.theSharedModel.getStructuredDocument());
2250
		// to the same location, use the buffer to do the writing
1934
				IPath fileLocation = FileBuffers.normalizeLocation(iFile.getFullPath());
2251
		if (FileBufferModelManager.getInstance().isExistingBuffer(
1935
				if (fileLocation.equals(buffer.getLocation())) {
2252
				sharedObject.theSharedModel.getStructuredDocument())) {
1936
					buffer.commit(new NullProgressMonitor(), true);
2253
			ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(
1937
					saved = true;
2254
					sharedObject.theSharedModel.getStructuredDocument());
1938
				}
2255
			IPath fileLocation = FileBuffers.normalizeLocation(iFile.getFullPath());
1939
			}
2256
			if (fileLocation.equals(buffer.getLocation())) {
1940
			if (!saved) {
2257
				buffer.commit(new NullProgressMonitor(), true);
1941
				IStructuredModel model = sharedObject.theSharedModel;
2258
				saved = true;
1942
				IStructuredDocument document = model.getStructuredDocument();
1943
				saveStructuredDocument(document, iFile, encodingRule);
1944
				trace("saving model", id); //$NON-NLS-1$
1945
			}
2259
			}
1946
			sharedObject.theSharedModel.setDirtyState(false);
2260
		}
1947
			sharedObject.theSharedModel.setNewState(false);
2261
		if (!saved) {
1948
		}	
2262
			IStructuredModel model = sharedObject.theSharedModel;
2263
			IStructuredDocument document = model.getStructuredDocument();
2264
			saveStructuredDocument(document, iFile, encodingRule);
2265
			trace("saving model", id); //$NON-NLS-1$
2266
		}
2267
		sharedObject.theSharedModel.setDirtyState(false);
2268
		sharedObject.theSharedModel.setNewState(false);
2269
1949
	}
2270
	}
1950
2271
1951
	/**
2272
	/**
Lines 1958-2003 Link Here
1958
	 * @throws IOException
2279
	 * @throws IOException
1959
	 * @throws CoreException
2280
	 * @throws CoreException
1960
	 */
2281
	 */
1961
	public void saveModel(String id, EncodingRule encodingRule) throws UnsupportedEncodingException, IOException, CoreException {
2282
	public void saveModel(String id, EncodingRule encodingRule)
2283
			throws UnsupportedEncodingException, IOException, CoreException {
1962
2284
1963
		// let's see if we already have it in our cache
2285
		// let's see if we already have it in our cache
1964
2286
		SharedObject sharedObject = null;
1965
		SYNC.acquire();
2287
		SYNC.acquire();
1966
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
2288
		try {
1967
		if (sharedObject == null) {
2289
			sharedObject = (SharedObject) fManagedObjects.get(id);
2290
		}
2291
		finally {
1968
			SYNC.release();
2292
			SYNC.release();
2293
		}
2294
		if (sharedObject == null) {
1969
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
2295
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
1970
		}
2296
		}
2297
2298
		// Note to self: not clear if this does anything.
2299
		// sharedObject.theSharedModel cannot be null, so what are we waiting
2300
		// for?
2301
		sharedObject.waitForLoadAttempt();
2302
		/**
2303
		 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=221610
2304
		 * 
2305
		 * Sync removed from here to prevent deadlock. Although the model
2306
		 * instance may disappear or be made invalid while the save is
2307
		 * happening, the document itself still has the contents we're trying to
2308
		 * save. Simultaneous saves should be throttled by resource locking
2309
		 * without our intervention.
2310
		 */
2311
		/*
2312
		 * if this model was based on a File Buffer and we're writing back to
2313
		 * the same location, use the buffer to do the writing
2314
		 */
2315
		if (FileBufferModelManager.getInstance().isExistingBuffer(
2316
				sharedObject.theSharedModel.getStructuredDocument())) {
2317
			ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(
2318
					sharedObject.theSharedModel.getStructuredDocument());
2319
			buffer.commit(new NullProgressMonitor(), true);
2320
		}
1971
		else {
2321
		else {
1972
			SYNC.release();
2322
			IFile iFile = getFileFor(sharedObject.theSharedModel);
1973
			sharedObject.waitForLoadAttempt();
2323
			IStructuredModel model = sharedObject.theSharedModel;
1974
			/**
2324
			IStructuredDocument document = model.getStructuredDocument();
1975
			 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=221610
2325
			saveStructuredDocument(document, iFile);
1976
			 * 
2326
			trace("saving model", id); //$NON-NLS-1$
1977
			 * Sync removed from here to prevent deadlock. Although the model
1978
			 * instance may disappear or be made invalid while the save is
1979
			 * happening, the document itself still has the contents we're
1980
			 * trying to save. Simultaneous saves should be throttled by
1981
			 * resource locking without our intervention.
1982
			 */
1983
			/*
1984
			 * if this model was based on a File Buffer and we're writing back
1985
			 * to the same location, use the buffer to do the writing
1986
			 */
1987
			if (FileBufferModelManager.getInstance().isExistingBuffer(sharedObject.theSharedModel.getStructuredDocument())) {
1988
				ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(sharedObject.theSharedModel.getStructuredDocument());
1989
				buffer.commit(new NullProgressMonitor(), true);
1990
			}
1991
			else {
1992
				IFile iFile = getFileFor(sharedObject.theSharedModel);
1993
				IStructuredModel model = sharedObject.theSharedModel;
1994
				IStructuredDocument document = model.getStructuredDocument();
1995
				saveStructuredDocument(document, iFile);
1996
				trace("saving model", id); //$NON-NLS-1$
1997
			}
1998
			sharedObject.theSharedModel.setDirtyState(false);
1999
			sharedObject.theSharedModel.setNewState(false);
2000
		}
2327
		}
2328
		sharedObject.theSharedModel.setDirtyState(false);
2329
		sharedObject.theSharedModel.setNewState(false);
2330
2001
	}
2331
	}
2002
2332
2003
	/**
2333
	/**
Lines 2005-2043 Link Here
2005
	 *             requires an extra "copy" of byte array, and should be avoid
2335
	 *             requires an extra "copy" of byte array, and should be avoid
2006
	 *             in favor of the IFile form.
2336
	 *             in favor of the IFile form.
2007
	 */
2337
	 */
2008
	public void saveModel(String id, OutputStream outputStream, EncodingRule encodingRule) throws UnsupportedEncodingException, CoreException, IOException {
2338
	public void saveModel(String id, OutputStream outputStream, EncodingRule encodingRule)
2339
			throws UnsupportedEncodingException, CoreException, IOException {
2340
		SharedObject sharedObject = null;
2009
		SYNC.acquire();
2341
		SYNC.acquire();
2010
		// let's see if we already have it in our cache
2342
		try {
2011
		SharedObject sharedObject = (SharedObject) fManagedObjects.get(id);
2343
			// let's see if we already have it in our cache
2012
		if (sharedObject == null) {
2344
			sharedObject = (SharedObject) fManagedObjects.get(id);
2345
		}
2346
		finally {
2013
			SYNC.release();
2347
			SYNC.release();
2348
		}
2349
		if (sharedObject == null) {
2350
2014
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
2351
			throw new IllegalStateException(SSECoreMessages.Program_Error__ModelManage_EXC_); //$NON-NLS-1$ = "Program Error: ModelManagerImpl::saveModel. Model should be in the cache"
2015
		}
2352
		}
2016
		else {
2353
		sharedObject.waitForLoadAttempt();
2017
			SYNC.release();
2354
		synchronized (sharedObject) {
2018
			sharedObject.waitForLoadAttempt();
2355
			CodedStreamCreator codedStreamCreator = new CodedStreamCreator();
2019
			synchronized(sharedObject) {
2356
			codedStreamCreator.set(sharedObject.theSharedModel.getId(), new DocumentReader(
2020
				CodedStreamCreator codedStreamCreator = new CodedStreamCreator();
2357
					sharedObject.theSharedModel.getStructuredDocument()));
2021
				codedStreamCreator.set(sharedObject.theSharedModel.getId(), new DocumentReader(sharedObject.theSharedModel.getStructuredDocument()));
2358
			codedStreamCreator.setPreviousEncodingMemento(sharedObject.theSharedModel
2022
				codedStreamCreator.setPreviousEncodingMemento(sharedObject.theSharedModel.getStructuredDocument().getEncodingMemento());
2359
					.getStructuredDocument().getEncodingMemento());
2023
				ByteArrayOutputStream byteArrayOutputStream = codedStreamCreator.getCodedByteArrayOutputStream(encodingRule);
2360
			ByteArrayOutputStream byteArrayOutputStream = codedStreamCreator
2024
				byte[] outputBytes = byteArrayOutputStream.toByteArray();
2361
					.getCodedByteArrayOutputStream(encodingRule);
2025
				outputStream.write(outputBytes);
2362
			byte[] outputBytes = byteArrayOutputStream.toByteArray();
2026
				trace("saving model", id); //$NON-NLS-1$
2363
			outputStream.write(outputBytes);
2027
				sharedObject.theSharedModel.setDirtyState(false);
2364
			trace("saving model", id); //$NON-NLS-1$
2028
				sharedObject.theSharedModel.setNewState(false);
2365
			sharedObject.theSharedModel.setDirtyState(false);
2029
			}
2366
			sharedObject.theSharedModel.setNewState(false);
2030
		}
2367
		}
2368
2031
	}
2369
	}
2032
2370
2033
	public void saveStructuredDocument(IStructuredDocument structuredDocument, IFile iFile) throws UnsupportedEncodingException, CoreException, IOException {
2371
	public void saveStructuredDocument(IStructuredDocument structuredDocument, IFile iFile)
2372
			throws UnsupportedEncodingException, CoreException, IOException {
2034
		saveStructuredDocument(structuredDocument, iFile, EncodingRule.CONTENT_BASED);
2373
		saveStructuredDocument(structuredDocument, iFile, EncodingRule.CONTENT_BASED);
2035
	}
2374
	}
2036
2375
2037
	public void saveStructuredDocument(IStructuredDocument structuredDocument, IFile iFile, EncodingRule encodingRule) throws UnsupportedEncodingException, CoreException, IOException {
2376
	public void saveStructuredDocument(IStructuredDocument structuredDocument, IFile iFile,
2377
			EncodingRule encodingRule) throws UnsupportedEncodingException, CoreException,
2378
			IOException {
2038
		if (FileBufferModelManager.getInstance().isExistingBuffer(structuredDocument)) {
2379
		if (FileBufferModelManager.getInstance().isExistingBuffer(structuredDocument)) {
2039
			ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(structuredDocument);
2380
			ITextFileBuffer buffer = FileBufferModelManager.getInstance().getBuffer(
2040
			if (buffer.getLocation().equals(iFile.getFullPath()) || buffer.getLocation().equals(iFile.getLocation())) {
2381
					structuredDocument);
2382
			if (buffer.getLocation().equals(iFile.getFullPath())
2383
					|| buffer.getLocation().equals(iFile.getLocation())) {
2041
				buffer.commit(new NullProgressMonitor(), true);
2384
				buffer.commit(new NullProgressMonitor(), true);
2042
			}
2385
			}
2043
		}
2386
		}
Lines 2059-2065 Link Here
2059
			// before writing to output stream.
2402
			// before writing to output stream.
2060
			handleConvertLineDelimiters(structuredDocument, iFile, encodingRule, encodingMemento);
2403
			handleConvertLineDelimiters(structuredDocument, iFile, encodingRule, encodingMemento);
2061
2404
2062
			ByteArrayOutputStream codedByteStream = codedStreamCreator.getCodedByteArrayOutputStream(encodingRule);
2405
			ByteArrayOutputStream codedByteStream = codedStreamCreator
2406
					.getCodedByteArrayOutputStream(encodingRule);
2063
			InputStream codedStream = new ByteArrayInputStream(codedByteStream.toByteArray());
2407
			InputStream codedStream = new ByteArrayInputStream(codedByteStream.toByteArray());
2064
			if (iFile.exists())
2408
			if (iFile.exists())
2065
				iFile.setContents(codedStream, true, true, null);
2409
				iFile.setContents(codedStream, true, true, null);
Lines 2088-2101 Link Here
2088
		}
2432
		}
2089
	}
2433
	}
2090
2434
2091
	 boolean isIdInUse(String newId) {
2435
	boolean isIdInUse(String newId) {
2092
			boolean inUse = false;
2436
		SharedObject object = null;
2093
			SYNC.acquire();
2437
		SYNC.acquire();
2094
			SharedObject object =(SharedObject) fManagedObjects.get(newId);
2438
		try {
2095
			if (object!=null) {
2439
			object = (SharedObject) fManagedObjects.get(newId);
2096
				inUse = object.theSharedModel!=null;
2440
		}
2097
			}
2441
		finally {
2098
			SYNC.release();
2442
			SYNC.release();
2099
			return inUse;
2100
		}
2443
		}
2444
		return object != null ? object.theSharedModel != null : false;
2445
	}
2446
2447
	private static String getProperty(String property) {
2448
		// Preference overrides system property overrides env-var
2449
2450
		IPreferencesService preferencesService = Platform.getPreferencesService();
2451
		IScopeContext[] lookupOrder = new IScopeContext[] {
2452
				new InstanceScope(), new ConfigurationScope()
2453
		};
2454
		String key = property;
2455
		if (property != null && property.startsWith(SSECorePlugin.ID)) {
2456
			// +1, include the "."
2457
			key = property.substring(SSECorePlugin.ID.length() + 1, property.length());
2458
		}
2459
		String value = preferencesService.getString(SSECorePlugin.ID, key, null, lookupOrder);
2460
		if (value == null) {
2461
			value = System.getProperty(property);
2462
		}
2463
		if (value == null) {
2464
			value = System.getenv(property);
2465
		}
2466
		return value;
2467
	}
2468
2469
	private static String getDefault(String property) {
2470
		// this is the "default-default"
2471
		if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) {
2472
			return "0";
2473
		}
2474
		else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad"
2475
				.equals(property)) {
2476
			return "false";
2477
		}
2478
		return null;
2479
	}
2480
2481
	private static boolean getBoolean(String key) {
2482
		String property = getProperty(key);
2483
		// if (property != null) {
2484
		//			System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$
2485
		// }
2486
		return property != null ? Boolean.parseBoolean(property) : Boolean
2487
				.parseBoolean(getDefault(key));
2488
	}
2489
2490
	private static int getInt(String key) {
2491
		String property = getProperty(key);
2492
		int size = 0;
2493
		if (property != null) {
2494
			try {
2495
				size = Integer.parseInt(property);
2496
				//	System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$
2497
			}
2498
			catch (NumberFormatException e) {
2499
				size = getDefaultInt(key, property, size);
2500
			}
2501
		}
2502
		else {
2503
			size = getDefaultInt(key, property, size);
2504
		}
2505
		return size;
2506
	}
2507
2508
	private static int getDefaultInt(String key, String property, int size) {
2509
		// ignored
2510
		try {
2511
			size = Integer.parseInt(getDefault(key));
2512
		}
2513
		catch (NumberFormatException e1) {
2514
			handleIntParseException(key, property, e1);
2515
			size = 0;
2516
		}
2517
		return size;
2518
	}
2519
2520
	private static void handleIntParseException(String key, String property,
2521
			NumberFormatException e1) {
2522
		Exception n = new Exception(
2523
				NLS
2524
						.bind(
2525
								"Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$
2526
								key, property), e1);
2527
		n.printStackTrace();
2528
	}
2529
2101
}
2530
}

Return to bug 287096