[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; + } + } }