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

Java tutorial

Introduction

Here is the source code for net.rim.ejde.internal.packaging.PackagingJob.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.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

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.signing.SignatureToolLaunchAction;
import net.rim.ejde.internal.ui.consoles.PackagingConsole;
import net.rim.ejde.internal.util.ImportUtils;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.PackagingUtils;
import net.rim.ejde.internal.util.ProjectUtils;
import net.rim.ejde.internal.util.ResourceBuilderUtils;
import net.rim.ejde.internal.util.StatusFactory;
import net.rim.ejde.internal.validation.DiagnosticFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.internal.resources.ResourceException;
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.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.osgi.util.NLS;

/**
 * This class represents the job for packaging BlackBerry projects with or without deployment to the simulator. This job should be
 * run after eclipse building is done. Please use {@link PackagingJobWrapper} to run the packaging job.
 *
 */
public abstract class PackagingJob implements IWorkspaceRunnable {
    static private final Logger _log = Logger.getLogger(PackagingJob.class);
    final static public QualifiedName BUILT_BY_JAVA_BUILDER_FLAG_QUALIFIED_NAME = new QualifiedName(
            ContextManager.PLUGIN_ID, "BuiltByEclipseBuilders"); //$NON-NLS-1$
    final static private String TRUE_STRING = "true"; //$NON-NLS-1$
    final static private String FALSE_STRING = "false"; //$NON-NLS-1$
    private Set<BlackBerryProject> _projects;
    private int _signingFlag;
    // sign flag
    // always sign
    final static public int SIGN_FORCE = 0;
    // sign only if packaging is needed
    final static public int SIGN_IF_NECESSARY = 1;
    // never sign
    final static public int SIGN_NO = 2;
    // sign only if protected APIs are used
    final static public int SIGN_IF_PROTECTED_API_USED = 3;

    /**
     * Constructs a PackagingJob instance.
     *
     * @param projects
     *            projects need to be packaged.
     */
    public PackagingJob(Set<BlackBerryProject> projects) {
        _projects = projects;
        _signingFlag = SIGN_NO;
    }

    /**
     * Constructs a PackagingJob instance.
     *
     * @param projects
     * @param signingFlag
     */
    public PackagingJob(Set<BlackBerryProject> projects, int signingFlag) {
        _projects = projects;
        _signingFlag = signingFlag;
    }

    /**
     * Mark the given <code>project</code> as need to be built.
     *
     * @param project
     * @param needBuild
     *            <code>true</code> mark the given <code>project</code> as need build, otherwise, mark the given
     *            <code>project</code> as not need build.
     */
    static synchronized public void setBuiltByJavaBuilders(IProject project, boolean needBuild) {
        try {
            _log.trace("Project " + project.getName() + " is marked as" //$NON-NLS-1$ //$NON-NLS-2$
                    + (needBuild ? " need RAPC." : " not need RAPC.")); //$NON-NLS-1$ //$NON-NLS-2$
            String newBuildFlag = needBuild ? TRUE_STRING : FALSE_STRING;
            String oldBuildFlag = project.getPersistentProperty(BUILT_BY_JAVA_BUILDER_FLAG_QUALIFIED_NAME);
            if ((oldBuildFlag == null) || !oldBuildFlag.equals(newBuildFlag)) {
                project.setPersistentProperty(BUILT_BY_JAVA_BUILDER_FLAG_QUALIFIED_NAME, newBuildFlag);
            }
        } catch (CoreException e) {
            _log.error(e);
        }
    }

    /**
     * Check if the given <code>project</code> needs to be built.
     *
     * @param project
     * @return
     */
    static synchronized private boolean builtByJavaBuilder(IProject project) {
        try {
            String value = project.getProject().getPersistentProperty(BUILT_BY_JAVA_BUILDER_FLAG_QUALIFIED_NAME);
            if ((value == null) || value.equals(TRUE_STRING)) {
                return true;
            }
        } catch (CoreException e) {
            _log.error(e);
            return true;
        }
        return false;
    }

    /**
     * Gets projects which need to be packaged;
     *
     * @return
     */
    public Set<BlackBerryProject> getProjects() {
        return _projects;
    }

