net.rim.ejde.internal.packaging.PackagingManager.java Source code

Java tutorial

Introduction

Here is the source code for net.rim.ejde.internal.packaging.PackagingManager.java

Source

/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.packaging;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.rim.ejde.internal.builders.ALXBuilder;
import net.rim.ejde.internal.builders.ResourceBuilder;
import net.rim.ejde.internal.core.ContextManager;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.core.IRIMMarker;
import net.rim.ejde.internal.launching.DeploymentHelper;
import net.rim.ejde.internal.model.BlackBerryProject;
import net.rim.ejde.internal.model.BlackBerryProjectCoreNature;
import net.rim.ejde.internal.model.BlackBerryProperties;
import net.rim.ejde.internal.model.BlackBerryPropertiesFactory;
import net.rim.ejde.internal.model.BlackBerrySDKInstall;
import net.rim.ejde.internal.model.BlackBerryVMInstallType;
import net.rim.ejde.internal.packaging.JadFile.CodEntry;
import net.rim.ejde.internal.ui.consoles.PackagingConsole;
import net.rim.ejde.internal.util.ImportUtils;
import net.rim.ejde.internal.util.InternalPackagingUtils;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.PackageUtils;
import net.rim.ejde.internal.util.PackagingUtils;
import net.rim.ejde.internal.util.ProblemFactory;
import net.rim.ejde.internal.util.ProjectUtils;
import net.rim.ejde.internal.util.StatusFactory;
import net.rim.ejde.internal.util.VMUtils;
import net.rim.ejde.internal.validation.DiagnosticFactory;
import net.rim.ide.OSUtils;
import net.rim.ide.Project;
import net.rim.ide.core.Util;
import net.rim.sdk.resourceutil.ResourceParseException;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.internal.resources.ResourceException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
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.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathContainer;
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.core.ToolFactory;
import org.eclipse.jdt.core.util.IClassFileReader;
import org.eclipse.jdt.core.util.IMethodInfo;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.jdt.internal.launching.JREContainer;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.LibraryLocation;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.MessageConsoleStream;

/**
 * This class provides methods to package a BlackBerry project.
 *
 * Usually a project has two deployment folders:
 * <p>
 * /deliverables/Standard
 * <p>
 * and
 * <p>
 * /deliverables/Web
 * <p>
 * The project is packaged into the <code>/deliverables/Standard</code> folder and all generated rapc artifacts are copied to the
 * <code>/deliverables/Web</code> folder. However, if the cod file is a zipped parent cod file, we un-zip it and copy all the
 * sibling cod files in the the <code>/deliverables/Web</code> folder.
 */
public class PackagingManager {
    static final Logger _log = Logger.getLogger(PackagingManager.class);
    static final int MAX_COMMAND_ELEMENTS = 30;
    public static final String COMPRESS_RESOURCE_OPTION = "-cr";
    public static final String CONVERT_PNG_RAPC_OPTION = "-convertpng";
    public static final String VERBOSE_RAPC_OPTION = "-verbose";
    public static final int MIDLET_JAR = 0x0001;
    public static final int EVISCERATED_JAR = 0x0002;
    private Vector<String> _compileOptions;
    private BlackBerryProject _bbProject;
    private List<String> _rapcCommandsHead;
    private List<String> _rapcCommands;
    private Vector<String> _sourceRoots;
    private Vector<String> _protectionOptions;
    private Vector<ImportedJar> _imports;
    private Vector<String> _otherFiles;
    private Vector<String> _outputFolders;
    private MessageConsoleStream _consoleOutputStream;
    private boolean writeToFile;

