[148806] Memory leak in HTMLDocumentTypeAdapterFactory
diff --git a/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
index 7a73ceb..dbeeb8b 100644
--- a/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.wst.sse.core; singleton:=true
-Bundle-Version: 1.1.0.qualifier
+Bundle-Version: 1.1.100.qualifier
 Bundle-Activator: org.eclipse.wst.sse.core.internal.SSECorePlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/AbstractStructuredModel.java b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/AbstractStructuredModel.java
index 952e4b3..8053245 100644
--- a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/AbstractStructuredModel.java
+++ b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/AbstractStructuredModel.java
@@ -194,6 +194,9 @@
 	// private String fLineDelimiter;
 	// private Object fType;
 	private IModelHandler fModelHandler;
+	// issue: we should not "hold on" to model manager, can 
+	// easily get with StructuredModelManager.getModelManager();
+	// but will need to add more null checks.
 	private IModelManager fModelManager;
 	private int fModelStateChanging;
 	private Object[] fModelStateListeners;
@@ -684,10 +687,12 @@
 
 	/**
 	 * The id is the id that the model manager uses to identify this model
+	 * 
+	 * @ISSUE - no one should need to know ID, so this should be default access eventually. 
+	 * If clients believe they do need ID, be sure to let us know (open a bug). 
 	 */
 	public String getId() {
 
-
 		return fId;
 	}
 
@@ -1036,7 +1041,7 @@
 				signalPreLifeCycleEventRelease(this);
 			}
 
-			_getModelManager().releaseFromEdit(getId());
+			_getModelManager().releaseFromEdit(this);
 			if (!isShared) {
 				signalPostLifeCycleListenerRelease(this);
 			}
@@ -1068,7 +1073,7 @@
 				signalPreLifeCycleEventRelease(this);
 			}
 
-			_getModelManager().releaseFromRead(getId());
+			_getModelManager().releaseFromRead(this);
 
 			if (!isShared) {
 				signalPostLifeCycleListenerRelease(this);
diff --git a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java
index 9349bc3..9ec3006 100644
--- a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java
+++ b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java
@@ -140,7 +140,7 @@
 			referenceCountForEdit = 0;
 		}
 	}
-	
+
 	private Exception debugException = null;
 
 	/**
@@ -336,12 +336,13 @@
 
 			// if we don't know how to create a model
 			// for this type of file, return null
-			if(sharedObject != null) {
-				// note: clients must call release for each time they call get.
+			if (sharedObject != null) {
+				// note: clients must call release for each time they call
+				// get.
 				model = sharedObject.theSharedModel;
 			}
 		}
-		
+
 		return model;
 	}
 
@@ -364,10 +365,10 @@
 			throw new ResourceInUse();
 		}
 
-		// if we get to hear without above exceptions, then all is ok 
-		// to get model like normal, but set 'new' attribute (where the 
-		// 'new' attribute means this is a model without a corresponding 
-		// underlying resource. 
+		// if we get to hear without above exceptions, then all is ok
+		// to get model like normal, but set 'new' attribute (where the
+		// 'new' attribute means this is a model without a corresponding
+		// underlying resource.
 		aSharedModel = FileBufferModelManager.getInstance().getModel(iFile);
 		aSharedModel.setNewState(true);
 		sharedObject = addToCache(id, aSharedModel);
@@ -530,7 +531,8 @@
 					multiTextEdit.apply(document);
 			}
 			catch (BadLocationException exception) {
-				// just adding generic runtime here, until whole method deleted.
+				// just adding generic runtime here, until whole method
+				// deleted.
 				throw new RuntimeException(exception.getMessage());
 			}
 		}
@@ -1334,11 +1336,32 @@
 		return model;
 	}
 
+	synchronized void releaseFromEdit(IStructuredModel structuredModel) {
+		Object id = structuredModel.getId();
+		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
+			cleanupDiscardedModel(structuredModel);
+		}
+		else {
+			releaseFromEdit(id);
+		}
+
+	}
+	
+	synchronized void releaseFromRead(IStructuredModel structuredModel) {
+		Object id = structuredModel.getId();
+		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
+			cleanupDiscardedModel(structuredModel);
+		}
+		else {
+			releaseFromRead(id);
+		}
+
+	}
 	/**
 	 * default for use in same package, not subclasses
 	 * 
 	 */
