org.springframework.ide.eclipse.boot.dash.cloudfoundry.packaging.CloudApplicationArchiver.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.ide.eclipse.boot.dash.cloudfoundry.packaging.CloudApplicationArchiver.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Pivotal, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Pivotal, Inc. - initial API and implementation
 *******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.cloudfoundry.packaging;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable;
import org.eclipse.jdt.ui.jarpackager.JarPackageData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.springframework.boot.loader.tools.Libraries;
import org.springframework.boot.loader.tools.Library;
import org.springframework.boot.loader.tools.LibraryCallback;
import org.springframework.boot.loader.tools.LibraryScope;
import org.springframework.boot.loader.tools.Repackager;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.ApplicationManifestHandler;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryUiUtil;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.JavaPackageFragmentRootHandler;
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;

public class CloudApplicationArchiver implements ICloudApplicationArchiver {

    private IJavaProject javaProject;

    private String applicationName;

    private final ApplicationManifestHandler parser;

    private static final String TEMP_FOLDER_NAME = "springidetempFolderForJavaAppJar";

    public CloudApplicationArchiver(IJavaProject javaProject, String applicationName,
            ApplicationManifestHandler parser) {
        this.javaProject = javaProject;
        this.applicationName = applicationName;
        this.parser = parser;
    }

    public File getApplicationArchive(IProgressMonitor monitor) throws Exception {
        File archive = getArchiveFromManifest(monitor);
        if (archive == null) {

            File packagedFile = null;

            JavaPackageFragmentRootHandler rootResolver = getPackageFragmentRootHandler(javaProject, monitor);

            final IPackageFragmentRoot[] roots = rootResolver.getPackageFragmentRoots(monitor);

            if (roots == null || roots.length == 0) {
                throw ExceptionUtil.coreException("Unable to package project" + javaProject.getElementName()
                        + " as a jar application. Please verify that the project is a valid Java project and contains a main type in source.");
            }

            IType mainType = rootResolver.getMainType(monitor);

            JarPackageData jarPackageData = getJarPackageData(roots, mainType, monitor);

            // generate a manifest file. Note that manifest files
            // are only generated in the temporary jar meant for
            // deployment.
            // The associated Java project is no modified.
            jarPackageData.setGenerateManifest(true);

            // This ensures that folders in output folders appear at root
            // level
            // Example: src/main/resources, which is in the project's
            // classpath, contains non-Java templates folder and
            // has output folder target/classes. If not exporting output
            // folder,
            // templates will be packaged in the jar using this path:
            // resources/templates
            // This may cause problems with the application's dependencies
            // if they are looking for just /templates at top level of the
            // jar
            // If exporting output folders, templates folder will be
            // packaged at top level in the jar.
            jarPackageData.setExportOutputFolders(true);

            packagedFile = packageApplication(jarPackageData, monitor);

            bootRepackage(roots, packagedFile);

            archive = packagedFile;
        }

        return archive;
    }

    protected JavaPackageFragmentRootHandler getPackageFragmentRootHandler(IJavaProject javaProject,
            IProgressMonitor monitor) throws CoreException {

        return new JavaPackageFragmentRootHandler(javaProject);
    }

    protected void bootRepackage(final IPackageFragmentRoot[] roots, File packagedFile) throws Exception {
        Repackager bootRepackager = new Repackager(packagedFile);
        bootRepackager.repackage(new Libraries() {

            public void doWithLibraries(LibraryCallback callBack) throws IOException {
                for (IPackageFragmentRoot root : roots) {

                    if (root.isArchive()) {

                        File rootFile = new File(root.getPath().toOSString());
                        if (rootFile.exists()) {
                            callBack.library(new Library(rootFile, LibraryScope.COMPILE));
                        }
                    }
                }
            }
        });
    }

