blob: e6243ad5097e3c3e761c777461671eb1638248c8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.LocationKind;
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.NullProgressMonitor;
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.wst.sse.core.internal.util.Debug;
public class FileContentCache {
private static class CacheEntry {
String contents;
long modificationStamp = IResource.NULL_STAMP;
IPath path;
CacheEntry(IPath path) {
this.path = path;
modificationStamp = getModificationStamp(path);
contents = readContents(path);
}
private IFile getFile(IPath path) {
if (path.segmentCount() > 1) {
return ResourcesPlugin.getWorkspace().getRoot().getFile(path);
}
return null;
}
boolean isStale() {
if (modificationStamp == IResource.NULL_STAMP) {
return true;
}
long newStamp = getModificationStamp(path);
return newStamp > modificationStamp;
}
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();
}
private long getModificationStamp(IPath filePath) {
IFile f = getFile(filePath);
if (f != null && f.isAccessible()) {
return f.getModificationStamp();
}
File file = filePath.toFile();
if (file.exists())
return file.lastModified();
return IResource.NULL_STAMP;
}
private String readContents(IPath filePath) {
if (DEBUG)
System.out.println("readContents:" + filePath);
StringBuffer s = new StringBuffer();
InputStream is = null;
try {
IFile f = getFile(filePath);
if (f != null && f.isAccessible()) {
String charset = detectCharset(f);
is = f.getContents();
Reader reader = new InputStreamReader(is, 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.logException(e);
e.printStackTrace();
}
}
finally {
try {
if (is != null) {
is.close();
}
}
catch (Exception e) {
// nothing to do
}
}
if (is == null) {
try {
FileBuffers.getTextFileBufferManager().connect(filePath, LocationKind.LOCATION, new NullProgressMonitor());
ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(filePath, LocationKind.LOCATION);
if (buffer != null) {
s.append(buffer.getDocument().get());
}
}
catch (CoreException e) {
// nothing to do
Logger.logException(e);
}
finally {
try {
FileBuffers.getTextFileBufferManager().disconnect(filePath, LocationKind.LOCATION, new NullProgressMonitor());
}
catch (CoreException e) {
Logger.logException(e);
}
}
}
return s.toString();
}
}
static final boolean DEBUG = false;
static FileContentCache instance = new FileContentCache();
public static FileContentCache getInstance() {
return instance;
}
private HashMap fContentMap;
private FileContentCache() {
super();
fContentMap = new HashMap();
}
private void cleanup() {
Iterator iterator = fContentMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
if (entry.getValue() != null && ((Reference) entry.getValue()).get() == null) {
iterator.remove();
}
}
}
public String getContents(IPath filePath) {
if (DEBUG)
System.out.println("getContents:" + filePath);
CacheEntry entry = null;
Object o = fContentMap.get(filePath);
if (o instanceof Reference) {
entry = (CacheEntry) ((Reference) o).get();
}
if (entry == null || entry.isStale()) {
if (DEBUG && entry != null && entry.isStale())
System.out.println("stale contents:" + filePath);
entry = new CacheEntry(filePath);
fContentMap.put(filePath, new SoftReference(entry));
}
cleanup();
return entry.contents;
}
}