blob: f91199d5341f22edbd7cb03217895326573a9148 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 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.wst.jsdt.debug.internal.core.launching;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
import org.eclipse.wst.jsdt.debug.core.model.IJavaScriptStackFrame;
import org.eclipse.wst.jsdt.debug.core.model.IScript;
import org.eclipse.wst.jsdt.debug.internal.core.Constants;
import org.eclipse.wst.jsdt.debug.internal.core.JavaScriptDebugPlugin;
/**
* Utility class to help with looking up source
*
* @since 1.1
*/
public final class SourceLookup {
public static final QualifiedName SCRIPT_URL = new QualifiedName(JavaScriptCore.PLUGIN_ID, "scriptURL"); //$NON-NLS-1$
public static final IPath TOP_LEVEL_PATH = new Path("/"); //$NON-NLS-1$
/**
* Returns the name of the source object to lookup or <code>null</code>
* if the object is not a {@link IJavaScriptStackFrame} or an {@link IScript}
*
* @param object the object to look up source for
* @return the name of the source element to look up or <code>null</code>
* @since 1.1
*/
public static String getSourceName(Object object) {
String name = null;
if (object instanceof IJavaScriptStackFrame) {
name = ((IJavaScriptStackFrame) object).getSourceName();
}
if(object instanceof IScript) {
name = URIUtil.lastSegment(((IScript)object).sourceURI());
}
if(name != null) {
if(new Path(name).getFileExtension() == null) {
//append .js, there is no case where we would look up a file with no extension from a script node
StringBuffer buf = new StringBuffer(name.length()+3);
buf.append(name).append('.').append(Constants.JS_EXTENSION);
return buf.toString();
}
return name;
}
return null;
}
/**
* Returns the raw element source to use to display an external editor. This method
* will make a request from the backing {@link VirtualMachine}.
*
* @param sourceobj the object to get the raw source from
* @return the raw source or <code>null</code>
*/
public static String getSource(Object sourceobj) {
if(sourceobj instanceof IJavaScriptStackFrame) {
IJavaScriptStackFrame jframe = (IJavaScriptStackFrame) sourceobj;
return jframe.getSource();
}
if(sourceobj instanceof IScript) {
IScript script = (IScript) sourceobj;
return script.source();
}
return null;
}
/**
* Returns the {@link URI} to use to look up source
*
* @param sourceobj the object to get the source {@link URI} for
* @return the {@link URI} or <code>null</code>
*/
public static URI getSourceURI(Object sourceobj) {
if(sourceobj instanceof IJavaScriptStackFrame) {
IJavaScriptStackFrame jframe = (IJavaScriptStackFrame) sourceobj;
try {
try {
return new URI(jframe.getSourcePath());
}
catch (URISyntaxException use) {
return URIUtil.fromString(jframe.getSourcePath());
}
} catch (URISyntaxException e) {
JavaScriptDebugPlugin.log(e);
}
}
if(sourceobj instanceof IScript) {
IScript script = (IScript) sourceobj;
return script.sourceURI();
}
return null;
}
/**
* Returns the external source from the given {@link URI}. This method queries the <code>External JavaScript Source</code>
* project and create it and the source {@link IFile} if necessary.
*
* @param sourceuri the {@link URI} to get the source for
* @param sourceobj the backing object we want to get the source for
* @throws CoreException
*/
public static IFile getExternalSource(URI sourceuri, Object sourceobj) throws CoreException {
String source = getSource(sourceobj);
if(source != null) {
IProject project = JavaScriptDebugPlugin.getExternalSourceProject(true);
IPath path = getSourcePath(sourceuri);
IFile file = project.getFile(path);
if(!file.isAccessible()) {
IContainer folder = project;
for (int i = 0; i < path.segmentCount()-1; i++) {
IFolder f = folder.getFolder(new Path(path.segment(i)));
if(!f.exists()) {
f.create(true, true, null);
}
folder = f;
}
file = doFormat(file, source);
}
else {
file = doFormat(file, source);
}
file.setPersistentProperty(SCRIPT_URL, sourceuri.toString());
return file;
}
return null;
}
/**
* Returns the source path from the given source {@link URI}.
* <br>
* This path may be altered as follows:
* <ul>
* <li>if the URI path is only a root ('/') than the returned path is changed to 'page.js'</li>
* <li>if the source URI has a host specification, it is added to the beginning of the source path</li>
* <li>if the total character count of any one segment of the path exceeds 15 chars, the path is pruned to avoid
* going over the windows 255 char path limit</li>
* </ul>
* @param sourceuri
* @return the {@link IPath} to use to represent the given source {@link URI}
*/
public static IPath getSourcePath(URI sourceuri) {
String uripath = sourceuri.getPath();
if(uripath == null) {
return null;
}
if(uripath.trim().equals("/")) { //$NON-NLS-1$
uripath = "index.htm"; //$NON-NLS-1$
}
String host = sourceuri.getHost();
IPath path = null;
if(host != null) {
path = new Path(host);
}
if(path == null) {
path = new Path(uripath);
}
else {
path = path.append(uripath);
}
return adjustPath(path);
}
/**
* Formats the given source into the given file handle
* @param handle
* @param source
* @return the file handle
* @throws CoreException
*/
static IFile doFormat(IFile handle, String source) throws CoreException {
/*CodeFormatter formatter = ToolFactory.createCodeFormatter(null);
TextEdit edit = formatter.format(CodeFormatter.K_JAVASCRIPT_UNIT, source, 0, source.length(), 0, null);
String localsrc = source;
if(edit != null) {
Document doc = new Document(source);
try {
edit.apply(doc);
localsrc = doc.get();
} catch (Exception e) {
JavaScriptDebugPlugin.log(e);
}
}*/
if(handle.isAccessible()) {
handle.setContents(new ByteArrayInputStream(source.getBytes()), IResource.FORCE, null);
}
else {
handle.create(new ByteArrayInputStream(source.getBytes()), true, null);
}
return handle;
}
/**
* Makes some sanity adjustments to the path prior to trying to create it.
* <ul>
* <li>make sure no one segment is super long, the current threshold is 15 characters per segment</li>
* <li>make sure no segment following the host part has '.js' in it. This prevents name collisions like:
* www.domain.org/scripts/myscript.js/eval/1.js and www.domain.org/scripts/myscript.js - where myscript.js will cause a
* collision trying to create a file resource, as it could already exist as a folder and vice versa
* </li>
* <li>if the script has no extension add .js to make sure Eclipse opens the correct editor for the content type</li>
* <ul>
* @param path
* @return the adjusted path
* @since 1.1
*/
static IPath adjustPath(IPath path) {
String segment = null;
ArrayList segments = new ArrayList(path.segmentCount());
for (int i = 0; i < path.segments().length; i++) {
segment = path.segment(i);
if(i > 0) {
if(segment.length() > 15) {
segment = segment.substring(0, 1) + segment.charAt(segment.length()-1);
}
if(i < path.segments().length-1) {
segment = segment.replaceAll("\\.js", "\\_js"); //$NON-NLS-1$ //$NON-NLS-2$
segment = segment.replaceAll("\\.html", "\\_html"); //$NON-NLS-1$ //$NON-NLS-2$
//segments can never end in '.' it is reserved on all platforms
if(segment.endsWith(".")) { //$NON-NLS-1$
segment = segment.substring(0, segment.length()-1) + '_';
}
}
}
segments.add(segment);
}
IPath newpath = new Path((String) segments.get(0));
for (int i = 1; i < segments.size(); i++) {
newpath = newpath.append((String) segments.get(i));
}
String ext = newpath.getFileExtension();
if(ext == null && !Constants.JS_EXTENSION.equals(ext)) {
newpath = newpath.addFileExtension(Constants.JS_EXTENSION);
}
return newpath;
}
}