    protected JarPackageData getJarPackageData(IPackageFragmentRoot[] roots, IType mainType,
            IProgressMonitor monitor) throws Exception {

        String filePath = getTempJarPath();

        IPath location = new Path(filePath);

        // Note that if no jar builder is specified in the package data
        // then a default one is used internally by the data that does NOT
        // package any jar dependencies.
        JarPackageData packageData = new JarPackageData();

        packageData.setJarLocation(location);

        // Don't create a manifest. A repackager should determine if a generated
        // manifest is necessary
        // or use a user-defined manifest.
        packageData.setGenerateManifest(false);

        // Since user manifest is not used, do not save to manifest (save to
        // manifest saves to user defined manifest)
        packageData.setSaveManifest(false);

        packageData.setManifestMainClass(mainType);
        packageData.setElements(roots);
        return packageData;
    }

    protected File packageApplication(final JarPackageData packageData, IProgressMonitor monitor) throws Exception {

        int progressWork = 10;
        final SubMonitor subProgress = SubMonitor.convert(monitor, progressWork);

        final File[] createdFile = new File[1];

        final Exception[] error = new Exception[1];
        Display.getDefault().syncExec(new Runnable() {

            @Override
            public void run() {
                Shell shell = CloudFoundryUiUtil.getShell();

                IJarExportRunnable runnable = packageData.createJarExportRunnable(shell);
                try {
                    runnable.run(subProgress);

                    File file = new File(packageData.getJarLocation().toString());
                    createdFile[0] = file;

                } catch (InvocationTargetException e) {
                    error[0] = e;
                } catch (InterruptedException ie) {
                    error[0] = ie;
                } finally {
                    subProgress.done();
                }
            }

        });
        if (error[0] != null) {
            throw error[0];
        }

        return createdFile[0];
    }

    public String getTempJarPath() throws Exception {
        File tempFolder = File.createTempFile(TEMP_FOLDER_NAME, null);
        tempFolder.delete();
        tempFolder.mkdirs();

        if (!tempFolder.exists()) {
            throw ExceptionUtil
                    .coreException("Failed to create temporary jar file when packaging application for deployment: "
                            + tempFolder.getAbsolutePath());
        }

        File targetFile = new File(tempFolder, applicationName + ".jar");
        targetFile.deleteOnExit();

        String path = new Path(targetFile.getAbsolutePath()).toString();

        System.out.println("getTempJarPath => " + path);
        return path;
    }

    public File getArchiveFromManifest(IProgressMonitor monitor) throws Exception {
        String archivePath = null;
        // Read the path again instead of deployment info, as a user may be
        // correcting the path after the module was creating and simply
        // attempting to push it again without the
        // deployment wizard
        if (parser.hasManifest()) {
            archivePath = parser.getApplicationProperty(applicationName, ApplicationManifestHandler.PATH_PROP,
                    monitor);
        }

        File packagedFile = null;
        if (archivePath != null) {
            // Only support paths that point to archive files
            IPath path = new Path(archivePath);
            if (path.getFileExtension() != null) {

                if (!path.isAbsolute()) {
                    // Check if it is project relative first
                    IFile projectRelativeFile = javaProject.getProject().getFile(path);
                    if (projectRelativeFile != null && projectRelativeFile.exists()) {
                        packagedFile = projectRelativeFile.getLocation().toFile();
                    } else {
                        // Case where file exists in file system but is not
                        // present in workspace (i.e. IProject may be out of
                        // synch with file system)
                        IPath projectPath = javaProject.getProject().getLocation();
                        if (projectPath != null) {
                            archivePath = projectPath.append(archivePath).toString();
                            File absoluteFile = new File(archivePath);
                            if (absoluteFile.exists() && absoluteFile.canRead()) {
                                packagedFile = absoluteFile;
                            }
                        }
                    }
                } else {
                    // See if it is an absolute path
                    File absoluteFile = new File(archivePath);
                    if (absoluteFile.exists() && absoluteFile.canRead()) {
                        packagedFile = absoluteFile;
                    }
                }
            }
            // If a path is specified but no file found stop further deployment
            if (packagedFile == null) {
                throw ExceptionUtil.coreException(
                        "No file found at: " + path + ". Unable to package the application for deployment");
            } else {
                return packagedFile;
            }
        }
        return null;
    }
}