org.eclipse.edt.ide.testserver.ClasspathUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.edt.ide.testserver.ClasspathUtil.java

Source

/*******************************************************************************
 * Copyright  2011, 2013 IBM Corporation and others.
 * 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:
 * IBM Corporation - initial API and implementation
 *
 *******************************************************************************/
package org.eclipse.edt.ide.testserver;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.edt.compiler.tools.IRUtils;
import org.eclipse.edt.ide.core.internal.model.EGLProject;
import org.eclipse.edt.ide.core.model.EGLCore;
import org.eclipse.edt.ide.core.model.EGLModelException;
import org.eclipse.edt.ide.core.model.IEGLPathEntry;
import org.eclipse.edt.ide.core.model.IEGLProject;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;

/**
 * Utility methods for building classpaths used by JDT. Clients may use this class.
 */
public class ClasspathUtil {

    private ClasspathUtil() {
        // No instances.
    }

    public final static char[] SUFFIX_egldd = ".egldd".toCharArray(); //$NON-NLS-1$
    public final static char[] SUFFIX_EGLDD = ".EGLDD".toCharArray(); //$NON-NLS-1$

    /**
     * The classpath entries that are applied to all test servers.
     */
    private static List<String> testServerBaseEntries;

    /**
     * Creates a classpath to be added to a a launch configuration for running the Jetty server. The appropriate Jetty,
     * servlet, and EDT plug-ins will be added to the classpath, as well as ensuring any Java projects on the EGL build path
     * are included in the classpath if they aren't already. Finally, classpath contributions from
     * {@link AbstractTestServerContribution#getClasspathAdditions(TestServerConfiguration)} will be appended at the end, so
     * long as the contributions are valid.
     * 
     * @param config  The test server configuration.
     * @param classpath  A list that will receive the new entries.
     * @throws CoreException
     */
    public static void buildClasspath(TestServerConfiguration config, List<String> classpath) throws CoreException {
        IProject project = config.getProject();
        String entry;

        // The project's JRE (not required for execution, but required for source lookup).
        try {
            IRuntimeClasspathEntry jreEntry = JavaRuntime.computeJREEntry(JavaCore.create(project));
            if (jreEntry != null) {
                classpath.add(jreEntry.getMemento());
            }
        } catch (CoreException ce) {
            TestServerPlugin.getDefault().log(ce);
        }

        if (testServerBaseEntries == null) {
            testServerBaseEntries = new ArrayList<String>(20);

            // Add all org.eclipse.jetty.* plug-ins.
            Bundle[] bundles = TestServerPlugin.getDefault().getBundle().getBundleContext().getBundles();
            for (Bundle bundle : bundles) {
                if (bundle.getSymbolicName().startsWith("org.eclipse.jetty.")) { //$NON-NLS-1$
                    entry = getClasspathEntry(bundle);
                    if (entry != null) {
                        testServerBaseEntries.add(entry);
                    }
                }
            }

            entry = getClasspathEntry("javax.servlet"); //$NON-NLS-1$
            if (entry != null) {
                testServerBaseEntries.add(entry);
            }

            entry = getClasspathEntry("org.eclipse.edt.ide.testserver"); //$NON-NLS-1$
            if (entry != null) {
                testServerBaseEntries.add(entry);
            }
        }

        classpath.addAll(testServerBaseEntries);

        // The main project.
        classpath.add(getWorkspaceProjectClasspathEntry(project.getName()));

        // Add any contributed classpath entries.
        for (AbstractTestServerContribution contrib : TestServerPlugin.getContributions()) {
            String[] extraClasspath = contrib.getClasspathAdditions(config);
            if (extraClasspath != null && extraClasspath.length > 0) {
                for (String next : extraClasspath) {
                    if (!classpath.contains(next)) {
                        // Validate the entry; bad entries will prevent the process from launching.
                        if (classpathEntryIsValid(next, project)) {
                            classpath.add(next);
                        } else {
                            TestServerPlugin.getDefault()
                                    .logWarning(NLS.bind(TestServerMessages.InvalidClasspathEntry, next));
                        }
                    }
                }
            }
        }
    }

