org.cloudfoundry.ide.eclipse.server.standalone.internal.application.StandaloneRuntimeResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.ide.eclipse.server.standalone.internal.application.StandaloneRuntimeResolver.java

Source

/*******************************************************************************
 * Copyright (c) 2012, 2014 Pivotal Software, Inc. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, 
 * Version 2.0 (the "License); you may not use this file except in compliance 
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 *  Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 ********************************************************************************/
package org.cloudfoundry.ide.eclipse.server.standalone.internal.application;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.cloudfoundry.ide.eclipse.server.core.internal.CloudFoundryPlugin;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;

/**
 * Given a java project, two separate lists are resolved: <br/>
 * 1. List of resolved runtime dependency locations like .jar and .zip files <br/>
 * 2. List of resolved runtime source locations like Java .class files, .xml
 * files, and other resources needed during runtime. <br/>
 * In addition, callers can specify whether test sources should be skipped from
 * the list of resolve runtime source locations
 * <p/>
 * Note that this resolver is meant to be disposable, and only resolves
 * dependencies once, caching the results. If update runtime source and
 * dependency locations need to be obtain, a new resolver should be created.
 * 
 * @deprecated As of CF 1.6.0 Java applications are now packaged into jars prior
 *             to deployment to Cloud Foundry. See
 *             {@link JavaCloudFoundryArchiver}
 */
public class StandaloneRuntimeResolver {

    public static final IPath[] TEST_SOURCE_NAME_PATTERNS = { new Path("src/test") }; //$NON-NLS-1$

    private final boolean skipTestSources;

    private final IJavaProject javaProject;

    private List<String> runtimeSource;

    private List<String> runtimeDependencies;

    public StandaloneRuntimeResolver(IJavaProject javaProject, boolean skipTestSources) {
        this.javaProject = javaProject;
        this.skipTestSources = skipTestSources;
    }

    protected boolean shouldSkipTestSources() {
        return skipTestSources;
    }