    @Override
    public void run(IProgressMonitor monitor) throws CoreException {
        // remove the code signing error
        ResourceBuilderUtils.cleanProblemMarkers(ResourcesPlugin.getWorkspace().getRoot(),
                new String[] { IRIMMarker.SIGNATURE_TOOL_PROBLEM_MARKER }, IResource.DEPTH_ONE);
        // open the packaging console
        PackagingConsole.getInstance().activate();
        LinkedHashSet<BlackBerryProject> projectSet = ProjectUtils.getProjectsByBuildOrder(_projects);
        monitor.beginTask(IConstants.EMPTY_STRING, projectSet.size() * 10);
        monitor.subTask(Messages.PackagingJob_Name);
        boolean needSign = false;
        // collect projects which need to be signed
        LinkedHashSet<BlackBerryProject> projectsNeedSigning = new LinkedHashSet<BlackBerryProject>();
        // collect projects whose dependent projects need to be signed
        LinkedHashSet<BlackBerryProject> projectsDependencyNeedSigning = new LinkedHashSet<BlackBerryProject>();
        // collect projects which are packaged successfully
        LinkedHashSet<BlackBerryProject> succesfullyPackagedProjects = new LinkedHashSet<BlackBerryProject>();
        for (BlackBerryProject bbProject : projectSet) {
            // 1. run java build on the project
            if (!isBuildAutomaticallyOn()) {
                try {
                    bbProject.getProject().build(IncrementalProjectBuilder.AUTO_BUILD,
                            new SubProgressMonitor(monitor, 1));
                } catch (CoreException e) {
                    _log.error(e);
                }
            }
            monitor.worked(3);
            // 2. package the project
            if (!needPackaging(bbProject)) {
                if (needGenerateALXFile(bbProject)) {
                    PackagingManager.generateALXForProject(bbProject);
                }
            } else {
                // remove the package problems
                ResourceBuilderUtils.cleanProblemMarkers(bbProject.getProject(),
                        new String[] { IRIMMarker.PACKAGING_PROBLEM }, IResource.DEPTH_INFINITE);
                try {
                    PackagingManager.packageProject(bbProject);
                    if (!needSign) {
                        needSign = true;
                    }
                } catch (CoreException e) {
                    _log.error(e.getMessage());
                    try {
                        ResourceBuilderUtils.createProblemMarker(
                                e.getStatus().getCode() == DiagnosticFactory.CREATE_FOLDER_ERR_ID
                                        ? bbProject.getMetaFileHandler()
                                        : bbProject.getProject(),
                                IRIMMarker.PACKAGING_PROBLEM, e.getMessage(), -1, IMarker.SEVERITY_ERROR);
                    } catch (Exception e1) {
                        _log.error(e1.getMessage());
                    }
                }
                PackagingJob.setBuiltByJavaBuilders(bbProject.getProject(), false);
            }
            monitor.worked(4);
            // 3. run post-build command
            runPostBuild(bbProject);
            monitor.worked(1);
            // 4. check if the project needs to be signed or not
            if (!hasPackagingProblems(bbProject.getProject())) {
                succesfullyPackagedProjects.add(bbProject);
                if (PackagingUtils.isSigningNeeded(bbProject)) {
                    projectsNeedSigning.add(bbProject);
                } else {
                    if (PackagingUtils.isSigningNeededForDependency(bbProject)) {
                        projectsDependencyNeedSigning.add(bbProject);
                    } else {
                        // if a project and its dependent projects do not need to be signed, copy the cod files to the web folder
                        // copy the cod files of dependency projects to the deployment folders
                        copyDependencyDeploymentFiles(bbProject);
                        // copy files from "Standard" to "Web"
                        copyToWebDeploymentFolder(bbProject);
                    }
                }
            }
            monitor.worked(2);
            if (monitor.isCanceled()) {
                monitor.done();
                return;
            }
        }
        // Code signing
        switch (_signingFlag) {
        case SIGN_FORCE: {
            if (!succesfullyPackagedProjects.isEmpty()) {
                signCodFile(succesfullyPackagedProjects, monitor);
            }
            break;
        }
        case SIGN_IF_PROTECTED_API_USED: {
            if (!projectsNeedSigning.isEmpty()) {
                signCodFile(projectsNeedSigning, monitor);
                for (BlackBerryProject project : projectsDependencyNeedSigning) {
                    // copy the cod files of dependency projects to the deployment folders
                    copyDependencyDeploymentFiles(project);
                    // copy files from "Standard" to "Web"
                    copyToWebDeploymentFolder(project);
                }
            }
            break;
        }
        case SIGN_IF_NECESSARY: {
            if (needSign) {
                if (!projectsNeedSigning.isEmpty()) {
                    signCodFile(projectsNeedSigning, monitor);
                    for (BlackBerryProject project : projectsDependencyNeedSigning) {
                        // copy the cod files of dependency projects to the deployment folders
                        copyDependencyDeploymentFiles(project);
                        // copy files from "Standard" to "Web"
                        copyToWebDeploymentFolder(project);
                    }
                }
            }
            break;
        }
        }
        monitor.done();
        return;
    }