    public static void addEGLPathToJavaPathIfNecessary(IJavaProject javaProject, IProject currProject,
            Set<IProject> seen, List<String> classpath) {
        if (seen.contains(currProject)) {
            return;
        }
        seen.add(currProject);

        try {
            if (currProject.hasNature(EGLCore.NATURE_ID)) {
                IEGLProject eglProject = EGLCore.create(currProject);
                for (IEGLPathEntry pathEntry : eglProject.getResolvedEGLPath(true)) {
                    if (pathEntry.getEntryKind() == IEGLPathEntry.CPE_PROJECT) {
                        IPath path = pathEntry.getPath();
                        IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
                        try {
                            if (resource != null && resource.getType() == IResource.PROJECT
                                    && !seen.contains(resource)
                                    && ((IProject) resource).hasNature(JavaCore.NATURE_ID)
                                    && !javaProject.isOnClasspath(resource)) {
                                classpath.add(getWorkspaceProjectClasspathEntry(resource.getName()));
                                addEGLPathToJavaPathIfNecessary(javaProject, (IProject) resource, seen, classpath);
                            }
                        } catch (CoreException ce) {
                        }
                    }
                }
            }
        } catch (EGLModelException e) {
        } catch (CoreException e) {
        }
    }

    public static String getClasspathEntry(String pluginName) {
        Bundle bundle = Platform.getBundle(pluginName);
        if (bundle != null) {
            return getClasspathEntry(bundle);
        }

        TestServerPlugin.getDefault().log(NLS.bind(TestServerMessages.CouldNotGetPluginPath, pluginName), null);
        return null;
    }

    public static String getClasspathEntry(Bundle bundle) {
        try {
            File file = FileLocator.getBundleFile(bundle);
            String path = file.getAbsolutePath();
            if (file.isDirectory()) {
                if (!path.endsWith(File.separator)) {
                    path += File.separator;
                }
                path += "bin"; //$NON-NLS-1$
            }

            return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><runtimeClasspathEntry externalArchive=\"" + path //$NON-NLS-1$
                    + "\" path=\"3\" type=\"2\"/>"; //$NON-NLS-1$
        } catch (IOException e) {
            TestServerPlugin.getDefault()
                    .log(NLS.bind(TestServerMessages.CouldNotGetPluginPath, bundle.getSymbolicName()), e);
            return null;
        }
    }

    public static String getWorkspaceProjectClasspathEntry(String projectName) {
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><runtimeClasspathEntry id=\"org.eclipse.jdt.launching.classpathentry.defaultClasspath\">" //$NON-NLS-1$
                + "<memento exportedEntriesOnly=\"false\" project=\"" + projectName + "\"/></runtimeClasspathEntry>"; //$NON-NLS-2$
    }

    /**
     * @return true if fileName is a type of file that may affect a server's classpath.
     */
    public static boolean canAffectClasspath(String fileName) {
        if (fileName == null || fileName.length() == 0) {
            return false;
        }

        return ".classpath".equals(fileName) || EGLProject.EGLPATH_FILENAME.equals(fileName) //$NON-NLS-1$
                || IRUtils.matchesFileName(fileName, SUFFIX_egldd, SUFFIX_EGLDD);
    }

    /**
     * Verifies that the classpath entry is valid and won't cause the launch to fail.
     * 
     * @param entry  The entry to validate.
     * @param serverProject  The project that the test server will run out of.
     * @return true if it's valid
     */
    public static boolean classpathEntryIsValid(String entry, IProject serverProject) {
        try {
            ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager()
                    .getLaunchConfigurationType(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);
            ILaunchConfigurationWorkingCopy copy = type.newInstance(null, "ezeTemp"); //$NON-NLS-1$
            copy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, serverProject.getName());
            copy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);

            List<String> classpath = new ArrayList<String>(1);
            classpath.add(entry);
            copy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, classpath);

            JavaRuntime.resolveRuntimeClasspath(JavaRuntime.computeUnresolvedRuntimeClasspath(copy), copy);
            return true;
        } catch (CoreException ce) {
            return false;
        }
    }

    /**
     * @return the resolved classpath for the launch configuration. All entries, not just user entries, are returned.
     * @throws CoreException
     */
    public static String[] resolveClasspath(ILaunchConfiguration config) throws CoreException {
        IRuntimeClasspathEntry[] entries = JavaRuntime
                .resolveRuntimeClasspath(JavaRuntime.computeUnresolvedRuntimeClasspath(config), config);

        String[] paths = new String[entries.length];
        for (int i = 0; i < entries.length; i++) {
            paths[i] = entries[i].getLocation();
        }
        return paths;
    }
}