[398691] ValidatorGroupListener can leak model references
diff --git a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/validate/ValidatorGroupListener.java b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/validate/ValidatorGroupListener.java
index c34c271..24473cb 100644
--- a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/validate/ValidatorGroupListener.java
+++ b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/validate/ValidatorGroupListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008 IBM Corporation and others.
+ * Copyright (c) 2008, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -30,6 +30,7 @@
 public class ValidatorGroupListener implements IValidatorGroupListener {
 
 	Map fDiagnosticMap = new HashMap();
+	private static final Object LOCK = new Object();
 	private static final boolean _debug = false;
 
 	public ValidatorGroupListener() {
@@ -52,9 +53,18 @@
 		if (resource.getType() != IResource.FILE)
 			return;
 
-		IStructuredModel model = (IStructuredModel) fDiagnosticMap.remove(resource.getFullPath());
-		if (model != null) {
-			model.releaseFromRead();
+		synchronized (LOCK) {
+			final IPath path = resource.getFullPath();
+			final ValidationModelReference ref = (ValidationModelReference) fDiagnosticMap.get(path);
+			if (ref != null) {
+				if (--ref.count == 0) {
+					// The model is no longer being tracked
+					fDiagnosticMap.remove(path);
+					if (ref.model != null) {
+						ref.model.releaseFromRead();
+					}
+				}
+			}
 		}
 	}
 
@@ -66,12 +76,23 @@
 				if (resource.getType() != IResource.FILE)
 					return;
 
-				IModelManager modelManager = StructuredModelManager.getModelManager();
-				// possible when shutting down
-				if (modelManager != null) {
-					IStructuredModel model = modelManager.getModelForRead((IFile) resource);
-					if (model != null) {
-						fDiagnosticMap.put(resource.getFullPath(), model);
+				synchronized (LOCK) {
+					final IPath path = resource.getFullPath();
+					final ValidationModelReference ref = (ValidationModelReference) fDiagnosticMap.get(path);
+					if (ref != null) {
+						// The model is already being tracked
+						++ref.count;
+					}
+					else {
+						// The model has not been obtained as part of the validation group yet
+						IModelManager modelManager = StructuredModelManager.getModelManager();
+						// possible when shutting down
+						if (modelManager != null) {
+							IStructuredModel model = modelManager.getModelForRead((IFile) resource);
+							if (model != null) {
+								fDiagnosticMap.put(resource.getFullPath(), new ValidationModelReference(model));
+							}
+						}
 					}
 				}
 			}
@@ -80,4 +101,13 @@
 			Logger.logException(e);
 		}
 	}
+
+	private class ValidationModelReference {
+		IStructuredModel model;
+		int count;
+		public ValidationModelReference(IStructuredModel model) {
+			this.model = model;
+			count = 1;
+		}
+	}
 }