    abstract protected void runPostBuild(BlackBerryProject properties);

    private void signCodFile(Set<BlackBerryProject> projectSet, IProgressMonitor monitor) throws CoreException {
        boolean successful = SignatureToolLaunchAction.signCodFiles(projectSet, monitor);
        if (successful) {
            for (BlackBerryProject bbProject : projectSet) {
                // copy the cod files of dependency projects to the deployment folders
                copyDependencyDeploymentFiles(bbProject);
                // copy files from "Standard" to "Web"
                copyToWebDeploymentFolder(bbProject);
            }
        }
    }

    /**
     * Copies the deployment files of the dependent projects to the corresponding deployment folders.
     *
     * @throws CoreException
     */
    private void copyDependencyDeploymentFiles(BlackBerryProject bbProject) throws CoreException {
        IPath standardSrcFolderPath, standardDstFolderPath;
        String outputFileName;
        IPath absoluteStandardSrcFolderPath, absoluteStandardDstFolderPath;
        for (BlackBerryProject dependentProj : ProjectUtils.getAllReferencedProjects(bbProject)) {
            // 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());
        }
    }

    private void copyToWebDeploymentFolder(BlackBerryProject bbProject) throws CoreException {
        String outputRootFolder = bbProject.getProperties()._packaging.getOutputFolder();
        IPath outputRootFolderPath = new Path(outputRootFolder);
        IPath standardOutputFolderPath = outputRootFolderPath
                .append(PackagingUtils.getStandardDeploymentFolderName());
        IPath webOutputFolderPath = outputRootFolderPath.append(PackagingUtils.getWebDeploymentFolderName());
        IFolder srcFolder = bbProject.getProject().getFolder(standardOutputFolderPath);
        srcFolder.accept(new CopyResourceVistor(bbProject, standardOutputFolderPath, webOutputFolderPath));
        // Refresh to show new resources
        IResource outputFolder = bbProject.getProject().findMember(webOutputFolderPath);
        outputFolder.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
    }

    class CopyResourceVistor implements IResourceVisitor {
        BlackBerryProject _bbProject;
        IPath _srcRootPath;
        IPath _destRootPath;
        IFolder _srcRootFolder;
        IFolder _destRootFolder;
        IProject _project;

        public CopyResourceVistor(BlackBerryProject bbProject, IPath srcRootPath, IPath destRootPath) {
            _bbProject = bbProject;
            _project = _bbProject.getProject();
            _srcRootPath = srcRootPath;
            _destRootPath = destRootPath;
            _srcRootFolder = _project.getFolder(_srcRootPath);
            _destRootFolder = _project.getFolder(_destRootPath);

        }

        @Override
        public boolean visit(IResource resource) throws CoreException {
            if (resource instanceof IFolder) {
                if (!resource.equals(_srcRootFolder)) {
                    IPath subPath = resource.getProjectRelativePath()
                            .removeFirstSegments(_srcRootPath.segmentCount());
                    IPath destPath = _destRootPath.append(subPath);
                    folderCopy(_bbProject, resource.getProjectRelativePath(), destPath);
                } else {
                    return true;
                }
            }
            return false;
        }

    }