    private PackagingManager(BlackBerryProject bbProject) {
        _bbProject = bbProject;
        _compileOptions = new Vector<String>();
        _sourceRoots = new Vector<String>();
        _imports = new Vector<ImportedJar>();
        _otherFiles = new Vector<String>();
        _protectionOptions = new Vector<String>();
        _outputFolders = new Vector<String>();
        _rapcCommandsHead = new ArrayList<String>();
        _rapcCommands = new ArrayList<String>();
        // Grab and activate a console to redirect build output to.
        PackagingConsole packagingConsole = PackagingConsole.getInstance();
        ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { packagingConsole });
        _consoleOutputStream = packagingConsole.newMessageStream();
    }

    /**
     * This is a help method to package a BlackBerry project.
     *
     * @param project
     *            A BlackBerry project
     *
     * @throws CoreException
     */
    static public void packageProject(BlackBerryProject project) throws CoreException {
        PackagingManager packagingManage = new PackagingManager(project);
        packagingManage.internalPackageProject();
    }

    /**
     * This is a help method to package a BlackBerry project.
     *
     * @param project
     *            A BlackBerry project
     *
     * @throws CoreException
     */
    static public void generateALXForProject(BlackBerryProject project) throws CoreException {
        PackagingManager packagingManage = new PackagingManager(project);
        // if the deliverable folder does not exist, create it
        IProject eclipseProject = project.getProject();
        IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(project));
        try {
            ImportUtils.createFolders(eclipseProject, outputFolderPath, IResource.DERIVED);
        } catch (CoreException e) {
            throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID,
                    project.getMetaFileHandler().getProjectRelativePath(),
                    NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG, outputFolderPath), e);
        }
        packagingManage.internalGenerateALX();
    }

    private void internalGenerateALX() throws CoreException {
        generateALX();
        IResource outputFolder = _bbProject.getProject()
                .findMember(new Path(PackagingUtils.getRelativeAlxFileOutputFolder(_bbProject)));
        outputFolder.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
    }

    private void internalPackageProject() throws CoreException {
        final BlackBerrySDKInstall bbVM = PackagingUtils.getBBSDKInstall(_bbProject.getJavaProject());
        if (bbVM == null) {
            String msg = NLS.bind(Messages.PackagingManager_PACKAGING_NO_BB_JRE_MSG,
                    _bbProject.getProject().getName());
            reportProblem(_bbProject.getProject(), -1, 0, 0, msg, Problem.ERROR);
            _log.error(msg);
            return;
        }
        // clean the deployment folders
        try {
            PackagingUtils.cleanProjectOutputFolder(_bbProject);
        } catch (CoreException e) {
            _log.error(e);
        }
        IProject eclipseProject = _bbProject.getProject();
        // if the deliverable folder does not exist, create it
        IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(_bbProject));
        try {
            ImportUtils.createFolders(eclipseProject, outputFolderPath, IResource.DERIVED);
        } catch (CoreException e) {
            throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID,
                    _bbProject.getMetaFileHandler().getProjectRelativePath(),
                    NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG, outputFolderPath), e);
        }

        // calculate rapc commands
        calculateRAPCCommand();
        // check if the project should be packaged
        if (!shouldPackage()) {
            return;
        }
        // run rapc command
        runRapcCommand();
        // post packaging steps
        postPackagingProcess(_bbProject);
    }

    private void postPackagingProcess(BlackBerryProject BBProject) throws CoreException {
        IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(_bbProject));
        IResource outputFolder = BBProject.getProject().findMember(outputFolderPath);
        // copy the cod files of dependency projects to the deployment folders
        copyDependencyDeploymentFiles();
        // Refresh to show new resources
        outputFolder.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
        // Generate ALX File
        if (BBProject.getProperties()._packaging.getGenerateALXFile().booleanValue()) {
            generateALX();
        }
    }

    /**
     * Copies the deployment files of the dependent projects to the corresponding deployment folders.
     *
     * @throws CoreException
     */
    private void copyDependencyDeploymentFiles() throws CoreException {
        IPath standardSrcFolderPath, standardDstFolderPath;
        String outputFileName;
        IPath absoluteStandardSrcFolderPath, absoluteStandardDstFolderPath;
        List<CodEntry> codEntries = new ArrayList<CodEntry>();
        String mainVersion = PackagingUtils.getVMOutputFolderName(_bbProject);
        for (BlackBerryProject dependentProj : ProjectUtils.getAllReferencedProjects(_bbProject)) {
            JadFile jadFile = null;
            try {
                jadFile = new JadFile(getJadFilePath(dependentProj).toFile());
                jadFile.parseJadFile();
                String dependencyVersion = PackagingUtils.getVMOutputFolderName(dependentProj);
                if (!mainVersion.equals(dependencyVersion)) {
                    // if the BB JRE of the main project is different than the dependency projects, need to calculate the cod
                    // relative paths
                    for (CodEntry entry : jadFile.getCodeEntries()) {
                        entry.setUrl(".." + File.separator + dependencyVersion + File.separator + entry.getUrl());
                    }
                }
                codEntries.addAll(jadFile.getCodeEntries());
            } catch (IOException e) {
                _log.error(e);
            }
            // get the standard deployment folder of the dependent project
            standardDstFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(dependentProj));
            // get the standard corresponding deployment folder of the main project
            absoluteStandardDstFolderPath = _bbProject.getProject().getLocation().append(standardDstFolderPath);
            // make sure the destination folder is created
            try {
                ImportUtils.createFolders(_bbProject.getProject(), standardDstFolderPath, IResource.DERIVED);
            } catch (CoreException e) {
                throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID,
                        _bbProject.getMetaFileHandler().getProjectRelativePath(),
                        NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG,
                                standardDstFolderPath),
                        e);
            }
            // copy deployment files in standard folder
            standardSrcFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(dependentProj));
            absoluteStandardSrcFolderPath = dependentProj.getProject().getLocation().append(standardSrcFolderPath);
            outputFileName = dependentProj.getProperties()._packaging.getOutputFileName();
            File[] outputFiles = absoluteStandardSrcFolderPath.toFile()
                    .listFiles(new DeploymentFileNameFilter(outputFileName));
            _log.trace(
                    "Dependent project " + dependentProj.getElementName() + " copy folder: " + standardSrcFolderPath
                            + " --> " + _bbProject.getElementName() + " / " + standardDstFolderPath);
            for (File file : outputFiles) {
                if (file.exists()) {
                    DeploymentHelper.executeCopy(file,
                            absoluteStandardDstFolderPath.append(file.getName()).toFile());
                }
            }
            // refresh the standard folder
            IFolder folder = _bbProject.getProject().getFolder(standardDstFolderPath);
            folder.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
        }
        if (codEntries.size() != 0) {
            writeCodEntry(codEntries);
        }
    }

    private void writeCodEntry(List<CodEntry> codEntries) {
        File file = getJadFilePath(_bbProject).toFile();
        BufferedWriter writer = null;
        List<String> list = new ArrayList<String>();
        try {
            JadFile jadFile = new JadFile(file);
            jadFile.parseJadFile();
            // add dependency cod entries
            jadFile.addCodEntries(codEntries);
            list = jadFile.getOtherProperties();
            for (CodEntry entry : jadFile.getCodeEntries()) {
                list.add(entry.getCodURLPropertyLine());
                list.add(entry.getCodSizePropertyLine());
                list.add(entry.getCodCreationgTimePropertyLine());
                list.add(entry.getCodShaPropertyLine());
            }
            IPath destFilePath = getJadFilePath(_bbProject);
            destFilePath = destFilePath.removeLastSegments(1);
            destFilePath = destFilePath.append(_bbProject.getProperties().getPackaging().getOutputFileName()
                    + IConstants.FULL_JAD_FILE_SUFFIX + IConstants.JAD_FILE_EXTENSION_WITH_DOT);
            writer = new BufferedWriter(new FileWriter(destFilePath.toFile()));
            for (int i = 0; i < list.size(); i++) {
                writer.write(list.get(i) + "\r\n");
            }
        } catch (Exception e) {
            _log.error(e);
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                _log.error(e);
            }
        }
    }

    public static final void copyInputStream(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int len;

        while ((len = in.read(buffer)) >= 0)
            out.write(buffer, 0, len);

        in.close();
        out.close();
    }

    class DeploymentFileNameFilter implements FilenameFilter {
        String _outputFileName;
        boolean _excludeCodFile;

        public DeploymentFileNameFilter(String outputFileName) {
            _outputFileName = outputFileName;
        }

        public DeploymentFileNameFilter(String outputFileName, boolean excludeCod) {
            _outputFileName = outputFileName;
            _excludeCodFile = excludeCod;
        }

        @Override
        public boolean accept(File dir, String name) {
            if (name.startsWith(_outputFileName)) {
                if (_excludeCodFile) {
                    if (!name.endsWith(IConstants.COD_FILE_EXTENSION_WITH_DOT)) {
                        return true;
                    }
                } else {
                    return true;
                }
            }
            return false;
        }
    }

    private void generateALX() throws CoreException {
        BlackBerryProperties properties = _bbProject.getProperties();
        String targetDir = PackagingUtils.getRelativeAlxFileOutputFolder(_bbProject);
        String targetFolderLocation;
        if (targetDir == null || targetDir.equals(IConstants.EMPTY_STRING)) {
            targetFolderLocation = _bbProject.getProject().getLocation().toOSString();
        } else {
            targetFolderLocation = _bbProject.getProject().getFolder(new Path(targetDir)).getLocation()
                    .toOSString();
        }
        String filename = properties._packaging.getOutputFileName();
        String alxName = targetFolderLocation + File.separator + filename;
        try {
            ALXBuilder.Alx alx = ALXBuilder.generateAlx(null, _bbProject);
            ALXBuilder.write(alxName, alx);
        } catch (ResourceParseException rpe) {
            throw new CoreException(new Status(IStatus.ERROR, ContextManager.PLUGIN_ID, rpe.getMessage()));
        } catch (FileNotFoundException fnfe) {
            throw new CoreException(new Status(IStatus.ERROR, ContextManager.PLUGIN_ID, fnfe.getMessage()));
        }
        // refresh the alx file
        IFile alxFile = _bbProject.getProject().getFolder(new Path(targetDir))
                .getFile(filename + IConstants.ALX_FILE_EXTENSION_WITH_DOT);
        alxFile.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
    }

    private void runRapcCommand() throws CoreException {
        try {
            File workDir = _bbProject.getProject().getLocation().toFile();
            if (writeToFile) {
                File outputFile = null;
                String outputFileName = _bbProject.getProject().getName() + ".files";
                outputFile = new File(workDir, outputFileName);
                _rapcCommandsHead.add("@" + outputFileName);
                flushToFile(outputFile);
            } else {
                _rapcCommandsHead.addAll(_rapcCommands);
            }
            String command = getStringCommand(_rapcCommandsHead);
            _log.trace("Execute rapc command: " + command + "; Working Directory: " + workDir.getPath());
            ProcessBuilder rapcBuilder = new ProcessBuilder(_rapcCommandsHead);

            String javaHome = System.getenv("JAVA_HOME");
            if (javaHome != null) {
                Map<String, String> env = rapcBuilder.environment();
                String pathName = "Path";
                for (String s : env.keySet()) {
                    if (s.equalsIgnoreCase("Path"))
                        pathName = s;
                }
                String path = env.get(pathName);
                path = path == null ? javaHome : (path + File.pathSeparator + javaHome);
                path = path + File.pathSeparator + javaHome + File.separator + "bin";
                env.put(pathName, path);
                _log.trace("PATH=" + path);
            }

            rapcBuilder.directory(workDir);
            rapcBuilder.redirectErrorStream(true);
            long startTime = System.currentTimeMillis();
            _consoleOutputStream.println(
                    NLS.bind(Messages.PackagingManager_PACKAGING_PROJECT_MSG, _bbProject.getProject().getName()));
            _consoleOutputStream.println(command);
            Process process = rapcBuilder.start();
            InputStream inStream = process.getInputStream();
            InputStreamHandler inputHandler = new InputStreamHandler(_bbProject.getProject(), _consoleOutputStream,
                    inStream);
            inputHandler.start();
            int result = process.waitFor();
            inputHandler.join();
            float spendTime = ((float) (System.currentTimeMillis() - startTime)) / 1000;
            if (result == 0) {

                _consoleOutputStream.println(NLS.bind(Messages.PackagingManager_PACKAGING_SUCCEED_MSG,
                        new String[] { _bbProject.getProject().getName(), String.valueOf(spendTime) }));
            } else {
                _consoleOutputStream.println(NLS.bind(Messages.PackagingManager_PACKAGING_FAILED_MSG,
                        new String[] { _bbProject.getProject().getName(), String.valueOf(spendTime) }));
            }
        } catch (IOException e) {
            throw new CoreException(StatusFactory.createErrorStatus(e.getMessage()));
        } catch (InterruptedException e) {
            throw new CoreException(StatusFactory.createErrorStatus(e.getMessage()));
        }
    }

    private void flushToFile(File file) throws IOException {
        FileOutputStream fout = null;
        PrintStream indirect = null;
        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            indirect = new PrintStream(bout, false, "UTF-8");
            for (int i = 0; i < _rapcCommands.size(); i++) {
                indirect.println(_rapcCommands.get(i));
            }
            indirect.close();
            byte[] newBytes = bout.toByteArray();

            // either old file doesn't exist or it isn't the same
            // write out the new data
            fout = new FileOutputStream(file);
            fout.write(newBytes);
            fout.close();
        } finally {
            if (indirect != null) {
                indirect.close();
            }
            if (fout != null) {
                fout.close();
            }
        }
    }

    private String getStringCommand(List<String> commands) {
        StringBuffer command = new StringBuffer();
        for (int i = 0; i < commands.size(); i++) {
            if (i != 0) {
                command.append(IConstants.ONE_BLANK_STRING);
            }
            System.out.println(commands.get(i));
            command.append(commands.get(i));
        }
        return command.toString();
    }

    private void calculateRAPCCommand() throws CoreException {
        // calculate rapc commands
        SourcerootVisitor visitor = new SourcerootVisitor();
        _bbProject.getProject().accept(visitor);
        // get customized jad and rapc files
        String custjad = PackagingUtils.getCustomJadFile(_bbProject);
        if (custjad != null) {
            _otherFiles.add(custjad);
        }
        String custrapc = PackagingUtils.getCustomRapcFile(_bbProject);
        if (custrapc != null) {
            _otherFiles.add(custrapc);
        }
        // get imported jars (project level and workspace level)
        _imports = getCompileImports(_bbProject);
        // check if there is any exported midlet jar
        // TODO: Try invoking rapc.jar in Windows instead of rapc.exe
        if (OSUtils.isWindows()) {
            // add path of rapc.exe
            _rapcCommandsHead.add(getRAPCPath());
        } else {
            _rapcCommandsHead.add("java");
            _rapcCommandsHead.add("-jar");
            // add path of rapc.jar
            _rapcCommandsHead.add(getRAPCPath());
        }

        // get compile options
        _compileOptions = getCompileOptions();
        // add compile options
        if (_compileOptions.size() > 0) {
            _rapcCommandsHead.addAll(_compileOptions);
        }
        // get source roots
        _sourceRoots = visitor.getSourceRoots(_bbProject.getProject());
        // add source roots
        // TODO: Added for preverifier and do more investigation and
        // see whether we can eliminate this option or not.
        if (!OSUtils.isWindows()) {
            String binDir = getRAPCPath().replace("rapc.jar", "");
            String exepath = "-exepath=" + binDir;
            _rapcCommandsHead.add(exepath);
        }
        StringBuffer rapcComandBuffer = new StringBuffer();
        if (_sourceRoots.size() > 0) {
            rapcComandBuffer.append("-sourceroot=");
            rapcComandBuffer.append(composeString(_sourceRoots, File.pathSeparator));
            _rapcCommandsHead.add(rapcComandBuffer.toString());
        }
        // get protection options
        _protectionOptions = getProtectionOptions(false);
        // add imports
        rapcComandBuffer = new StringBuffer();
        writeToFile = (_imports.size() + _protectionOptions.size()) > MAX_COMMAND_ELEMENTS;
        if (_imports.size() > 0) {
            if (writeToFile) {
                for (int i = 0; i < _imports.size(); i++) {
                    _rapcCommands.add("-import=" + _imports.get(i).toString());
                }
            } else {
                rapcComandBuffer.append("-import=");
                rapcComandBuffer.append(composeImportsString(_imports, File.pathSeparator, false));
                _rapcCommands.add(rapcComandBuffer.toString());
            }
        }
        // add protection options
        if (_protectionOptions.size() > 0) {
            _rapcCommands.addAll(_protectionOptions);
        }
        // add exported jar files
        for (int i = 0; i < _imports.size(); i++) {
            if (_imports.get(i).isExported()) {
                _rapcCommands.add(_imports.get(i).getPath());
            }
        }

        prepareDescriptor();

        // add other files
        _rapcCommands.addAll(_otherFiles);
        // get output folders
        getOutputFolder();
        // add output folders
        if (_outputFolders.size() > 0) {
            _rapcCommands.addAll(_outputFolders);
        }
    }

    private void prepareDescriptor() throws CoreException {
        boolean found = false;
        IPath outputFilePath = PackagingUtils.getAbsoluteStandardOutputFilePath(_bbProject).removeLastSegments(1);
        int i;
        for (i = 0; i < _otherFiles.size(); i++) {
            String sl = _otherFiles.get(i).toLowerCase();
            if (sl.endsWith(IConstants.RAPC_FILE_EXTENSION_WITH_DOT)
                    || sl.endsWith(IConstants.JAD_FILE_EXTENSION_WITH_DOT)) {
                File f = new File(_otherFiles.get(i));
                String distFileName = _bbProject.getProperties().getPackaging().getOutputFileName();
                if (sl.endsWith(IConstants.RAPC_FILE_EXTENSION_WITH_DOT)) {
                    distFileName += IConstants.RAPC_FILE_EXTENSION_WITH_DOT;
                    found = true;
                } else {
                    distFileName += IConstants.JAD_FILE_EXTENSION_WITH_DOT;
                }
                File f2 = outputFilePath.append(distFileName).toFile();
                DeploymentHelper.executeCopy(f, f2);
                _otherFiles.set(i, f2.getAbsolutePath());
            }
        }
        if (!found) {
            // generate rapc file
            RAPCFile rapcFile = new RAPCFile(_bbProject);
            rapcFile.loadContent();
            rapcFile.flushToFile();
            _otherFiles.addElement(RAPCFile.getRelativeRapcFilePath(_bbProject).toOSString());
        }
    }

    private IPath getJadFilePath(BlackBerryProject bbProject) {
        IPath outputFilePath = PackagingUtils.getAbsoluteStandardOutputFilePath(bbProject).removeLastSegments(1);
        String jadFileName = bbProject.getProperties().getPackaging().getOutputFileName();
        jadFileName += IConstants.JAD_FILE_EXTENSION_WITH_DOT;
        return outputFilePath.append(jadFileName);
    }

    /**
     * Checks if the project should be packaged.
     *
     * @return
     */
    private boolean shouldPackage() {
        int MidletJarNumber = 0;
        for (ImportedJar jar : _imports) {
            if (jar.isExported()) {
                if (jar.isMidletJar()) {
                    MidletJarNumber++;
                    if (MidletJarNumber != 1) {
                        reportProblem(_bbProject.getProject(), 0, 0, 0,
                                Messages.PackagingManager_MIDLET_JAR_ERROR_MSG1, Problem.ERROR);
                        return false;
                    }
                    Vector<String> jadFiles = getJadFiles(_otherFiles);
                    if (jadFiles.size() == 0) {
                        reportProblem(_bbProject.getProject(), 0, 0, 0,
                                Messages.PackagingManager_MIDLET_JAR_ERROR_MSG2, Problem.WARNING);
                    } else if (jadFiles.size() > 1) {
                        reportProblem(_bbProject.getProject(), 0, 0, 0,
                                Messages.PackagingManager_MIDLET_JAR_ERROR_MSG3, Problem.ERROR);
                        return false;
                    }
                } else if ((jar.getType() & EVISCERATED_JAR) > 0) {
                    reportProblem(_bbProject.getProject(), 0, 0, 0,
                            NLS.bind(Messages.PackagingManager_MIDLET_JAR_ERROR_MSG4, jar._path), Problem.ERROR);
                    return false;
                }
            }
        }
        return true;
    }

    private Vector<String> getJadFiles(Vector<String> files) {
        Vector<String> jadFiles = new Vector<String>();
        for (String file : files) {
            if (file.endsWith(IConstants.JAD_FILE_EXTENSION_WITH_DOT)) {
                jadFiles.add(file);
            }
        }
        return jadFiles;
    }

    private void getOutputFolder() {
        Set<IPath> outputFolderSet = ImportUtils.getOutputPathSet(_bbProject);
        IPath javaOutRelPath;
        for (IPath path : outputFolderSet) {
            // get rid of the first project segment
            javaOutRelPath = path.removeFirstSegments(1).makeRelative();
            IFolder folder = _bbProject.getProject().getFolder(javaOutRelPath);
            if (folder == null || !folder.exists()) {
                continue;
            }
            if (folder.isLinked()) {
                _outputFolders.add(folder.getLocation().toOSString());
            } else {
                _outputFolders.add(_bbProject.getProject().getLocation().append(javaOutRelPath).toOSString());
            }
        }
    }

    private String composeImportsString(Vector<ImportedJar> vector, String separator, boolean exported) {
        StringBuffer buffer = new StringBuffer();
        if (vector == null) {
            return buffer.toString();
        }
        boolean first = true;
        for (int i = 0; i < vector.size(); i++) {
            if (vector.get(i).isExported() != exported) {
                continue;
            }
            if (first) {
                buffer.append(vector.get(i).toString());
                first = false;
            } else {
                buffer.append(separator);
                buffer.append(vector.get(i).toString());
            }
        }
        return buffer.toString();
    }

    private String composeString(Vector<String> vector, String separator) {
        StringBuffer buffer = new StringBuffer();
        if (vector == null) {
            return buffer.toString();
        }
        for (int i = 0; i < vector.size(); i++) {
            if (i == 0) {
                buffer.append(vector.get(i).toString());
            } else {
                buffer.append(separator);
                buffer.append(vector.get(i).toString());
            }
        }
        return buffer.toString();
    }

    static private boolean existingJar(Vector<ImportedJar> vec, ImportedJar jar) {
        if (jar == null) {
            return false;
        }
        for (int i = 0; i < vec.size(); i++) {
            if (vec.get(i).getPath().equalsIgnoreCase(jar.getPath())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Gets paths of all imported jars (project level and workspace level) and jars of dependency projects.
     *
     * @return
     * @throws CoreException
     */
    static public Vector<ImportedJar> getCompileImports(IJavaProject jProject) throws CoreException {
        Vector<ImportedJar> vector = new Vector<ImportedJar>();
        IClasspathEntry[] entries = jProject.getRawClasspath();
        if (entries != null && entries.length > 0) {
            getCompileImportsRecusively(entries, jProject, vector, true);
        }
        return vector;
    }

    static private void getCompileImportsRecusively(IClasspathEntry[] entries, IJavaProject jProject,
            Vector<ImportedJar> imports, boolean isMainProject) throws CoreException {
        if (imports == null) {
            imports = new Vector<ImportedJar>();
        }
        // Workspace imports; if there aren't any specified, default to
        // using the runtime libraries.
        IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
        // String jarPathString;
        try {
            BlackBerryProperties properties = null;
            boolean needAddBBJar = false;
            IPath jarPath = null;
            ImportedJar importedJar = null;
            for (IClasspathEntry entry : entries) {
                switch (entry.getEntryKind()) {
                case IClasspathEntry.CPE_CONTAINER: {
                    // libraries
                    IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(),
                            jProject.getJavaProject());
                    if (container == null) {
                        continue;
                    }

                    IVMInstall containerVM;
                    if (!(container instanceof JREContainer)) {
                        // We need to verify the type of the container because the path of Maven container only has one
                        // segment and JavaRuntime.getVMInstall(IPath) return the default VM install if the entry path has one
                        // segment.
                        containerVM = null;
                    } else {
                        containerVM = JavaRuntime.getVMInstall(entry.getPath());
                    }

                    try {
                        if (containerVM != null) {
                            if (containerVM.getVMInstallType().getId().equals(BlackBerryVMInstallType.VM_ID)) {
                                if (isMainProject) {
                                    // Add jars to a list
                                    IClasspathEntry[] classpathEntries = container.getClasspathEntries();
                                    if (classpathEntries != null && classpathEntries.length > 0) {
                                        getCompileImportsRecusively(classpathEntries, jProject, imports, false);
                                    }
                                }
                            } else {
                                if (!jProject.getProject().hasNature(BlackBerryProjectCoreNature.NATURE_ID)) {
                                    needAddBBJar = true;
                                    continue;
                                }
                            }
                        } else {
                            // Add jars to a list
                            IClasspathEntry[] classpathEntries = container.getClasspathEntries();
                            if (classpathEntries != null && classpathEntries.length > 0) {
                                getCompileImportsRecusively(classpathEntries, jProject, imports, false);
                            }
                        }
                    } catch (CoreException e) {
                        _log.error(e.getMessage());
                        continue;
                    }
                    break;
                }
                case IClasspathEntry.CPE_LIBRARY: {
                    // imported jars
                    jarPath = PackageUtils.getAbsoluteEntryPath(entry);
                    // the jar path can be null if the jar file does not exist
                    if (jarPath == null) {
                        throw new CoreException(StatusFactory.createErrorStatus(
                                NLS.bind(Messages.PackagingManager_Entry_Not_Found_MSG, entry.getPath())));
                    }
                    if (jarPath.lastSegment().equals(IConstants.RIM_API_JAR) && needAddBBJar) {
                        needAddBBJar = false;
                    }

                    importedJar = null;
                    if (PackagingUtils.getPackagExportedJar()) {
                        if (entry.isExported()) {
                            if (isMainProject) {
                                // if the exported jar is not in the main project but a dependent project, the classes it
                                // contains are packaged into the dependent project jar. We don't add it to classpath.
                                importedJar = new ImportedJar(jarPath.toOSString(), true,
                                        getJarFileType(jarPath.toFile()));
                            }
                        } else {
                            importedJar = new ImportedJar(jarPath.toOSString(), false,
                                    getJarFileType(jarPath.toFile()));
                        }
                    } else {
                        importedJar = new ImportedJar(jarPath.toOSString(), false,
                                getJarFileType(jarPath.toFile()));
                    }
                    if (importedJar != null && !existingJar(imports, importedJar)) {
                        imports.add(importedJar);
                    }
                    break;
                }
                case IClasspathEntry.CPE_PROJECT: {
                    // dependency projects
                    IProject project = workspaceRoot.getProject(entry.getPath().toString());
                    IJavaProject javaProject = JavaCore.create(project);
                    try {
                        if (project.hasNature(BlackBerryProjectCoreNature.NATURE_ID)) {
                            properties = ContextManager.PLUGIN.getBBProperties(javaProject.getProject().getName(),
                                    false);
                            if (properties == null) {
                                _log.error("BlackBerry properties is null");
                                break;
                            }
                        } else {
                            properties = BlackBerryPropertiesFactory.createBlackBerryProperties(javaProject);
                        }
                    } catch (CoreException e) {
                        _log.error(e.getMessage());
                        continue;
                    }
                    if (PackagingManager.getProjectTypeID(properties._application.getType()) == Project.LIBRARY) {
                        IPath absoluteJarPath = PackagingUtils
                                .getAbsoluteStandardOutputFilePath(new BlackBerryProject(javaProject, properties));
                        File jarFile = new File(
                                absoluteJarPath.toOSString() + IConstants.DOT_MARK + IConstants.JAR_EXTENSION);
                        importedJar = new ImportedJar(jarFile.getAbsolutePath(), false, getJarFileType(jarFile));
                        if (!existingJar(imports, importedJar)) {
                            imports.add(importedJar);
                        }
                        IClasspathEntry[] subEntries = javaProject.getRawClasspath();
                        if (subEntries != null && subEntries.length > 0) {
                            getCompileImportsRecusively(subEntries, javaProject, imports, false);
                        }
                    }
                    break;
                }
                case IClasspathEntry.CPE_VARIABLE: {
                    // variables
                    String e = entry.getPath().toString();
                    int index = e.indexOf('/');
                    if (index == -1) {
                        index = e.indexOf('\\');
                    }
                    String variable = e;
                    IPath cpvar = JavaCore.getClasspathVariable(variable);
                    if (cpvar == null) {
                        String msg = NLS.bind(Messages.PackagingManager_Variable_Not_Defined_MSG, variable);
                        throw new CoreException(StatusFactory.createErrorStatus(msg));
                    }
                    if (cpvar.lastSegment().equals(IConstants.RIM_API_JAR) && needAddBBJar) {
                        needAddBBJar = false;
                    }
                    // TODO RAPC does not support a class folder. We may support it later on
                    if (cpvar.lastSegment().endsWith("." + IConstants.JAR_EXTENSION)) {
                        importedJar = new ImportedJar(cpvar.toOSString(), false, getJarFileType(cpvar.toFile()));
                        if (!existingJar(imports, importedJar)) {
                            imports.add(importedJar);
                        }
                    }
                    break;
                }
                }
            }
            if (needAddBBJar && isMainProject) {
                // insert the default BB jre lib if needed
                IVMInstall bbVM = VMUtils.getDefaultBBVM();
                if (bbVM != null) {
                    LibraryLocation[] libLocations = bbVM.getLibraryLocations();
                    if (libLocations != null) {
                        for (LibraryLocation location : libLocations) {
                            importedJar = new ImportedJar(location.getSystemLibraryPath().toOSString(), false,
                                    getJarFileType(location.getSystemLibraryPath().toFile()));
                            if (!existingJar(imports, importedJar)) {
                                imports.add(importedJar);
                            }
                        }
                    }
                }
            }
        } catch (JavaModelException e) {
            _log.error(e.getMessage());
        }
    }

    public static String quoteFile(String fileName) {
        return IConstants.DOUBLE_QUOTE + fileName + IConstants.DOUBLE_QUOTE;
    }

    public static int getProjectTypeID(String type) {
        if (type.trim().equalsIgnoreCase(BlackBerryProject.CLDC_APPLICATION)) {
            return Project.CLDC_APPLICATION;
        }
        if (type.trim().equalsIgnoreCase(BlackBerryProject.MIDLET)) {
            return Project.MIDLET;
        }
        if (type.trim().equalsIgnoreCase(BlackBerryProject.LIBRARY)) {
            return Project.LIBRARY;
        }
        return -1;
    }

    private String getRAPCPath() {
        String rapcPath = IConstants.EMPTY_STRING;
        try {
            IVMInstall vm = null;
            if (_bbProject.getProject().hasNature(BlackBerryProjectCoreNature.NATURE_ID)) {
                vm = JavaRuntime.getVMInstall(_bbProject);
            } else {
                // for java proejct, we use the default BB jre
                vm = VMUtils.getDefaultBBVM();
            }
            if (vm != null) {
                File vmLocation = vm.getInstallLocation();
                IPath vmPath = new Path(vmLocation.getPath());
                vmPath = vmPath.append("bin");
                if (OSUtils.isWindows()) {
                    vmPath = vmPath.append("rapc.exe");
                } else {
                    // Make sure preverify is in executable state
                    File f = null;
                    if ((f = new File(vmPath + File.separator + IConstants.PREVERIFY_FILE_NAME)).exists()) {
                        if (!f.canExecute()) {
                            f.setExecutable(true);
                        }
                    }
                    // invoke rapc.jar instead of rapc.exe
                    vmPath = vmPath.append("rapc.jar");
                }
                rapcPath = vmPath.toOSString();
            } else {
                throw ProblemFactory.create_VM_MISSING_exception(_bbProject.getElementName());
            }
        } catch (CoreException e) {
            _log.error("getRapcPath: " + e.getMessage());
        }
        return rapcPath;
    }

    private Vector<String> getCompileOptions() {
        Vector<String> options = new Vector<String>();
        BlackBerryProperties properties = _bbProject.getProperties();
        // TODO java home
        // get options from the compile section
        if (properties._compile.getCompressResources().booleanValue()) {
            options.add(COMPRESS_RESOURCE_OPTION);
        }
        if (properties._compile.getConvertImages().booleanValue()) {
            options.add(CONVERT_PNG_RAPC_OPTION);
        }
        if (!properties._compile.getCreateWarningForNoExportedRoutine().booleanValue()
                || !properties._application.getType().equals(BlackBerryProject.CLDC_APPLICATION)) {
            options.add(Project.NO_MAIN_RAPC_OPTION);
        }
        if (!properties._compile.getOutputCompilerMessages().booleanValue()) {
            options.add(Project.QUIET_RAPC_OPTION);
        }
        if (!StringUtils.isBlank(properties._compile.getAliasList())
                && properties._application.getType().equals(BlackBerryProject.LIBRARY)) {
            options.add(Project.ALIAS_RAPC_OPTION + properties._compile.getAliasList());
        }
        // add other options
        InternalPackagingUtils.addOtherOptions(options, properties);
        // add codename
        int projectType = getProjectTypeID(properties._application.getType());
        String outputFileName = PackagingUtils.getRelativeStandardOutputFilePath(_bbProject).toOSString();
        if (projectType == Project.LIBRARY) {
            options.addElement("library=" + outputFileName);
        } else {
            options.addElement("codename=" + outputFileName);
        }

        if (projectType == Project.MIDLET) {
            options.addElement("-midlet");
        }
        return options;
    }

    /**
     * Checks if a jar file is a MidletJar created by rapc.
     *
     * @param f
     * @return
     */
    static public int getJarFileType(File f) {
        int type = 0x0;
        if (!f.exists()) {
            return type;
        }
        java.util.jar.JarFile jar = null;
        try {
            jar = new java.util.jar.JarFile(f, false);
            java.util.jar.Manifest manifest = jar.getManifest();
            if (manifest != null) {
                java.util.jar.Attributes attributes = manifest.getMainAttributes();
                String profile = attributes.getValue("MicroEdition-Profile");
                if (profile != null) {
                    if ("MIDP-1.0".equals(profile) || "MIDP-2.0".equals(profile)) {
                        type = type | MIDLET_JAR;
                    }
                }
            }
            Enumeration<JarEntry> entries = jar.entries();
            JarEntry entry;
            String entryName;
            InputStream is = null;
            IClassFileReader classFileReader = null;
            // check the attribute of the class files in the jar file
            for (; entries.hasMoreElements();) {
                entry = entries.nextElement();
                entryName = entry.getName();
                if (entryName.endsWith(IConstants.CLASS_FILE_EXTENSION_WITH_DOT)) {
                    is = jar.getInputStream(entry);
                    classFileReader = ToolFactory.createDefaultClassFileReader(is, IClassFileReader.ALL);
                    if (isEvisceratedClass(classFileReader)) {
                        type = type | EVISCERATED_JAR;
                        break;
                    }
                }
            }
        } catch (IOException e) {
            _log.error(e.getMessage());
        } finally {
            try {
                if (jar != null) {
                    jar.close();
                }
            } catch (IOException e) {
                _log.error(e.getMessage());
            }
        }
        return type;
    }

    /**
     * Verify if the given <code>classFileReader</code> has code attributes.
     *
     * @param classFileReader
     * @return
     */
    static private boolean isEvisceratedClass(IClassFileReader classFileReader) {
        // ignore interface classes
        if (!classFileReader.isClass()) {
            return false;
        }
        IMethodInfo[] methodInfos = classFileReader.getMethodInfos();
        if (methodInfos == null) {
            return false;
        }
        for (int i = 0; i < methodInfos.length; i++) {
            // Ignore <init>, <clinit> and abstract methods
            if ("<init>".equalsIgnoreCase(String.valueOf(methodInfos[i].getName())) || methodInfos[i].isClinit()
                    || (methodInfos[i].getAccessFlags() & IModifierConstants.ACC_ABSTRACT) != 0) {
                continue;
            }
            if (methodInfos[i].getCodeAttribute() == null) {
                return true;
            }
        }
        return false;
    }

    public static void reportProblem(IResource resource, int line, int start, int end, String msg, int level) {
        reportProblem(resource, IRIMMarker.PACKAGING_PROBLEM, line, start, end, msg, level);
    }

    public static void reportProblem(IResource resource, String type, int line, int start, int end, String msg,
            int level) {

        try {
            IMarker m = resource.createMarker(type);
            m.setAttribute(IMarker.LINE_NUMBER, line);
            m.setAttribute(IMarker.MESSAGE, msg);
            m.setAttribute(IMarker.CHAR_START, start);
            m.setAttribute(IMarker.CHAR_END, end);
            switch (level) {
            case Problem.ERROR:
                m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
                m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
                break;
            case Problem.WARNING:
                m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
                m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
                break;
            case Problem.INFO:
            default:
                m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW);
                m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
                break;
            }
        } catch (CoreException e) {
            _log.error(e.getMessage(), e);
        }
    }

    private Vector<String> getProtectionOptions(boolean forMakefile) {
        Vector<String> v = new Vector<String>();
        Hashtable<String, String> classProtection, packageProtection;
        classProtection = _bbProject.getProperties()._hiddenProperties.getClassProtection();
        packageProtection = _bbProject.getProperties()._hiddenProperties.getPackageProtection();
        Object keys[] = packageProtection.keySet().toArray();
        for (int i = 0; i < keys.length; ++i) {
            v.addElement("package:" + Util.doubleDollar(keys[i].toString()) + "="
                    + stripPath(packageProtection.get(keys[i])));
        }
        keys = classProtection.keySet().toArray();
        for (int i = 0; i < keys.length; ++i) {
            if (forMakefile) {
                v.addElement("class:" + Util.doubleDollar(keys[i].toString()) + "="
                        + stripPath(classProtection.get(keys[i])));
            } else {
                // When we are not creating a makefile don't add double $$ to rapc cmd line
                v.addElement("class:" + keys[i].toString() + "=" + stripPath(classProtection.get(keys[i])));
            }
        }
        return v;
    }

    private String stripPath(Object f) {
        return new File(f.toString()).getName();
    }

    private class SourcerootVisitor implements IResourceVisitor {
        Set<String> _resourceRootSet;

        public SourcerootVisitor() {
            _resourceRootSet = new HashSet<String>();
        }

        public boolean visit(IResource resource) throws CoreException {
            if (!(resource instanceof IFile)) {
                return shouldBeSourceRoot(resource);
            }
            String extension = resource.getFileExtension();
            if (extension != null) {
                if (extension.equalsIgnoreCase(IConstants.JAVA_EXTENSION)) {
                    String sourceRoot = calculateSourceRoot(resource.getLocation().toFile());
                    if (sourceRoot != null) {
                        _resourceRootSet.add(sourceRoot);
                    }
                }
            }
            return false;
        }

        private String calculateSourceRoot(File javaFile) {
            String packagename = PackageUtils.getJavaFilePackageID(javaFile);
            packagename = packagename.replace(IConstants.DOT_CHAR, IConstants.BACK_SLASH_CHAR);
            IPath absolutePath = new Path(javaFile.getPath());
            IPath packageAndFileNamPath = null;
            if (packagename.trim().equals(IConstants.EMPTY_STRING)) {
                packageAndFileNamPath = new Path(javaFile.getName());
            } else {
                packageAndFileNamPath = new Path(packagename);
                packageAndFileNamPath = packageAndFileNamPath.append(new Path(javaFile.getName()));
            }
            int differentSegNumber = absolutePath.segmentCount() - packageAndFileNamPath.segmentCount();
            if (differentSegNumber >= 0) {
                IPath actualPackageAndFileNamPath = absolutePath.removeFirstSegments(differentSegNumber);
                if (actualPackageAndFileNamPath
                        .matchingFirstSegments(packageAndFileNamPath) == packageAndFileNamPath.segmentCount()) {
                    return absolutePath.removeLastSegments(packageAndFileNamPath.segmentCount()).toOSString();
                }
            }
            _log.debug("Java file [" + javaFile.getPath() + "] is not in the right package."); //$NON-NLS-1$ //$NON-NLS-2$
            return null;
        }

        public Vector<String> getSourceRoots(IProject proj) {
            Vector<String> roots = new Vector<String>();
            roots.addAll(_resourceRootSet);
            try {
                if (proj.hasNature(JavaCore.NATURE_ID)) {
                    IJavaProject jproj = JavaCore.create(proj);
                    IClasspathEntry[] clpentrs = jproj.getResolvedClasspath(true);
                    IWorkspaceRoot workspaceRoot = proj.getWorkspace().getRoot();
                    for (IClasspathEntry clpentry : clpentrs) {
                        if ((clpentry.getEntryKind() == IClasspathEntry.CPE_SOURCE)
                                && !ImportUtils.getImportPref(ResourceBuilder.LOCALE_INTERFACES_FOLDER_NAME)
                                        .equals(clpentry.getPath().lastSegment())) {
                            // Try to resolve the source container
                            IResource resource = workspaceRoot.findMember(clpentry.getPath());
                            boolean found = false;
                            if (resource instanceof IContainer) {
                                for (String resRoot : _resourceRootSet) {
                                    if (resource.getLocation().equals(new Path(resRoot))) {
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found) {
                                    roots.add(resource.getLocation().toOSString());
                                }
                            }
                        }
                    }
                }
            } catch (CoreException e) {
                _log.error(e);
            }
            return roots;
        }

        private boolean shouldBeSourceRoot(IResource resource) {
            if (resource instanceof IProject) {
                return true;
            }
            if (PackageUtils.isUnderSrcFolder(resource)) {
                return true;
            }
            return false;
        }
    }

    /**
     * This class is a handler for executing reading an InputStream of a process in a StringBuffer
     *
     *
     */
    static public class InputStreamHandler extends Thread {
        private InputStream _stream;
        private MessageConsoleStream _consoleStream;
        private IProject _project;

        /**
         * Regular expression to match an error line pattern. These lines are usually in the form file:line:msg
         */
        private static final Pattern javaErrorStartPattern = Pattern.compile(".*\\.java:\\d+:\\s\\S.*");
        private static final Pattern rapcErrorStartPattern = Pattern.compile("[Ee]rror.*");
        private static final Pattern rapcErrorStartPattern2 = Pattern.compile(".*[Ee]rror!.*");
        /**
         * Regular expression to match a symbol error. This typically looks like symbol : <missing symbol>
         */
        private static final Pattern errorSymbolPattern = Pattern.compile("^symbol\\s*:\\s\\S.*");

        private static final Pattern errorLocationPattern = Pattern.compile("^location\\s*:\\s\\S.*$");

        private static final Pattern errorSourcePattern = Pattern.compile("^\\s+\\S.*$");

        private static final Pattern errorSourceLocationPattern = Pattern.compile("^\\s*\\^\\s*$");

        /**
         * Regular expression to match a warning line pattern. These lines are usually in the form file:line: Warning!: msg
         */
        private static final Pattern javaWarningStartPattern = Pattern.compile(".*\\.java:\\d+:\\s[Ww]arning.*");

        private static final Pattern errorLineNumberPattern = Pattern.compile(":\\d+:");

        private static final Pattern rapcWarningStartPattern = Pattern.compile("[Ww]arning.*");
        private static final Pattern rapcWarningStartPattern2 = Pattern.compile(".*[Ww]arning!.*");

        /**
         * @param captureBuffer
         * @param stream
         */
        public InputStreamHandler(IProject project, MessageConsoleStream consoleOutputStream,
                InputStream inputStream) {
            _stream = inputStream;
            _consoleStream = consoleOutputStream;
            _project = project;
        }

        /*
         * (non-Javadoc)
         *
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try {
                /*
                 * List of queued problems to submit. This is a stack, because it is useful to get the problem just added to add
                 * additional info to it.
                 */
                Stack<Problem> problems = new Stack<Problem>();
                InputStreamReader isr = new InputStreamReader(_stream);
                BufferedReader br = new BufferedReader(isr);
                while (true) {
                    String line = br.readLine();
                    if (line == null) {
                        break;
                    }
                    try {
                        parse(line, problems);
                    } catch (RuntimeException e) {
                        _log.error(e.getMessage(), e);
                    }
                    _consoleStream.println(line);
                }
                _stream.close();
                reportProblems(problems);
            } catch (IOException ioe) {
                _log.error(ioe);
            }
        }

        private void reportProblems(Stack<Problem> problems) {
            for (Problem problem : problems) {
                reportProblem(problem);
            }
            problems.clear();
        }

        private void reportProblem(Problem problem) {
            _log.trace("reporting problem " + problem.file + " at " + problem.line + " about " + problem.msg);
            IResource resource = null;
            if (problem.file != null) {
                IPath problemFileLocation = new Path(problem.file);
                resource = ProjectUtils.getResource(_project, problemFileLocation.toFile());
            } else {
                resource = _project;
            }

            if (resource != null) {
                PackagingManager.reportProblem(resource, problem.line, problem.start, problem.end, problem.msg,
                        problem.level);
            }
        }

        /**
         * Takes a string and delegates it based on the pattern of it.
         *
         * @param s
         */
        protected void parse(String s, Stack<Problem> problems) {
            if (javaWarningStartPattern.matcher(s).matches()) {
                parseJavaWarningStart(s, problems);
            } else if (rapcWarningStartPattern.matcher(s).matches()
                    || rapcWarningStartPattern2.matcher(s).matches()) {
                parseRAPCWarningStart(s, problems);
            } else if (javaErrorStartPattern.matcher(s).matches()) {
                parseJavaErrorString(s, problems);
            } else if (rapcErrorStartPattern.matcher(s).matches() || rapcErrorStartPattern2.matcher(s).matches()) {
                parseRAPCErrorStart(s, problems);
            }
        }

        /**
         * Parses an error generated by RAPC.
         */
        private void parseRAPCErrorStart(String s, Stack<Problem> problems) {
            // For example:
            // Error!: Error: java compiler failed:
            // C:\Java\jdk1.6.0_01\bin\javac.exe -source 1.3
            // -target 1.1 -g -O -d C:\DOCUME~1\zqiu\LOCALS~1\Temp\r ...

            Matcher m = rapcErrorStartPattern.matcher(s);
            if (!m.find()) {
                m = rapcErrorStartPattern2.matcher(s);
                if (!m.find()) {
                    _log.error("Failed to parse RAPC error message: " + s);
                    return;
                }
            }

            Problem problem = new Problem();
            problem.msg = s;
            problem.level = Problem.ERROR;

            problems.add(problem);
        }

        /**
         * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more
         * information about the specific error.
         */
        private void parseRAPCWarningStart(String s, Stack<Problem> problems) {
            // For example:
            // Warning!: Reference to class: net.rim.device.api.io.File requires
            // signing
            // with key: RIM Runtime API

            Matcher m = rapcWarningStartPattern.matcher(s);
            if (!m.find()) {
                m = rapcWarningStartPattern2.matcher(s);
                if (!m.find()) {
                    _log.error("Failed to parse RAPC warning message: " + s);
                    return;
                }
            }

            Problem problem = new Problem();
            problem.msg = s;
            problem.level = Problem.WARNING;

            problems.add(problem);
        }

        /**
         * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more
         * information about the specific error.
         */
        private void parseJavaWarningStart(String s, Stack<Problem> problems) {
            // For example:
            // C:\samples\com\rim\samples\device\tictactoe\TTTService.java:10:
            // package net.rim.blackberry.api.blackberrymessenger does not exist

            int firstColon, secondColon;

            Matcher m = errorLineNumberPattern.matcher(s);
            if (m.find()) {
                firstColon = m.start();
                secondColon = m.end() - 1;
            } else {
                _log.warn("Faling back to old way of doing things...");
                secondColon = s.lastIndexOf(':');
                firstColon = s.lastIndexOf(':', secondColon - 1);
            }

            Problem problem = new Problem();
            problem.file = s.substring(0, firstColon).trim();
            problem.line = Integer.parseInt(s.substring(firstColon + 1, secondColon));
            problem.msg = s.substring(secondColon + 1).trim();
            problem.level = Problem.WARNING;

            problems.add(problem);
        }

        /* Keep track of state for parse() automaton */
        private int parseState;

        /**
         * Takes a string and delegates it based on the pattern of it.
         *
         * @param s
         */
        private void parseJavaErrorString(String s, Stack<Problem> problems) {
            _log.trace("Parsing " + s);
            if (javaErrorStartPattern.matcher(s).matches()) {
                // Some warnings appear on stderr for some reason...
                // For example:
                // C:\samples\com\rim\samples\device\syncdemo\SyncDemo.java:288:
                // warning: [deprecation] getScreenWidth() in
                // net.rim.device.api.ui.Graphics has been deprecated
                if (javaWarningStartPattern.matcher(s).matches()) {
                    parseJavaWarningStart(s, problems);
                } else {
                    parseErrorStart(s, problems);
                }
                parseState = 0;
            } else if ((parseState == 0) && errorSymbolPattern.matcher(s).matches()) {
                parseErrorSymbol(s, problems);
                parseState = 1;
            } else if ((parseState == 1) && errorLocationPattern.matcher(s).matches()) {
                // Optional "location:*" line. Only occurs for stuff in inner
                // classes or methods.
            } else if ((parseState == 1) && errorSourcePattern.matcher(s).matches()) {
                parseErrorSource(s, problems);
                parseState = 2;
            } else if ((parseState == 2) && errorSourceLocationPattern.matcher(s).matches()) {
                parseErrorLocation(s, problems);
                parseState = 3;
            }
        }

        /**
         * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more
         * information about the specific error.
         */
        private void parseErrorStart(String s, Stack<Problem> problems) {
            // For example:
            // C:\samples\com\rim\samples\device\tictactoe\TTTService.java:10:
            // package net.rim.blackberry.api.blackberrymessenger does not exist

            int firstColon, secondColon;

            Matcher m = errorLineNumberPattern.matcher(s);
            if (m.find()) {
                firstColon = m.start();
                secondColon = m.end() - 1;
            } else {
                _log.warn("Faling back to old way of doing things...");
                secondColon = s.lastIndexOf(':');
                firstColon = s.lastIndexOf(':', secondColon - 1);
            }

            Problem problem = new Problem();
            problem.file = s.substring(0, firstColon).trim();
            problem.line = Integer.parseInt(s.substring(firstColon + 1, secondColon));
            problem.msg = s.substring(secondColon + 1).trim();
            problem.level = Problem.ERROR;

            problems.add(problem);
        }

        /**
         * This parses the line associated with a "cannot find symbol" error. Following such an error, rapc will output the undef
         * symbol.
         *
         * @param s
         */
        private void parseErrorSymbol(String s, Stack<Problem> problems) {
            // For example:
            // C:\samples\com\rim\samples\device\tictactoe\TTTRequestListener.java
            // :28: cannot find symbol
            // symbol : class Session

            try {
                int colon = s.indexOf(":");
                Problem problem = problems.peek();
                if ((problem.msg != null) && problem.msg.equals("cannot find symbol")) {
                    problem.msg += " " + s.substring(colon).trim();
                }
            } catch (EmptyStackException e) {
                _log.error(e.getMessage(), e);
            }
        }

        private void parseErrorLocation(String s, Stack<Problem> problems) {
            try {
                Problem problem = problems.peek();
                if (problem != null) {
                    problem.start = s.indexOf('^');

                    String source = problem.source;
                    int sourceLength = source.length();
                    for (int i = problem.start; i < sourceLength; i++) {
                        char c = source.charAt(i);

                        // All valid characters that can go into java
                        // identifiers.
                        if (((c > 96) && (c < 123)) || ((c > 64) && (c < 91)) || ((c > 47) && (c < 58)) || (c == 36)
                                || (c == 95)) {
                            // Do Nothing
                        } else {
                            problem.end = i + 1;
                            break;
                        }
                    }
                }
            } catch (EmptyStackException e) {
                _log.error(e.getMessage(), e);
            }
        }

        private void parseErrorSource(String s, Stack<Problem> problems) {
            try {
                Problem problem = problems.peek();
                if (problem != null) {
                    problem.source = s;
                }
            } catch (EmptyStackException e) {
                _log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * Problem declaration
     */
    static public class Problem {
        public static final int ERROR = 1;
        public static final int WARNING = 2;
        public static final int INFO = 4;

        String file;
        int line;
        String msg;
        int level;

        String source;
        int start = -1;
        int end = -1;

        @Override
        public String toString() {
            return "Problem[file=" + file + ";line=" + line + ";msg=" + msg + ";level=" + level + ";]";
        }

    }

    /**
     * ImportedJar class is used to differentiate if a jar is exported or not.
     *
     *
     */
    public static class ImportedJar {
        String _path;
        boolean _exported;
        int _type;

        public ImportedJar(String path, boolean exported, int jarType) {
            _path = path;
            _exported = exported;
            _type = jarType;
        }

        public boolean isExported() {
            return _exported;
        }

        public void setExported(boolean exported) {
            _exported = exported;
        }

        public String getPath() {
            return _path;
        }

        public void setPath(String path) {
            _path = path;
        }

        public int getType() {
            return _type;
        }

        public void setType(int type) {
            _type = type;
        }

        public String toString() {
            return _path;
        }

        public boolean isMidletJar() {
            return (_type & MIDLET_JAR) > 0;
        }
    }
}