### Eclipse Workspace Patch 1.0 #P org.eclipse.jst.jsp.core Index: src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java,v retrieving revision 1.14 diff -u -r1.14 JSPCorePlugin.java --- src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java 23 Feb 2006 05:04:57 -0000 1.14 +++ src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java 12 Oct 2006 06:35:27 -0000 @@ -16,6 +16,7 @@ import org.eclipse.jst.jsp.core.internal.contentproperties.JSPFContentPropertiesManager; import org.eclipse.jst.jsp.core.internal.java.search.JSPIndexManager; import org.eclipse.jst.jsp.core.internal.taglib.TaglibHelperManager; +import org.eclipse.jst.jsp.core.internal.util.JSPFragmentBufferCache; import org.eclipse.jst.jsp.core.taglib.TaglibIndex; import org.osgi.framework.BundleContext; @@ -87,6 +88,8 @@ // stop taglib controller TaglibController.shutdown(); TaglibIndex.shutdown(); + + JSPFragmentBufferCache.logStatus(); super.stop(context); } Index: src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java,v retrieving revision 1.51.2.1 diff -u -r1.51.2.1 JSPTranslator.java --- src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java 13 Sep 2006 01:06:44 -0000 1.51.2.1 +++ src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java 12 Oct 2006 06:35:27 -0000 @@ -19,6 +19,7 @@ import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -52,7 +53,9 @@ import org.eclipse.jst.jsp.core.internal.taglib.TaglibHelper; import org.eclipse.jst.jsp.core.internal.taglib.TaglibHelperManager; import org.eclipse.jst.jsp.core.internal.taglib.TaglibVariable; +import org.eclipse.jst.jsp.core.internal.util.JSPFragmentBufferCache; import org.eclipse.jst.jsp.core.jspel.IJSPELTranslator; +import org.eclipse.jst.jsp.core.taglib.TaglibIndex; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.ltk.parser.BlockMarker; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; @@ -62,7 +65,6 @@ import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; -import org.eclipse.wst.sse.core.internal.util.URIResolver; import org.eclipse.wst.sse.core.utils.StringUtils; import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument; import org.eclipse.wst.xml.core.internal.contentmodel.CMNode; @@ -1558,6 +1560,11 @@ private int fLastJSPType = SCRIPTLET; /** + * Set if IPaths + */ + private HashSet fIncludedDocumentPaths; + + /** * JSPType is only used internally in this class to describe tye type of * region to be translated * @@ -1601,7 +1608,7 @@ return; } else if (regionText.equals("include")) { //$NON-NLS-1$ - String fileLocation = ""; //$NON-NLS-1$ + String fileUri = ""; //$NON-NLS-1$ // CMVC 258311 // PMR 18368, B663 // skip to required "file" attribute, should be safe because @@ -1609,9 +1616,9 @@ while (r != null && regions.hasNext() && !r.getType().equals(DOMRegionContext.XML_TAG_ATTRIBUTE_NAME)) { r = (ITextRegion) regions.next(); } - fileLocation = getAttributeValue(r, regions); + fileUri = getAttributeValue(r, regions); if (attrValue != null) - handleIncludeFile(fileLocation); + handleIncludeFile(fileUri); } else if (regionText.indexOf("page") > -1) { //$NON-NLS-1$ translatePageDirectiveAttributes(regions); @@ -1755,43 +1762,35 @@ } protected void handleIncludeFile(String filename) { - if (filename != null) { - String fileLocation = null; - if (getResolver() != null) { - fileLocation = (getIncludes().empty()) ? getResolver().getLocationByURI(StringUtils.strip(filename)) : getResolver().getLocationByURI(StringUtils.strip(filename), (String) getIncludes().peek()); + ITextFileBuffer baseBuffer = TaglibController.getFileBuffer(fStructuredDocument); + if (baseBuffer != null && filename != null) { + IPath filePath = null; + IPath basePath = baseBuffer.getLocation(); + if (filename.startsWith("/")) { //$NON-NLS-1$ + IPath contextRoot = TaglibIndex.getContextRoot(basePath); + filePath = contextRoot.append(filename); } else { - // shouldn't happen - fileLocation = StringUtils.strip(filename); + if (getIncludes().isEmpty()) + filePath = basePath.removeLastSegments(1).append(filename); + else + filePath = ((IPath) getIncludes().peek()).removeLastSegments(1).append(filename); } + // hopefully, a resolver is present and has returned a canonical // file path - if (!getIncludes().contains(fileLocation) && getBaseLocation() != null && !fileLocation.equals(getBaseLocation())) { - getIncludes().push(fileLocation); + if (!getIncludes().contains(filePath)) { + getIncludes().push(filePath); JSPIncludeRegionHelper helper = new JSPIncludeRegionHelper(this); - boolean parsed = helper.parse(fileLocation); + boolean parsed = helper.parse(filePath); if (!parsed) { - Logger.log(Logger.ERROR_DEBUG, "Error: included file " + filename + " not found {" + getBaseLocation() + ")"); + Logger.log(Logger.ERROR_DEBUG, "Error: included file " + filename + " not found {" + basePath + ")"); } getIncludes().pop(); } } } - private URIResolver getResolver() { - return (fStructuredModel != null) ? fStructuredModel.getResolver() : null; - } - - /** - * - * @return java.lang.String - */ - private String getBaseLocation() { - if (getResolver() == null) - return null; - return getResolver().getFileBaseLocation(); - } - private Stack getIncludes() { if (fIncludes == null) fIncludes = new Stack(); @@ -2421,4 +2420,40 @@ public IStructuredDocument getStructuredDocument() { return fStructuredDocument; } + + /** + * Gets the documents. + * + * @return Returns a java.util.Hashtable + */ + private HashSet getIncludedDocumentPaths() { + if (fIncludedDocumentPaths == null) + fIncludedDocumentPaths = new HashSet(); + return fIncludedDocumentPaths; + } + + public void release() { + for (Iterator iter = getIncludedDocumentPaths().iterator(); iter.hasNext();) { + Object key = iter.next(); + JSPFragmentBufferCache.disconnect((IPath) key); + } + } + /** + * get the contents of a file as a String + * + * @param filePath + * @return the contents, null if the file could not be found + */ + String getContents(IPath filePath) { + StringBuffer s = null; + if (!getIncludedDocumentPaths().contains(filePath)) { + getIncludedDocumentPaths().add(filePath); + JSPFragmentBufferCache.connect(filePath); + } + s = JSPFragmentBufferCache.getBuffer(filePath); + if (s == null) { + s = new StringBuffer(); + } + return s.toString(); + } } \ No newline at end of file Index: src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java,v retrieving revision 1.13.6.1 diff -u -r1.13.6.1 JSPTranslationAdapter.java --- src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java 13 Sep 2006 01:06:44 -0000 1.13.6.1 +++ src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java 12 Oct 2006 06:35:27 -0000 @@ -111,6 +111,8 @@ fJSPTranslation.release(); } + if(fTranslator != null) + fTranslator.release(); } /** Index: src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java,v retrieving revision 1.25.2.1 diff -u -r1.25.2.1 XMLJSPRegionHelper.java --- src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java 13 Sep 2006 01:06:44 -0000 1.25.2.1 +++ src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java 12 Oct 2006 06:35:33 -0000 @@ -10,12 +10,9 @@ *******************************************************************************/ package org.eclipse.jst.jsp.core.internal.java; -import java.io.InputStream; import java.util.Iterator; import java.util.List; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jst.jsp.core.internal.Logger; @@ -28,7 +25,6 @@ import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; -import org.eclipse.wst.sse.core.internal.util.Debug; import org.eclipse.wst.sse.core.utils.StringUtils; import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument; import org.eclipse.wst.xml.core.internal.contentmodel.CMNode; @@ -91,10 +87,10 @@ * @param filename * @return */ - public boolean parse(String filename) { + public boolean parse(IPath filePath) { // from outer class List blockMarkers = this.fTranslator.getBlockMarkers(); - String contents = getContents(filename); + String contents = this.fTranslator.getContents(filePath); if(contents == null) return false; reset(contents); @@ -458,42 +454,6 @@ * @return the contents, null if the file could not be found */ protected String getContents(String fileName) { - StringBuffer s = new StringBuffer(); - int c = 0; - int count = 0; - InputStream is = null; - try { - IPath filePath = new Path(fileName); - IFile f = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); - if(f != null && !f.exists()) { - f = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(filePath); - } - if (f != null && f.exists()) { - is = f.getContents(); - while ((c = is.read()) != -1) { - count++; - s.append((char) c); - } - } - else { - // error condition, file could not be found - return null; - } - } - catch (Exception e) { - if (Debug.debugStructuredDocument) - e.printStackTrace(); - } - finally { - try { - if (is != null) { - is.close(); - } - } - catch (Exception e) { - // nothing to do - } - } - return s.toString(); + return fTranslator.getContents(new Path(fileName)); } } \ No newline at end of file Index: .options =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/.options,v retrieving revision 1.11.2.1 diff -u -r1.11.2.1 .options --- .options 13 Sep 2006 01:22:21 -0000 1.11.2.1 +++ .options 12 Oct 2006 06:35:27 -0000 @@ -31,4 +31,5 @@ org.eclipse.jst.jsp.core/debug/jspvalidator=false org.eclipse.jst.jsp.core/debug/taglibvars=false -org.eclipse.jst.jsp.core/debug/taglibclassloader \ No newline at end of file +org.eclipse.jst.jsp.core/debug/taglibclassloader=false +org.eclipse.jst.jsp.core/debug/fragments/cache=false \ No newline at end of file Index: src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java =================================================================== RCS file: /cvsroot/webtools/jst/components/jsp/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java,v retrieving revision 1.26 diff -u -r1.26 TLDCMDocumentManager.java --- src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java 3 May 2006 07:48:55 -0000 1.26 +++ src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java 12 Oct 2006 06:35:27 -0000 @@ -12,30 +12,22 @@ -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; +import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.jst.jsp.core.internal.Logger; import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibController; import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP11TLDNames; @@ -46,6 +38,7 @@ import org.eclipse.jst.jsp.core.internal.parser.JSPSourceParser; import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace; import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts; +import org.eclipse.jst.jsp.core.internal.util.JSPFragmentBufferCache; import org.eclipse.jst.jsp.core.taglib.IJarRecord; import org.eclipse.jst.jsp.core.taglib.ITLDRecord; import org.eclipse.jst.jsp.core.taglib.ITaglibIndexListener; @@ -249,22 +242,24 @@ includedFile = null; } - if (includedFile != null) { + ITextFileBuffer baseBuffer = TaglibController.getFileBuffer(TLDCMDocumentManager.this); + if (baseBuffer != null && includedFile != null) { // strip any extraneous quotes and white space includedFile = StringUtils.strip(includedFile).trim(); IPath filePath = null; + IPath location = baseBuffer.getLocation(); if (includedFile.startsWith("/")) { //$NON-NLS-1$ - IPath contextRoot = TaglibIndex.getContextRoot(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation()); + IPath contextRoot = TaglibIndex.getContextRoot(location); filePath = contextRoot.append(includedFile); } else { if (getIncludes().isEmpty()) - filePath = TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation().removeLastSegments(1).append(includedFile); + filePath = location.removeLastSegments(1).append(includedFile); else filePath = ((IPath) getIncludes().peek()).removeLastSegments(1).append(includedFile); } // check for "loops" - if (filePath != null && !getIncludes().contains(filePath) && !filePath.equals(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation())) { + if (filePath != null && !getIncludes().contains(filePath) && !filePath.equals(location)) { /* * Prevent slow performance when editing scriptlet part of * the JSP by only processing includes if they've been @@ -520,123 +515,12 @@ taglibReferences.add(reference); } - private String detectCharset(IFile file) { - if (file.getType() == IResource.FILE && file.isAccessible()) { - IContentDescription d = null; - try { - // optimized description lookup, might not succeed - d = file.getContentDescription(); - if (d != null) - return d.getCharset(); - } - catch (CoreException e) { - // should not be possible given the accessible and file - // type - // check above - } - InputStream contents = null; - try { - contents = file.getContents(); - IContentDescription description = Platform.getContentTypeManager().getDescriptionFor(contents, file.getName(), new QualifiedName[]{IContentDescription.CHARSET}); - if (description != null) { - return description.getCharset(); - } - } - catch (IOException e) { - // will try to cleanup in finally - } - catch (CoreException e) { - Logger.logException(e); - } - finally { - if (contents != null) { - try { - contents.close(); - } - catch (Exception e) { - // not sure how to recover at this point - } - } - } - } - return ResourcesPlugin.getEncoding(); - } - protected String getContents(IPath filePath) { - StringBuffer s = new StringBuffer(); - IFile iFile = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); - if (iFile != null && iFile.exists()) { - String charset = detectCharset(iFile); - InputStream contents = null; - try { - contents = iFile.getContents(); - Reader reader = new InputStreamReader(contents, charset); - char[] readBuffer = new char[2048]; - int n = reader.read(readBuffer); - while (n > 0) { - s.append(readBuffer, 0, n); - n = reader.read(readBuffer); - } - } - catch (Exception e) { - if (Debug.debugStructuredDocument) - Logger.log(Logger.WARNING, "An exception occured while scanning " + filePath, e); //$NON-NLS-1$ - } - finally { - try { - if (contents != null) { - contents.close(); - } - } - catch (Exception e) { - // nothing to do - } - } - } - else { - int c = 0; - int length = 0; - int count = 0; - File file = null; - FileInputStream fis = null; - try { - file = new File(filePath.toString()); - length = (int) file.length(); - fis = new FileInputStream(file); - while (((c = fis.read()) >= 0) && (count < length)) { - count++; - s.append((char) c); - } - } - catch (FileNotFoundException e) { - if (Debug.debugStructuredDocument) - System.out.println("File not found : \"" + filePath + "\""); //$NON-NLS-2$//$NON-NLS-1$ - } - catch (ArrayIndexOutOfBoundsException e) { - if (Debug.debugStructuredDocument) - System.out.println("Usage wrong: specify inputfile"); //$NON-NLS-1$ - //$NON-NLS-1$ - } - catch (IOException e) { - if (Debug.debugStructuredDocument) - System.out.println("An I/O error occured while scanning :"); //$NON-NLS-1$ - //$NON-NLS-1$ - } - catch (Exception e) { - if (Debug.debugStructuredDocument) - e.printStackTrace(); - } - finally { - try { - if (fis != null) { - fis.close(); - } - } - catch (Exception e) { - // nothing to do - } - } + if (!getIncludedDocumentPaths().contains(filePath)) { + getIncludedDocumentPaths().add(filePath); + JSPFragmentBufferCache.connect(filePath); } + StringBuffer s = JSPFragmentBufferCache.getBuffer(filePath); return s.toString(); } @@ -689,6 +573,12 @@ } } + Collection getIncludedDocumentPaths() { + if (fIncludedDocumentPaths == null) + fIncludedDocumentPaths = new HashSet(); + return fIncludedDocumentPaths; + } + /** * An entry in the shared cache map */ @@ -718,6 +608,7 @@ protected static List bannedPrefixes = null; private static Hashtable fCache = null; + static final String XMLNS = "xmlns:"; //$NON-NLS-1$ static final int XMLNS_LENGTH = XMLNS.length(); @@ -746,7 +637,6 @@ return fCache; } - public static Object getUniqueIdentifier(ITaglibRecord reference) { Object identifier = null; switch (reference.getRecordType()) { @@ -777,6 +667,7 @@ } return identifier; } + private CMDocumentFactoryTLD fCMDocumentBuilder = null; private DirectiveStructuredDocumentRegionHandler fDirectiveHandler = null; @@ -786,10 +677,10 @@ */ private Hashtable fDocuments = null; - // timestamp cache to prevent excessive reparsing - // of included files - // IPath (filepath) > Long (modification stamp) - HashMap fInclude2TimestampMap = new HashMap(); + /** + * Set if IPaths + */ + private HashSet fIncludedDocumentPaths = null; private Stack fIncludes = null; @@ -820,13 +711,19 @@ } } } + + for (Iterator iter = getIncludedDocumentPaths().iterator(); iter.hasNext();) { + Object key = iter.next(); + JSPFragmentBufferCache.disconnect((IPath) key); + } } /** - * Derives an unique cache key for the give URI. The URI is "resolved" - * and a unique value generated from the result. This ensures that two - * different relative references from different files do not have overlapping - * TLD records in the shared cache if they don't resolve to the same TLD. + * Derives an unique cache key for the give URI. The URI is "resolved" and + * a unique value generated from the result. This ensures that two + * different relative references from different files do not have + * overlapping TLD records in the shared cache if they don't resolve to + * the same TLD. * * @param uri * @return @@ -979,7 +876,13 @@ path = (IPath) getIncludes().peek(); } else { - path = TaglibController.getFileBuffer(this).getLocation(); + ITextFileBuffer fileBuffer = TaglibController.getFileBuffer(this); + if (fileBuffer != null) { + path = fileBuffer.getLocation(); + } + else { + path = Path.EMPTY; + } } return path; @@ -1073,57 +976,21 @@ */ boolean hasAnyIncludeBeenModified(IPath filePath) { boolean result = false; - // check the top level - if (hasBeenModified(filePath)) { - result = true; - } - else { // check all includees - Iterator iter = fInclude2TimestampMap.keySet().iterator(); + Iterator iter = getIncludedDocumentPaths().iterator(); while (iter.hasNext()) { - if (hasBeenModified((IPath) iter.next())) { + // should already be connected + if (JSPFragmentBufferCache.hasBeenModified((IPath) iter.next())) { result = true; break; } } - } return result; } - /** - * @param filename - * @return - */ - boolean hasBeenModified(IPath filePath) { - boolean result = false; - // quick filename/timestamp cache check here... - IFile f = null; - if (f == null && filePath.segmentCount() > 1) { - f = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); - } - if (f != null && f.exists()) { - Long currentStamp = new Long(f.getModificationStamp()); - Object o = fInclude2TimestampMap.get(filePath); - if (o != null) { - Long previousStamp = (Long) o; - // stamps don't match, file changed - if (currentStamp.longValue() != previousStamp.longValue()) { - result = true; - // store for next time - fInclude2TimestampMap.put(filePath, currentStamp); - } - } - else { - // return true, since we've not encountered this file yet. - result = true; - // store for next time - fInclude2TimestampMap.put(filePath, currentStamp); - } - } - return result; - } - public void indexChanged(ITaglibRecordEvent event) {} + public void indexChanged(ITaglibRecordEvent event) { + } /** * Loads the tags from the specified URI. It must point to a URL of valid Index: src/org/eclipse/jst/jsp/core/internal/util/JSPFragmentBufferCache.java =================================================================== RCS file: src/org/eclipse/jst/jsp/core/internal/util/JSPFragmentBufferCache.java diff -N src/org/eclipse/jst/jsp/core/internal/util/JSPFragmentBufferCache.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/jst/jsp/core/internal/util/JSPFragmentBufferCache.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * + *******************************************************************************/ +package org.eclipse.jst.jsp.core.internal.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.core.runtime.content.IContentDescription; +import org.eclipse.jst.jsp.core.internal.Logger; + +public class JSPFragmentBufferCache { + static class FragmentCacheEntry { + StringBuffer buffer; + int referenceCount; + long modificationStamp; + } + + private static final boolean _debug = Boolean.valueOf(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/fragments/cache")).booleanValue(); //$NON-NLS-1$ + + static JSPFragmentBufferCache _instance; + + public static void connect(IPath fragmentPath) { + getInstance()._connect(fragmentPath); + } + + public static void disconnect(IPath fragmentPath) { + getInstance()._disconnect(fragmentPath); + } + + public static StringBuffer getBuffer(IPath fragmentPath) { + return getInstance()._getBuffer(fragmentPath); + } + + static JSPFragmentBufferCache getInstance() { + if (_instance == null) + _instance = new JSPFragmentBufferCache(); + return _instance; + } + + public static boolean hasBeenModified(IPath fragmentPath) { + return getInstance()._hasBeenModified(fragmentPath); + } + + public static void logStatus() { + if (_debug && _instance != null) { + Iterator iterator = _instance.fFragmentBufferCache.keySet().iterator(); + while (iterator.hasNext()) { + IPath path = (IPath) iterator.next(); + Object o = _instance.fFragmentBufferCache.get(path); + if (o instanceof FragmentCacheEntry) { + Logger.log(Logger.INFO, "JSP Fragment Cache: still connected to " + path + " at shutdown"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + } + + Map fFragmentBufferCache = null; + + private JSPFragmentBufferCache() { + super(); + fFragmentBufferCache = new HashMap(); + } + + private synchronized void _connect(IPath fragmentPath) { + FragmentCacheEntry entry = null; + Object o = fFragmentBufferCache.get(fragmentPath); + if (o != null) { + if (o instanceof FragmentCacheEntry) { + /* + * a strong reference to an entry is present + */ + entry = (FragmentCacheEntry) o; + } + else if (o instanceof WeakReference) { + /* + * a weak reference to an entry is present, restore it if + * possible + */ + entry = (FragmentCacheEntry) ((WeakReference) o).get(); + if (entry != null) { + fFragmentBufferCache.put(fragmentPath, entry); + } + } + } + if (entry == null) { + /* + * no valid reference to an entry is present, create one + */ + entry = new FragmentCacheEntry(); + entry.modificationStamp = IResource.NONE; + fFragmentBufferCache.put(fragmentPath, entry); + } + + // just increment count for now + entry.referenceCount++; + if (_debug) { + Logger.log(Logger.INFO, "JSP Fragment Cache: connected to [" + entry.referenceCount + "] " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + private synchronized void _disconnect(IPath fragmentPath) { + FragmentCacheEntry entry = null; + Object o = fFragmentBufferCache.get(fragmentPath); + if (o != null) { + if (o instanceof FragmentCacheEntry) { + /* + * a strong reference to an entry is present, at least + * decrement it + */ + entry = (FragmentCacheEntry) o; + entry.referenceCount--; + + if (entry.referenceCount == 0) { + /* make the entry weakly referenced */ + fFragmentBufferCache.put(fragmentPath, new WeakReference(entry)); + } + if (_debug) { + Logger.log(Logger.INFO, "JSP Fragment Cache: disconnected [" + entry.referenceCount + "] from " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + } + else if (o instanceof WeakReference) { + /* + * ignore weak referenced entries + */ + if (_debug) { + Logger.log(Logger.INFO, "JSP Fragment Cache: disconnected (weak) from " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + else { + if (_debug) + Logger.log(Logger.INFO, "JSP Fragment Cache: disconnected (null) from " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + private StringBuffer _getBuffer(IPath fragmentPath) { + StringBuffer s = null; + Object o = fFragmentBufferCache.get(fragmentPath); + if (o != null) { + FragmentCacheEntry entry = (FragmentCacheEntry) o; + + synchronized (entry) { + // ensure our cache entry is up-to-date + IFile fragmentFile = ResourcesPlugin.getWorkspace().getRoot().getFile(fragmentPath); + if (entry.buffer == null || fragmentFile.getModificationStamp() != entry.modificationStamp) { + if (_debug) { + if (entry.buffer == null) + Logger.log(Logger.INFO, "JSP Fragment Cache: populating buffer for " + fragmentFile + "@" + entry.modificationStamp); //$NON-NLS-1$ //$NON-NLS-2$ + else + Logger.log(Logger.INFO, "JSP Fragment Cache: repopulating buffer for " + fragmentFile + "@" + entry.modificationStamp); //$NON-NLS-1$ //$NON-NLS-2$ + } + s = getContents(fragmentFile); + entry.buffer = s; + entry.modificationStamp = fragmentFile.getModificationStamp(); + } + s = entry.buffer; + } + } + else { + if (_debug) { + Logger.log(Logger.INFO, "JSP Fragment Cache: no buffer found when requested for " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + return s; + } + + private boolean _hasBeenModified(IPath fragmentPath) { + boolean modified = false; + + FragmentCacheEntry entry = null; + Object o = fFragmentBufferCache.get(fragmentPath); + if (o != null) { + if (o instanceof FragmentCacheEntry) { + /* + * a strong reference to an entry is present + */ + entry = (FragmentCacheEntry) o; + } + else if (o instanceof WeakReference) { + /* + * a weak reference to an entry is present, restore it if + * possible + */ + entry = (FragmentCacheEntry) ((WeakReference) o).get(); + if (entry != null) { + fFragmentBufferCache.put(fragmentPath, entry); + } + } + } + if (entry == null) { + modified = true; + } + else { + IFile fragmentFile = ResourcesPlugin.getWorkspace().getRoot().getFile(fragmentPath); + modified = (fragmentFile.getModificationStamp() != entry.modificationStamp); + } + + if (_debug) { + Logger.log(Logger.INFO, "JSP Fragment Cache: checked modification [" + modified + "] of " + fragmentPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return modified; + } + + private String detectCharset(IFile file) { + String detectedCharset = null; + try { + detectedCharset = file.getCharset(true); + } + catch (CoreException e1) { + Logger.logException(e1); + } + if (detectedCharset != null) { + return detectedCharset; + } + + if (file.getType() == IResource.FILE && file.isAccessible()) { + IContentDescription d = null; + try { + // optimized description lookup, might not succeed + d = file.getContentDescription(); + if (d != null) + return d.getCharset(); + } + catch (CoreException e) { + // should not be possible given the accessible and file + // type + // check above + } + InputStream contents = null; + try { + contents = file.getContents(); + IContentDescription description = Platform.getContentTypeManager().getDescriptionFor(contents, file.getName(), new QualifiedName[]{IContentDescription.CHARSET}); + if (description != null) { + return description.getCharset(); + } + } + catch (IOException e) { + // will try to cleanup in finally + } + catch (CoreException e) { + Logger.logException(e); + } + finally { + if (contents != null) { + try { + contents.close(); + } + catch (Exception e) { + // not sure how to recover at this point + } + } + } + } + return ResourcesPlugin.getEncoding(); + } + + private StringBuffer getContents(IFile file) { + StringBuffer s = new StringBuffer(); + if (file.isAccessible()) { + String charset = detectCharset(file); + InputStream contents = null; + try { + contents = file.getContents(); + Reader reader = new InputStreamReader(contents, charset); + char[] readBuffer = new char[2048]; + int n = reader.read(readBuffer); + while (n > 0) { + s.append(readBuffer, 0, n); + n = reader.read(readBuffer); + } + } + catch (Exception e) { + if (_debug) { + Logger.log(Logger.WARNING, "JSP Fragment Cache: An exception occured while reading " + file.getFullPath(), e); //$NON-NLS-1$ + } + } + finally { + try { + if (contents != null) { + contents.close(); + } + } + catch (Exception e) { + // nothing to do + } + } + } + return s; + } +}