StandardPreverifier.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
eclipseme.core.model.impl |
![]() |
![]() |
EclipseME |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/**
* Copyright (c) 2003-2006 Craig Setera
* All Rights Reserved.
* Licensed under the Eclipse Public License - v 1.0
* For more information see http://www.eclipse.org/legal/epl-v10.html
*/
package eclipseme.core.model.impl;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.IStreamListener;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IStreamMonitor;
import org.eclipse.debug.core.model.IStreamsProxy;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstallType;
import org.eclipse.jdt.launching.JavaRuntime;
import eclipseme.core.BuildLoggingConfiguration;
import eclipseme.core.IEclipseMECoreConstants;
import eclipseme.core.console.BuildConsoleProxy;
import eclipseme.core.console.IBuildConsoleProxy;
import eclipseme.core.internal.EclipseMECorePlugin;
import eclipseme.core.internal.PreferenceAccessor;
import eclipseme.core.internal.utils.EnvironmentVariables;
import eclipseme.core.internal.utils.TemporaryFileManager;
import eclipseme.core.internal.utils.Utils;
import eclipseme.core.model.IMidletSuiteProject;
import eclipseme.core.model.IPreverifier;
import eclipseme.core.model.Version;
import eclipseme.core.persistence.IPersistenceProvider;
import eclipseme.core.persistence.PersistenceException;
import eclipseme.preverifier.results.IClassErrorInformation;
import eclipseme.preverifier.results.PreverificationError;
import eclipseme.preverifier.results.PreverificationErrorLocation;
import eclipseme.preverifier.results.PreverificationErrorLocationType;
import eclipseme.preverifier.results.PreverificationErrorType;
/**
* A standard preverifier implementation. This preverifier
* requires the preverification binary and the available
* CLDC parameters to be specified. Once created, the
* preverifier may be stored and retrieved using the standard
* persistence mechanism.
* <p />
* Copyright (c) 2003-2006 Craig Setera<br>
* All Rights Reserved.<br>
* Licensed under the Eclipse Public License - v 1.0<p/>
* <br>
* $Revision: 1.7 $
* <br>
* $Date: 2006/12/18 02:13:47 $
* <br>
* @author Craig Setera
*/
public class StandardPreverifier implements IPreverifier {
private static final int MAX_COMMAND_LENGTH = 2000;
// The regular expression we will use to match the preverify
// error
private static final String PREV_ERR_REGEX =
"^Error preverifying class (\\S*)$";
// The compiled pattern for regular expression matching
private static final Pattern PREV_ERR_PATTERN =
Pattern.compile(PREV_ERR_REGEX, Pattern.MULTILINE);
/**
* Extract the class name from the specified
* IResource within the specified java project.
*
* @param javaProject the java project to provide the relative name
* @param resource the resource to extract a class name
* @return the class name or <code>null</code> if the resource
* name cannot be converted for some reason.
* @throws JavaModelException
*/
public static String extractClassName(
IJavaProject javaProject,
IResource resource)
throws JavaModelException
{
IPath classPath = extractResourcePath(javaProject, resource);
return (classPath == null) ? null :
classPath.removeFileExtension().toString().replace('/', '.');
}
/**
* Extract the class path from the specified
* IResource within the specified java project.
*
* @param javaProject
* @param resource
* @return the extracted resource path
* @throws JavaModelException
*/
public static IPath extractResourcePath(
IJavaProject javaProject,
IResource resource)
throws JavaModelException
{
IPath resultPath = null;
IPath projectOutputPath =
javaProject.getOutputLocation().makeAbsolute();
IPath resourcePath = resource.getFullPath();
IClasspathEntry[] classpath = javaProject.getRawClasspath();
for (int i = 0; i < classpath.length; i++) {
IClasspathEntry entry = classpath[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
IPath entryPath = entry.getOutputLocation();
entryPath = (entryPath == null) ?
projectOutputPath : entryPath.makeAbsolute();
if (entryPath.isPrefixOf(resourcePath)) {
resultPath =
resourcePath.removeFirstSegments(entryPath.segmentCount());
}
}
}
return resultPath;
}
// The executable to use for preverification
private File preverifierExecutable;
// The parameters to use
private StandardPreverifierParameters parameters;
/**
* @see eclipseme.core.persistence.IPersistable#loadUsing(eclipseme.core.persistence.IPersistenceProvider)
*/
public void loadUsing(IPersistenceProvider persistenceProvider)
throws PersistenceException
{
String preverifierExeString = persistenceProvider.loadString("preverifierExecutable");
preverifierExecutable = new File(preverifierExeString);
parameters = (StandardPreverifierParameters) persistenceProvider.loadPersistable("parameters");
}
/**
* @see eclipseme.core.model.IPreverifier#preverify(eclipseme.core.model.IMidletSuiteProject, org.eclipse.core.resources.IResource[], org.eclipse.core.resources.IFolder, org.eclipse.core.runtime.IProgressMonitor)
*/
public PreverificationError[] preverify(
IMidletSuiteProject midletProject,
IResource[] toVerify,
IFolder outputFolder,
IProgressMonitor monitor)
throws CoreException, IOException
{
ArrayList allErrors = new ArrayList();
// Create the temporary file of commands for
// the verifier
ensureFolderExists(outputFolder, monitor);
File outputFile = outputFolder.getLocation().toFile();
ArrayList baseArguments = constructCommandLine(
midletProject,
outputFile,
monitor);
ArrayList arguments = new ArrayList(baseArguments);
for (int i = 0; i < toVerify.length; i++) {
IResource resource = toVerify[i];
switch (resource.getType()) {
case IResource.FOLDER:
case IResource.PROJECT:
arguments.add(resource.getLocation().toOSString());
break;
case IResource.FILE:
if (resource.getName().endsWith(".class")) {
addClassTarget(arguments, resource);
} else if (resource.getName().endsWith(".jar")) {
arguments.add(resource.getLocation().toOSString());
}
break;
}
if (commandLength(arguments) > MAX_COMMAND_LENGTH) {
// Launch the system process
String[] commandLine = (String[]) arguments.toArray(new String[arguments.size()]);
PreverificationError[] errors = runPreverifier(commandLine, null, monitor);
allErrors.addAll(Arrays.asList(errors));
arguments = new ArrayList(baseArguments);
}
}
if (arguments.size() != baseArguments.size()) {
// Launch the system process
String[] commandLine = (String[]) arguments.toArray(new String[arguments.size()]);
PreverificationError[] errors = runPreverifier(commandLine, null, monitor);
allErrors.addAll(Arrays.asList(errors));
}
return (PreverificationError[]) allErrors.toArray(new PreverificationError[allErrors.size()]);
}
/**
* @see eclipseme.core.model.IPreverifier#preverifyJarFile(eclipseme.core.model.IMidletSuiteProject, java.io.File, org.eclipse.core.resources.IFolder, org.eclipse.core.runtime.IProgressMonitor)
*/
public PreverificationError[] preverifyJarFile(
IMidletSuiteProject midletProject,
File jarFile,
IFolder outputFolder,
IProgressMonitor monitor)
throws CoreException, IOException
{
// Rather than trying to preverify a jar file, we will expand it
// first and then preverify against the expanded classes.
File srcDirectory = TemporaryFileManager.instance.createTempDirectory(
jarFile.getName().replace('.', '_') + "_",
".tmp");
srcDirectory.mkdirs();
Utils.extractArchive(jarFile, srcDirectory);
// Create the target directory for the preverification. We will
// tell the preverifier to use this when doing the preverification.
File tgtDirectory = TemporaryFileManager.instance.createTempDirectory(
jarFile.getName().replace('.', '_') + "_",
".tmp");
tgtDirectory.mkdirs();
ArrayList arguments = constructCommandLine(
midletProject,
tgtDirectory,
monitor);
arguments.add(srcDirectory.toString());
// Launch the system process
String[] environment = getEnvironment(jarFile);
String[] commandLine = (String[]) arguments.toArray(new String[arguments.size()]);
PreverificationError[] errors = runPreverifier(commandLine, environment, monitor);
// TODO we need to test the outcome of the previous before going much further
// here...
// Copy all of the non-class resources so they end up back in the
// jar file
FileFilter classFilter = new FileFilter() {
public boolean accept(File pathname) {
return
pathname.isDirectory() ||
!pathname.getName().endsWith(".class");
}
};
Utils.copy(srcDirectory, tgtDirectory, classFilter);
// Finally, re-jar the output of the preverification into the requested jar file...
File outputJarFile = new File(outputFolder.getLocation().toFile(), jarFile.getName());
Utils.createArchive(outputJarFile, tgtDirectory);
return errors;
}
/**
* Return the length of the command-line length given the specified argument list.
*
* @param arguments
* @return
*/
private int commandLength(ArrayList arguments) {
int length = 0;
Iterator iter = arguments.iterator();
while (iter.hasNext()) {
Object arg = (Object) iter.next();
length += arg.toString().length();
if (iter.hasNext()) length++;
}
return length;
}
/**
* Construct the command line for the specified preverification.
*
* @param midletProject
* @param target
* @return
* @throws CoreException
*/
private ArrayList constructCommandLine(
IMidletSuiteProject midletProject,
File target,
IProgressMonitor monitor)
throws CoreException
{
ArrayList arguments = new ArrayList();
// The program we are running...
arguments.add(preverifierExecutable.toString());
// Configuration parameters
String[] configurationParameters = getCLDCConfigurationParameters(midletProject);
for (int i = 0; i < configurationParameters.length; i++) {
arguments.add(configurationParameters[i]);
}
addClasspath(arguments, midletProject, monitor);
addOptions(arguments, configurationParameters, target);
return arguments;
}
/**
* @return Returns the parameters.
*/
public StandardPreverifierParameters getParameters() {
return parameters;
}
/**
* @return Returns the preverifierExecutable.
*/
public File getPreverifierExecutable() {
return preverifierExecutable;
}
/**
* @param parameters The parameters to set.
*/
public void setParameters(StandardPreverifierParameters parameters) {
this.parameters = parameters;
}
/**
* @param preverifierExecutable The preverifierExecutable to set.
*/
public void setPreverifierExecutable(File preverifierExecutable) {
this.preverifierExecutable = preverifierExecutable;
}
/**
* @see eclipseme.core.persistence.IPersistable#storeUsing(eclipseme.core.persistence.IPersistenceProvider)
*/
public void storeUsing(IPersistenceProvider persistenceProvider)
throws PersistenceException
{
persistenceProvider.storeString("preverifierExecutable", preverifierExecutable.toString());
persistenceProvider.storePersistable("parameters", parameters);
}
/**
* Return the parameters to be used for controlling the CLDC
* preverification.
*
* @param midletProject
* @return
* @throws CoreException if an error occurs working with the midlet project.
*/
protected String[] getCLDCConfigurationParameters(IMidletSuiteProject midletProject)
throws CoreException
{
IProject project = midletProject.getProject();
Version configVersion =
PreferenceAccessor.instance.getPreverificationConfigurationVersion(project);
return isCLDC1_0(configVersion) ? parameters.cldc10 : parameters.cldc11;
}
/**
* Return a boolean indicating whether the specified configuration
* is a 1.0 CLDC config.
*
* @param configSpec
* @return
*/
protected boolean isCLDC1_0(Version configVersion) {
return (configVersion.getMajor().equals("1") && configVersion.getMinor().equals("0"));
}
/**
* Run the preverifier program and capture the errors that
* occurred during preverification.
*
* @param commandLine
* @param environment
* @throws CoreException
*/
protected PreverificationError[] runPreverifier(
String[] commandLine,
String[] environment,
IProgressMonitor monitor)
throws CoreException
{
final ArrayList errorList = new ArrayList();
IProcess process = Utils.launchApplication(
commandLine, null,
environment,
"Preverifier", "CLDC Preverifier");
// Listen on the process output streams
IStreamsProxy proxy = process.getStreamsProxy();
if (BuildLoggingConfiguration.instance.isPreverifierOutputEnabled()) {
BuildConsoleProxy.instance.traceln("======================== Launching Preverification =========================");
BuildConsoleProxy.instance.addConsoleStreamListener(
IBuildConsoleProxy.ID_ERROR_STREAM,
proxy.getErrorStreamMonitor());
BuildConsoleProxy.instance.addConsoleStreamListener(
IBuildConsoleProxy.ID_OUTPUT_STREAM,
proxy.getOutputStreamMonitor());
}
proxy.getErrorStreamMonitor().addListener(new IStreamListener() {
public void streamAppended(String text, IStreamMonitor monitor) {
handleErrorReceived(text, errorList);
}
});
// Wait until completion
while ((!monitor.isCanceled()) && (!process.isTerminated())) {
try { Thread.sleep(100); } catch (InterruptedException e) {};
}
if (BuildLoggingConfiguration.instance.isPreverifierOutputEnabled()) {
BuildConsoleProxy.instance.traceln("======================== Preverification exited with code: " + process.getExitValue());
}
return (PreverificationError[]) errorList.toArray(new PreverificationError[errorList.size()]);
}
/**
* Add classpath information to the arguments for
* the specified java project and referenced projects.
*
* @param commandLine
* @param midletProject
* @throws CoreException
*/
private void addClasspath(ArrayList args, IMidletSuiteProject midletProject, IProgressMonitor monitor)
throws CoreException
{
String classpath = getFullClasspath(midletProject);
args.add("-classpath");
args.add(classpath);
}
/**
* Add a class target to the resources to be verified.
*
* @param args
* @param resource
* @throws JavaModelException
*/
private void addClassTarget(
List args,
IResource resource)
throws JavaModelException
{
// Find the source directory this class resides in
IProject project = resource.getProject();
IJavaProject javaProject = JavaCore.create(project);
String className = extractClassName(javaProject, resource);
if (className != null) {
args.add(className);
}
}
/**
* Add the options to the argument list.
*
* @param args
* @param configurationParameters
* @param outputDir
*/
private void addOptions(
ArrayList args,
String[] configurationParameters,
File outputDir)
{
args.add("-d");
args.add(outputDir.toString());
}
/**
* Ensure the specified output folder exists or create if it does not already
* exist.
*
* @param folder
* @param monitor
* @throws CoreException
*/
private void ensureFolderExists(IFolder folder, IProgressMonitor monitor) throws CoreException {
// Make sure the output folder exists before we start
if (!folder.exists()) {
folder.create(true, true, monitor);
}
}
/**
* Get the environment values for the preverification processing.
*
* @param The resources to verify. If this is a jar file, the
* jar program must be available on the path.
* @return
* @throws CoreException
*/
private String[] getEnvironment(File jarFileToVerify)
throws CoreException
{
String[] environment = null;
if (jarFileToVerify != null) {
// See if the jar executable is available already...
if (!isJarExecutableOnPath()) {
// See if we can get it from the VM installation
IVMInstall fullJDK = searchForVMInstallWithJar();
if (fullJDK == null) {
IStatus status = EclipseMECorePlugin.newStatus(
IStatus.ERROR,
IEclipseMECoreConstants.ERR_COULD_NOT_FIND_JAR_TOOL,
"Could not find jar tool executable.");
EclipseMECorePlugin.statusPrompt(status, this);
} else {
// Found a VM installation with the jar tool...
// Set the PATH environment value so that the
// preverifier can find the jar tool.
String pathValue =
new File(fullJDK.getInstallLocation(), "bin").toString();
environment = getEnvironmentWithAugmentedPath(pathValue);
}
}
}
return environment;
}
/**
* Augment the PATH environment variables and return them
* in a form that can be used in an exec() call.
*
* @param pathValue
* @return
* @throws CoreException
*/
private String[] getEnvironmentWithAugmentedPath(String pathValue)
throws CoreException
{
String[] environment = null;
try {
EnvironmentVariables envVars = new EnvironmentVariables();
String path = envVars.getVariable("PATH");
path = path + File.pathSeparator + pathValue;
envVars.setVariable("PATH", path);
environment = envVars.convertToStrings();
} catch (IOException e) {
EclipseMECorePlugin.throwCoreException(IStatus.ERROR, -999, e);
}
return environment;
}
/**
* Get the full classpath including all J2ME libraries.
*
* @param midletProject
* @return
* @throws CoreException
*/
private String getFullClasspath(IMidletSuiteProject midletProject) throws CoreException {
IJavaProject javaProject = midletProject.getJavaProject();
String[] entries = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < entries.length; i++) {
if (i != 0) {
sb.append(File.pathSeparatorChar);
}
sb.append(entries[i]);
}
return sb.toString();
}
/**
* Get the executable for creation of jar files.
*
* @return
*/
private String getJarExecutable() {
String executable = null;
String os = System.getProperty("os.name").toLowerCase();
if (
(os.indexOf("windows 9") > -1) ||
(os.indexOf("nt") > -1) ||
(os.indexOf("windows 2000") > -1) ||
(os.indexOf("windows xp") > -1)) {
executable = "jar.exe";
} else {
executable = "jar";
}
return executable;
}
/**
* Handle the arrival of text on the error stream.
*
* @param text
* @param errorList
*/
protected void handleErrorReceived(String text, List errorList)
{
text = text.trim();
Matcher matcher = PREV_ERR_PATTERN.matcher(text);
if (matcher.find()) {
// Found a match for the error...
if (matcher.groupCount() > 0) {
final String classname = matcher.group(1);
String errorText = "Error preverifying class";
if (matcher.end() < text.length()) {
StringBuffer sb = new StringBuffer(errorText);
sb.append(": ");
String detail = text.substring(matcher.end());
detail = detail.trim();
sb.append(detail);
errorText = sb.toString();
}
IClassErrorInformation classInfo = new IClassErrorInformation() {
public String getName() {
return classname;
}
public String getSourceFile() {
return null;
}
};
PreverificationErrorLocation location =
new PreverificationErrorLocation(
PreverificationErrorLocationType.UNKNOWN_LOCATION,
classInfo, null, null, -1);
PreverificationError error = new PreverificationError(
PreverificationErrorType.UNKNOWN_ERROR,
location,
text);
errorList.add(error);
}
} else {
EclipseMECorePlugin.log(IStatus.WARNING, text);
}
}
/**
* Return a boolean indicating whether the specified
* virtual machine installation appears to have the
* jar executable within it.
*
* @param install
* @return
*/
private boolean installContainsJarExecutable(IVMInstall install) {
boolean containsJar = false;
File installLocation = install.getInstallLocation();
if (installLocation != null) {
File bin = new File(installLocation, "bin");
if (bin.exists()) {
File[] matches = bin.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().startsWith("jar");
}
});
containsJar = ((matches != null) && (matches.length > 0));
}
}
return containsJar;
}
/**
* Return a boolean indicating whether the JAR executable can be
* found on the system path.
*
* @param testJar
* @return
* @throws CoreException
*/
private boolean isJarExecutableOnPath()
throws CoreException
{
boolean onPath = false;
String executable = getJarExecutable();
try {
EnvironmentVariables envVars = new EnvironmentVariables();
String pathString = envVars.getVariable("PATH");
StringTokenizer st = new StringTokenizer(pathString, File.pathSeparator);
while (st.hasMoreTokens()) {
File path = new File(st.nextToken());
File jar = new File(path, executable);
if (jar.exists()) {
onPath = true;
break;
}
}
} catch (IOException e) {
EclipseMECorePlugin.throwCoreException(IStatus.ERROR, -999, e);
}
return onPath;
}
/**
* Search for and return a virtual machine installation that appears
* to have the jar tool executable contained within.
*
* @return
*/
private IVMInstall searchForVMInstallWithJar() {
IVMInstall fullJDK = null;
IVMInstall install = JavaRuntime.getDefaultVMInstall();
if (installContainsJarExecutable(install)) {
fullJDK = install;
} else {
IVMInstallType installType = install.getVMInstallType();
IVMInstall[] installs = installType.getVMInstalls();
for (int i = 0; i < installs.length; i++) {
install = installs[i];
if (installContainsJarExecutable(install)) {
fullJDK = install;
break;
}
}
}
return fullJDK;
}
}
The table below shows all metrics for StandardPreverifier.java.




