/******************************************************************************* * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH 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 *******************************************************************************/ package de.gebit.integrity.eclipse.classpath; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.JavaCore; import org.eclipse.osgi.service.datalocation.Location; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import de.gebit.integrity.eclipse.Activator; /** * Classpath container which adds the Integrity bundles required to run tests as well as their immediate dependencies. * Note that not all declared dependencies (and their sub-dependencies) are actually added! This is due to a lot of them * actually not being required for simple test execution. If you're using an environment that does enforce full * dependency resolution (OSGi!), you'll have to add all necessary dependencies there yourself (for example on the * target platform in Eclipse PDE). * * @author Rene Schneider - initial API and implementation * */ public class IntegrityClasspathContainer implements IClasspathContainer { /** * The container path. */ private IPath path; /** * Creates a new instance. * * @param aPath * the container path */ public IntegrityClasspathContainer(IPath aPath) { path = aPath; } @Override public IClasspathEntry[] getClasspathEntries() { ArrayList<IClasspathEntry> tempEntryList = new ArrayList<IClasspathEntry>(); addToList(tempEntryList, new String[][] { new String[] { "de.gebit.integrity.runner" } }); addToList(tempEntryList, new String[][] { new String[] { "de.gebit.integrity.remoting" } }); addToList(tempEntryList, new String[][] { new String[] { "de.gebit.integrity.dsl" } }); addToList(tempEntryList, new String[][] { new String[] { "javax.inject" } }); addToList(tempEntryList, new String[][] { new String[] { "com.google.inject" } }); addToList(tempEntryList, new String[][] { new String[] { "com.google.guava" } }); addToList(tempEntryList, new String[][] { new String[] { "org.antlr.runtime" } }); addToList(tempEntryList, new String[][] { new String[] { "org.slf4j.log4j", "org.slf4j.api" }, new String[] { "org.apache.log4j" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.core.contenttype" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.core.jobs" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.core.resources" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.core.runtime" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.emf.common" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.emf.ecore" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.emf.ecore.xmi" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.emf.mwe.utils" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.equinox.common" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.equinox.preferences" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.text" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.xtext" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.xtext.util" } }); addToList(tempEntryList, new String[][] { new String[] { "org.eclipse.xtext.common.types" } }); addToList(tempEntryList, new String[][] { new String[] { "org.jdom" } }); // convert the list to an array and return it IClasspathEntry[] tempEntryArray = new IClasspathEntry[tempEntryList.size()]; return (IClasspathEntry[]) tempEntryList.toArray(tempEntryArray); } private void addToList(List<IClasspathEntry> aList, String[][] someBundleNames) { StringBuffer tempBuffer = new StringBuffer(); for (String[] tempBundleNames : someBundleNames) { StringBuffer tempInnerBuffer = new StringBuffer(); List<IClasspathEntry> tempList = new ArrayList<IClasspathEntry>(); boolean tempFoundAll = true; for (String tempBundleName : tempBundleNames) { IClasspathEntry tempEntry = getPluginEntry(findBundle(tempBundleName)); if (tempEntry != null) { tempList.add(tempEntry); } else { if (tempInnerBuffer.length() > 0) { tempInnerBuffer.append(", "); } tempInnerBuffer.append(tempBundleName); tempFoundAll = false; } } if (tempList.size() == 0 || !tempFoundAll) { if (tempBuffer.length() > 0) { tempBuffer.append(", "); } tempBuffer.append("{ " + tempInnerBuffer + " }"); } else { aList.addAll(tempList); return; } } Activator .getInstance() .getLog() .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Was unable to find any of the bundle combinations '" + tempBuffer + "' to add it to a projects' classpath!")); } private Bundle findBundle(String aSymbolicName) { for (Bundle tempBundle : FrameworkUtil.getBundle(JavaCore.class).getBundleContext().getBundles()) { if (tempBundle.getSymbolicName().equals(aSymbolicName)) { return tempBundle; } } return null; } @Override public String getDescription() { return "Integrity"; } @Override public int getKind() { return IClasspathContainer.K_APPLICATION; } @Override public IPath getPath() { return path; } /** * Resolves a bundle to its installation directory and creates an {@link IClasspathEntry} with it. * * @param aBundle * the bundle * @return The classpath entry, or null if no path was determinable. */ private IClasspathEntry getPluginEntry(Bundle aBundle) { if (aBundle == null) { return null; } IPath tempPluginPath = getInstallationDirectoryFor(aBundle); if (tempPluginPath == null) { return null; } else { return getLibrary(tempPluginPath); } } /** * Returns the installation directory for the given bundle or <code>null</code> if it cannot be determined. */ private IPath getInstallationDirectoryFor(Bundle aBundle) { String tempBundleLocation = aBundle.getLocation(); if (tempBundleLocation == null || tempBundleLocation.length() == 0) { return null; } IPath tempBundlePath; if (tempBundleLocation.startsWith("reference:file:")) { String tempPathString = tempBundleLocation.substring(15); if (tempPathString.endsWith("/")) { // This is a directory! Happens during development, when an Eclipse instance is started from another // Eclipse with the Integrity projects living there as projects and thus being included in the "inner" // Eclipse as directories. We'll return the right subdir in that case to allow for inclusion of the // compiled classes return new Path(tempPathString + "target/classes/"); } tempBundlePath = new Path(tempPathString); } else { tempBundlePath = new Path(tempBundleLocation); } if (tempBundlePath.isAbsolute()) { return tempBundlePath; } Location tempInstallLocation = Platform.getInstallLocation(); if (tempInstallLocation == null || !tempInstallLocation.isSet()) { return null; } Path tempPath = new Path(tempInstallLocation.getURL().getPath()); return tempPath.append(tempBundlePath); } /** * Creates an IClasspathEntry for the given jar file in the given path. * * @param aLibPath * the path where to find the jar * @param aJarName * the file name of the jar file * @return the library IClasspath entry */ private IClasspathEntry getLibrary(IPath aLibPath) { String tempJarName = aLibPath.removeFileExtension().lastSegment(); String tempSourceSuffix = aLibPath.toString().contains("de.gebit.integrity") ? "" : "_src"; IPath tempSourceJar = aLibPath.removeLastSegments(1).append(tempJarName + tempSourceSuffix) .addFileExtension("jar"); return JavaCore.newLibraryEntry(aLibPath, tempSourceJar, null); } }