-	synchronized void releaseFromEdit(Object id) {
+	synchronized private void releaseFromEdit(Object id) {
 		// ISSUE: many of these asserts should be changed to "logs"
 		// and continue to limp along?
 
@@ -1350,7 +1373,7 @@
 		// to be called on them, for now, but the model manager
 		// doesn't need to do anything.
 		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
-			// do nothing related to model managment.
+			throw new IllegalArgumentException("Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
 		}
 		else {
 			sharedObject = (SharedObject) fManagedObjects.get(id);
@@ -1365,9 +1388,10 @@
 				// if edit goes to zero, but still open for read,
 				// then we should reload here, so we are in synch with
 				// contents on disk.
-				// ISSUE: should we check isDirty here? 
-				// ANSWER: here, for now now. model still has its own dirty flag for some reason. 
-				// we need to address * that * too. 
+				// ISSUE: should we check isDirty here?
+				// ANSWER: here, for now now. model still has its own dirty
+				// flag for some reason.
+				// we need to address * that * too.
 				if ((sharedObject.referenceCountForRead > 0) && (sharedObject.referenceCountForEdit == 0) && sharedObject.theSharedModel.isDirty()) {
 					signalPreLifeCycleListenerRevert(sharedObject.theSharedModel);
 					revertModel(id, sharedObject);
@@ -1377,18 +1401,20 @@
 			}
 		}
 	}
-	
+
 	// private for now, though public forms have been requested, in past.
 	private void revertModel(Object id, SharedObject sharedObject) {
 		IStructuredDocument structuredDocument = sharedObject.theSharedModel.getStructuredDocument();
 		FileBufferModelManager.getInstance().revert(structuredDocument);
 	}
+
 	private void signalPreLifeCycleListenerRevert(IStructuredModel structuredModel) {
 		int type = ModelLifecycleEvent.MODEL_REVERT | ModelLifecycleEvent.PRE_EVENT;
 		// what's wrong with this design that a cast is needed here!?
 		ModelLifecycleEvent event = new ModelLifecycleEvent(structuredModel, type);
 		((AbstractStructuredModel) structuredModel).signalLifecycleEvent(event);
 	}
+
 	private void signalPostLifeCycleListenerRevert(IStructuredModel structuredModel) {
 		int type = ModelLifecycleEvent.MODEL_REVERT | ModelLifecycleEvent.POST_EVENT;
 		// what's wrong with this design that a cast is needed here!?
@@ -1404,12 +1430,17 @@
 			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));
 		}
 
+		cleanupDiscardedModel(sharedObject.theSharedModel);
+	}
+
+	private void cleanupDiscardedModel(IStructuredModel structuredModel) {
+		IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
 		/*
 		 * This call (and setting the StructuredDocument to null) were
 		 * previously done within the model itself, but for concurrency it
 		 * must be done here during a synchronized release.
 		 */
-		sharedObject.theSharedModel.getFactoryRegistry().release();
+		structuredModel.getFactoryRegistry().release();
 
 		/*
 		 * For structured documents originating from file buffers, disconnect
@@ -1425,19 +1456,19 @@
 		 * The model itself in particular may have internal listeners used to
 		 * coordinate the document with its own "structure".
 		 */
-		sharedObject.theSharedModel.setStructuredDocument(null);
+		structuredModel.setStructuredDocument(null);
 	}
 
 	/**
 	 * default for use in same package, not subclasses
 	 * 
 	 */
-	synchronized void releaseFromRead(Object id) {
+	synchronized private void releaseFromRead(Object id) {
 		Assert.isNotNull(id, "id parameter can not be null"); //$NON-NLS-1$
 		SharedObject sharedObject = null;
 
 		if (id.equals(UNMANAGED_MODEL) || id.equals(DUPLICATED_MODEL)) {
-			// do nothing related to model management.
+			throw new IllegalArgumentException("Ids of UNMANAGED_MODEL or DUPLICATED_MODEL are illegal here");
 		}
 		else {
 
@@ -1450,9 +1481,6 @@
 			if ((sharedObject.referenceCountForRead == 0) && (sharedObject.referenceCountForEdit == 0)) {
 				discardModel(id, sharedObject);
 			}
-			// ISSUE: if edit goes to zero, but still open for read,
-			// then we should reload here, so we are in synch with
-			// contents on disk.
 		}
 	}