    /**
     * Copy files form the <code>srcFolderRelativePath</code> to the <code>destFolderRelativePath</code> in project
     * <code>bbProject</code>. If there is any cod file, un-zip it if it contains any sibling cod files and then copy the sibling
     * files to the <code>destFolder</code> .
     *
     * @param bbProject
     * @param srcFolderRelativePath
     * @param destFolderRelativePath
     * @throws CoreException
     */
    private void folderCopy(BlackBerryProject bbProject, IPath srcFolderRelativePath, IPath destFolderRelativePath)
            throws CoreException {
        try {
            ImportUtils.createFolders(bbProject.getProject(), destFolderRelativePath, 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, destFolderRelativePath),
                    e);
        }
        IPath srcFolderPath = bbProject.getProject().getLocation().append(srcFolderRelativePath);
        IPath destFolderPath = bbProject.getProject().getLocation().append(destFolderRelativePath);
        // handle the cod files
        File[] codFiles = srcFolderPath.toFile().listFiles(new CodFileFilter());
        if (codFiles == null) {
            return;
        }
        _log.trace("Project " + bbProject.getElementName() + " folder copy: " + srcFolderRelativePath + " --> "
                + destFolderRelativePath);
        for (int i = 0; i < codFiles.length; i++) {
            copySiblingCod(new Path(codFiles[i].getAbsolutePath()), destFolderPath);
        }
        // IPath codFilePath = standardOutputFolderPath.append( bbProject.getProperties()._packaging.getOutputFileName()
        // + IConstants.COD_FILE_EXTENSION_WITH_DOT );
        // copy other files to the web deployment folder
        File[] files = srcFolderPath.toFile()
                .listFiles(new DeploymentFileNameFilter(IConstants.EMPTY_STRING, true));
        IPath destinationFilePath;
        String fileName;
        for (File file : files) {
            fileName = file.getName();
            destinationFilePath = destFolderPath.append(fileName);
            DeploymentHelper.executeCopy(file, destinationFilePath.toFile());
        }

    }

    class FolderFilter implements FileFilter {

        @Override
        public boolean accept(File pathname) {
            if (pathname.isDirectory() || pathname.exists()) {
                return true;
            }
            return false;
        }

    }

    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 (!StringUtils.isBlank(_outputFileName) && !name.startsWith(_outputFileName)) {
                return false;
            }
            if (_excludeCodFile) {
                if (!name.endsWith(IConstants.COD_FILE_EXTENSION_WITH_DOT)) {
                    return true;
                }
            } else {
                return true;
            }
            return false;
        }
    }

    class CodFileFilter implements FilenameFilter {

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

    /**
     * If the cod file represented by the given <code>codFilePath</code> contains sibling cod file, un-zip it and copy all sibling
     * cod files to the <code>destinationFolderPath</code>. If the cod file is a single cod file, just copy it to the
     * <code>destinationFolderPath</code>.
     *
     * @param codFilePath
     * @param destinationFolderPath
     * @throws CoreException
     */
    private void copySiblingCod(IPath codFilePath, IPath destinationFolderPath) throws CoreException {
        boolean hasSiblingCod = false;
        File codFile = codFilePath.toFile();
        try {
            JarFile zipFile = new JarFile(codFile);
            Enumeration<JarEntry> entries = zipFile.entries();
            if (entries.hasMoreElements()) {
                hasSiblingCod = true;
                JarEntry entry;
                for (; entries.hasMoreElements();) {
                    entry = entries.nextElement();
                    if (entry.isDirectory()) {
                        // this should not happen
                        continue;
                    }
                    InputStream is = zipFile.getInputStream(entry);
                    File outputFile = destinationFolderPath.append(entry.getName()).toFile();
                    PackagingManager.copyInputStream(is,
                            new BufferedOutputStream(new FileOutputStream(outputFile)));
                }
            } else {
                hasSiblingCod = false;
            }
        } catch (IOException e) {
            if (codFile.exists()) {
                // if the cod file does not contain any sibling file, we get IOException
                hasSiblingCod = false;
            } else {
                _log.error(e);
            }
        } finally {
            if (!hasSiblingCod) {
                // if the cod file is a single cod file, copy it to the destination
                DeploymentHelper.executeCopy(codFile, destinationFolderPath.append(codFile.getName()).toFile());
            }
        }
    }

    private boolean isBuildAutomaticallyOn() {
        return ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding();
    }

    private boolean needPackaging(BlackBerryProject bbproj) throws CoreException {
        // check if the project has any critical problem
        if (ProjectUtils.hasCriticalProblems(bbproj.getProject())) {
            return false;
        }
        List<BlackBerryProject> dependencyPrjoects = ProjectUtils.getAllReferencedProjects(bbproj);
        // check if the project's dependency projects have any critical problem, it does not make sense to package a project while
        // its dependency projects can not be packaged.
        if (hasProblemOnDependency(dependencyPrjoects)) {
            return false;
        }
        // check if the project has any packaging problem
        if (hasPackagingProblems(bbproj.getProject())) {
            return true;
        }
        // check if the project has been built by the java builder
        if (PackagingJob.builtByJavaBuilder(bbproj.getProject())) {
            return true;
        }
        // check if the project has been updated
        if (hasBeenUpdated(bbproj)) {
            return true;
        }
        // check if the project's dependency projects have been updated
        if (hasBeenUpdated(bbproj, dependencyPrjoects)) {
            return true;
        }
        return false;
    }

    private boolean needGenerateALXFile(BlackBerryProject project) {
        BlackBerryProperties properties = project.getProperties();
        if (!properties._packaging.getGenerateALXFile().booleanValue()) {
            return false;
        }
        String filename = properties._packaging.getOutputFileName() + IConstants.ALX_FILE_EXTENSION_WITH_DOT;
        IPath alxFilePath = new Path(
                PackagingUtils.getRelativeAlxFileOutputFolder(project) + IPath.SEPARATOR + filename);
        IResource alxIFile = project.getProject().findMember(alxFilePath);
        return (alxIFile == null) || (!alxIFile.exists());
    }

    /**
     * Checks if any of the BlackBerry project in the given <code>bbProjects</code> has been update after the last time the
     * <code>mainProject</code> was packaged.
     *
     * @param mainProject
     * @param bbProjects
     * @return
     */
    private boolean hasBeenUpdated(BlackBerryProject mainProject, List<BlackBerryProject> bbProjects) {
        // we only check the cod file in the standard output folder
        IPath refFilePath = mainProject.getProject().getLocation()
                .append(PackagingUtils.getRelativeStandardOutputFolder(mainProject));
        refFilePath = refFilePath.append(new Path(mainProject.getProperties()._packaging.getOutputFileName()
                + IConstants.COD_FILE_EXTENSION_WITH_DOT));
        File refFile = refFilePath.toFile();
        if (!refFile.exists()) {
            return true;
        }
        IPath dependencySampleFilePath = null;
        File dependencyCodFile = null;
        for (BlackBerryProject bbProject : bbProjects) {
            dependencySampleFilePath = bbProject.getProject().getLocation()
                    .append(PackagingUtils.getRelativeStandardOutputFolder(bbProject));
            dependencySampleFilePath = dependencySampleFilePath
                    .append(new Path(bbProject.getProperties()._packaging.getOutputFileName()
                            + IConstants.DEBUG_FILE_EXTENSION_WITH_DOT));
            dependencyCodFile = dependencySampleFilePath.toFile();
            if (dependencyCodFile.lastModified() > refFile.lastModified()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasBeenUpdated(BlackBerryProject bbproj) throws CoreException {
        IPath refFilePath = bbproj.getProject().getLocation()
                .append(PackagingUtils.getRelativeStandardOutputFolder(bbproj));
        refFilePath = refFilePath.append(new Path(
                bbproj.getProperties()._packaging.getOutputFileName() + IConstants.DEBUG_FILE_EXTENSION_WITH_DOT));
        File refFile = refFilePath.toFile();
        if (!refFile.exists()) {
            return true;
        }
        IFile iDescriptorFile = bbproj.getProject().getFile(BlackBerryProject.METAFILE);
        File descriptorFile = iDescriptorFile.getLocation().toFile();
        // check the time stamp of the project descriptor file
        if (!descriptorFile.exists() && bbproj.getProject().hasNature(BlackBerryProjectCoreNature.NATURE_ID)) {
            // TODO not support java project now
            throw new CoreException(StatusFactory.createErrorStatus("Project does not have the descriptor file."));
        }
        if (descriptorFile.lastModified() > refFile.lastModified()) {
            return true;
        }
        //Find the custom JAD file in the project root
        String custjad = PackagingUtils.getCustomJadFile(bbproj);
        if (custjad != null) {
            File jadFile = new File(custjad);
            if (jadFile.lastModified() > refFile.lastModified()) {
                return true;
            }
        }

        //Find the custom rapc file in the project root
        String custrapc = PackagingUtils.getCustomJadFile(bbproj);
        if (custrapc != null) {
            File rapcFile = new File(custrapc);
            if (rapcFile.lastModified() > refFile.lastModified()) {
                return true;
            }
        }

        // check if the output folders and their children have been updated
        Set<File> outputFolders = ImportUtils.getOutputFolderSet(bbproj);
        for (File folder : outputFolders) {
            if (ProjectUtils.hasFolderBeenUpdated(folder, refFile.lastModified())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if the projects in the given <code>project</code> have any packaging problems.
     *
     * @param project
     * @return
     */
    private boolean hasPackagingProblems(IProject project) {
        if (project == null) {
            return false;
        }
        try {
            IMarker[] markers = project.findMarkers(IRIMMarker.PACKAGING_PROBLEM, true, IResource.DEPTH_INFINITE);
            for (IMarker marker : markers) {
                Integer severity = (Integer) marker.getAttribute(IMarker.SEVERITY);
                if ((severity != null) && (severity.intValue() >= IMarker.SEVERITY_ERROR)) {
                    return true;
                }
            }
            return false;
        } catch (CoreException e) {
            _log.error(e);
            return true;
        }
    }

    private boolean hasProblemOnDependency(List<BlackBerryProject> dependencyPrjoects) throws CoreException {
        IProject iProject = null;
        for (BlackBerryProject jProject : dependencyPrjoects) {
            iProject = jProject.getProject();
            if (ProjectUtils.hasCriticalProblems(iProject)) {
                return true;
            }
        }
        return false;
    }
}