    /**
     * Returns either test sources, or non-test sources, based on a flag
     * setting. If nothing is found, returns empty list.
     */
    protected Collection<IClasspathEntry> getSourceEntries(boolean istest) {
        try {
            IClasspathEntry[] rawEntries = javaProject.getRawClasspath();
            if (rawEntries != null) {
                Collection<IClasspathEntry> sourceEntries = new HashSet<IClasspathEntry>();
                for (IClasspathEntry entry : rawEntries) {
                    if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                        IPath path = entry.getPath();
                        if (path != null) {
                            boolean isTestSource = isTestSource(path.toOSString());
                            if ((istest && isTestSource) || (!istest && !isTestSource)) {
                                sourceEntries.add(entry);
                            }
                        }
                    }
                }
                return sourceEntries;
            }
        } catch (JavaModelException e) {
            CloudFoundryPlugin.log(e);
        }
        return Collections.emptyList();
    }

    protected Collection<String> getSourceOutputLocations(boolean istest) {
        Collection<IClasspathEntry> entries = getSourceEntries(istest);
        Set<String> locations = new HashSet<String>();
        for (IClasspathEntry entry : entries) {
            IPath path = entry.getOutputLocation();

            // For source entries, path is relative to workspace root
            path = getWorkspaceFullPath(path);

            if (path != null) {
                locations.add(path.toOSString());
            }
        }

        return locations;
    }

    protected Collection<String> getTestSourceOutputLocations() {
        return getSourceOutputLocations(true);
    }

    protected Collection<String> getNonTestSourceOutputLocations() {
        Collection<String> outputs = getSourceOutputLocations(false);
        Set<String> nonTestOutput = new HashSet<String>(outputs);
        // add the Java project default output location as well
        try {
            IPath location = javaProject.getOutputLocation();
            location = getWorkspaceFullPath(location);

            if (location != null) {
                nonTestOutput.add(location.toOSString());
            }
        } catch (JavaModelException e) {
            CloudFoundryPlugin.log(e);
        }
        return nonTestOutput;
    }

    /**
     * Gets full path for workspace paths. The path may be a path to a project
     * relative folder, or to a project itself
     * 
     * @param relativePath
     * @return
     */
    protected IPath getWorkspaceFullPath(IPath relativePath) {
        if (relativePath == null) {
            return null;
        }
        IPath path = relativePath;
        if (path.segmentCount() == 1) {
            // The path may be the project itself
            IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0));
            if (project.isAccessible()) {
                path = project.getLocation();
            }
        } else {
            IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(path);

            if (folder.isAccessible()) {
                path = folder.getLocation();
            }
        }
        return path;
    }

    /**
     * 
     * @param location
     *            should be an OS specific location
     * @return true if the OS path location contains a test source pattern like
     *         "src/test"
     */
    protected boolean isTestSource(String location) {
        if (location != null) {
            for (IPath testPattern : TEST_SOURCE_NAME_PATTERNS) {
                if (location.contains(testPattern.toOSString())) {
                    return true;
                }
            }
        }
        return false;
    }

    public List<String> getRuntimeSourceLocations() throws CoreException {
        if (runtimeSource == null) {
            computeRuntimeClassPath();
        }
        return runtimeSource;
    }

    public List<String> getRuntimeDependencyLocations() throws CoreException {
        if (runtimeDependencies == null) {
            computeRuntimeClassPath();
        }
        return runtimeDependencies;
    }

    public boolean hasRuntimeDependencies() {
        try {
            return !getRuntimeDependencyLocations().isEmpty();
        } catch (CoreException e) {
            CloudFoundryPlugin.log(e);
        }
        return false;
    }

    protected void computeRuntimeClassPath() throws CoreException {
        runtimeDependencies = new ArrayList<String>();

        IRuntimeClasspathEntry[] unresolved = JavaRuntime.computeUnresolvedRuntimeClasspath(javaProject);
        IRuntimeClasspathEntry jreEntry = JavaRuntime.computeJREEntry(javaProject);
        List<IRuntimeClasspathEntry> resolved = new ArrayList<IRuntimeClasspathEntry>();

        // Resolve all runtime entries, and skip the jre entry
        for (IRuntimeClasspathEntry rcEntry : unresolved) {

            if (rcEntry.equals(jreEntry)) {
                continue;
            } else {
                IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(rcEntry, javaProject);

                if (entries != null) {
                    resolved.addAll(Arrays.asList(entries));
                }
            }
        }

        // Separate dependency entries like archives from other runtime entries
        List<IRuntimeClasspathEntry> toSeparate = new ArrayList<IRuntimeClasspathEntry>(resolved);

        for (IRuntimeClasspathEntry entry : resolved) {

            String entryLocation = entry.getLocation();
            if (isAccessibleFile(entryLocation)) {
                toSeparate.remove(entry);
                runtimeDependencies.add(entry.getLocation());
            }
        }
        resolved = toSeparate;

        if (shouldSkipTestSources()) {
            // The special case to consider is if both the test source and non
            // test source have the same output location
            // if that is the case, the runtime entry associated with that
            // output location CANNOT be skipped. The only time
            // the test source entry can be skipped is if the output location
            // for that entry is NOT also used by a non test source entry
            Collection<String> testSourceOutputLocations = getTestSourceOutputLocations();
            Collection<String> nonTestSourceOutputLocations = getNonTestSourceOutputLocations();
            List<IRuntimeClasspathEntry> nonTestEntries = new ArrayList<IRuntimeClasspathEntry>(resolved);
            for (IRuntimeClasspathEntry entry : resolved) {

                String entryLocation = entry.getLocation();
                if (testSourceOutputLocations.contains(entryLocation)
                        && !nonTestSourceOutputLocations.contains(entryLocation)) {
                    nonTestEntries.remove(entry);
                }
            }
            resolved = nonTestEntries;
        }

        Set<String> resolvedEntryLocations = new HashSet<String>(resolved.size());
        for (IRuntimeClasspathEntry entry : resolved) {
            resolvedEntryLocations.add(entry.getLocation());
        }

        runtimeSource = new ArrayList<String>(resolvedEntryLocations);

    }

    protected boolean isAccessibleFile(String location) {
        File file = new File(location);
        try {
            return file.exists() && file.isFile();
        } catch (SecurityException e) {
            // Ignore
        }
        return false;
    }
}