blob: 78332d11ffde308896d1b3ded030077fcf8c9e78 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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.java.search;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
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.Path;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jface.text.Position;
import org.eclipse.jst.jsp.core.internal.Logger;
import org.eclipse.jst.jsp.core.internal.java.IJSPTranslation;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslation;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslationAdapter;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslationExtension;
import org.eclipse.jst.jsp.core.internal.modelhandler.ModelHandlerForJSP;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.exceptions.UnsupportedCharsetExceptionWithDetail;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
/**
* Created with a .jsp file, but should appear to be a .java file for indexing
* and searching purposes. There are purposely few fields in this class, and
* those fields are lightweight since it's possible for many JSP search
* documents to exist in memory at one time (eg. after importing a project
* with a large number of JSP files)
*
* @author pavery
*/
public class JSPSearchDocument {
private String UNKNOWN_PATH = "**path unknown**"; //$NON-NLS-1$
private String fJSPPathString = UNKNOWN_PATH;
private String fCUPath = UNKNOWN_PATH;
private SearchParticipant fParticipant = null;
private long fLastModifiedStamp;
private char[] fCachedCharContents;
/**
* @param file
* @param participant
* @throws CoreException
*/
public JSPSearchDocument(String filePath, SearchParticipant participant) {
this.fJSPPathString = filePath;
this.fParticipant = participant;
}
public SearchParticipant getParticipant() {
return this.fParticipant;
}
/**
* @see org.eclipse.jdt.core.search.SearchDocument#getCharContents()
*/
public char[] getCharContents() {
if(fCachedCharContents == null || isDirty()) {
JSPTranslation trans = getJSPTranslation();
fCachedCharContents = trans != null ? trans.getJavaText().toCharArray() : new char[0];
fCUPath = trans.getJavaPath();
}
return fCachedCharContents;
}
public String getJavaText() {
return new String(getCharContents());
}
private IModelManager getModelManager() {
return StructuredModelManager.getModelManager();
}
/**
* It's not recommended for clients to hold on to this JSPTranslation
* since it's kind of large. If possible, hold on to the
* JSPSearchDocument, which is more of a lightweight proxy.
*
* @return the JSPTranslation for the jsp file, or null if it's an
* unsupported file.
*/
public final JSPTranslationExtension getJSPTranslation() {
JSPTranslationExtension translation = null;
IFile jspFile = getFile();
if (!JSPSearchSupport.isJsp(jspFile))
return translation;
IStructuredModel model = null;
try {
// get existing model for read, then get document from it
IModelManager modelManager = getModelManager();
if (modelManager != null) {
jspFile.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
model = modelManager.getModelForRead(jspFile);
}
// handle unsupported
if (model instanceof IDOMModel) {
IDOMModel xmlModel = (IDOMModel)model;
setupAdapterFactory(xmlModel);
IDOMDocument doc = xmlModel.getDocument();
JSPTranslationAdapter adapter = (JSPTranslationAdapter) doc.getAdapterFor(IJSPTranslation.class);
translation = adapter.getJSPTranslation();
}
}
catch (IOException e) {
Logger.logException(e);
}
catch (CoreException e) {
Logger.logException(e);
}
catch (UnsupportedCharsetExceptionWithDetail e) {
// no need to log this. Just consider it an invalid file for our
// purposes.
// Logger.logException(e);
}
finally {
if (model != null)
model.releaseFromRead();
}
return translation;
}
/**
* add the factory for JSPTranslationAdapter here
*
* @param sm
*/
private void setupAdapterFactory(IStructuredModel sm) {
ModelHandlerForJSP.ensureTranslationAdapterFactory(sm);
}
/**
* the path to the Java compilation unit
*
* @see org.eclipse.jdt.core.search.SearchDocument#getPath()
*/
public String getPath() {
// caching the path since it's expensive to get translation
// important that isDirty() check is second to cache modification stamp
if(this.fCUPath == null || isDirty() || this.fCUPath == UNKNOWN_PATH) {
JSPTranslation trans = getJSPTranslation();
if(trans != null) {
this.fCUPath = trans.getJavaPath();
// save since it's expensive to calculate again later
fCachedCharContents = trans.getJavaText().toCharArray();
}
}
return fCUPath != null ? fCUPath : UNKNOWN_PATH;
}
public int getJspOffset(int javaOffset) {
// copied from JSPTranslation
int result = -1;
int offsetInRange = 0;
Position jspPos, javaPos = null;
JSPTranslation trans = getJSPTranslation();
if (trans != null) {
HashMap java2jspMap = trans.getJava2JspMap();
// iterate all mapped java ranges
Iterator it = java2jspMap.keySet().iterator();
while (it.hasNext()) {
javaPos = (Position) it.next();
// need to count the last position as included
if (!javaPos.includes(javaOffset) && !(javaPos.offset + javaPos.length == javaOffset))
continue;
offsetInRange = javaOffset - javaPos.offset;
jspPos = (Position) java2jspMap.get(javaPos);
if (jspPos != null)
result = jspPos.offset + offsetInRange;
else {
Logger.log(Logger.ERROR, "jspPosition was null!" + javaOffset); //$NON-NLS-1$
}
break;
}
}
return result;
}
public IFile getFile() {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath jspPath = new Path(this.fJSPPathString);
IFile jspFile = root.getFile(jspPath);
if (!jspFile.exists()) {
// possibly outside workspace
jspFile = root.getFileForLocation(jspPath);
}
return jspFile;
}
private boolean isDirty() {
boolean modified = false;
IFile f = getFile();
if(f != null) {
long currentStamp = f.getModificationStamp();
if(currentStamp != fLastModifiedStamp)
modified = true;
fLastModifiedStamp = currentStamp;
}
return modified;
}
public void release() {
// nothing to do now since JSPTranslation is created on the fly
}
/**
* for debugging
*/
public String toString() {
return "[JSPSearchDocument:" + this.fJSPPathString + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.search.SearchDocument#getEncoding()
*/
public String getEncoding() {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.search.SearchDocument#getByteContents()
*/
public byte[] getByteContents() {
// TODO Auto-generated method stub
return null;
}
}