blob: dfb69fda634495736102328909528be5d62dece5 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2003, 2015 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.core.ext;
import java.io.IOException;
import java.net.URL;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.objectteams.otdt.internal.core.ext.OTCoreExtMessages;
import org.eclipse.objectteams.otdt.internal.core.ext.OTVariableInitializer;
import org.eclipse.objectteams.otequinox.TransformerPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
/**
* This class serves the "OTRE" classpath container.
* It also provides access to resolved paths for all OTRE-related jars.
* @author gis
*/
public class OTREContainer implements IClasspathContainer
{
/** Name of this classpath container, which hosts the full OTRE. */
public static final String OTRE_CONTAINER_NAME = "OTRE"; //$NON-NLS-1$
// these are served from the current plugin:
private static IPath OTRE_MIN_JAR_PATH;
private static IPath OTRE_AGENT_JAR_PATH;
private static IPath OTDRE_AGENT_JAR_PATH;
private static IPath[][] BYTECODE_WEAVER_PATHS = new IPath[WeavingScheme.values().length][]; // will be initialized in {@link findBytecodeLib(BundleContext,boolean)}
// details of this container: name and hosting plugin:
private static final IPath OTRE_CONTAINER_PATH = new Path(OTRE_CONTAINER_NAME);
static String OT_RUNTIME_PLUGIN = "org.eclipse.objectteams.runtime"; //$NON-NLS-1$
// file names for the above OTRE_X_JAR_PATH constants:
private static final String OTRE_MIN_JAR_FILENAME = "otre_min.jar"; //$NON-NLS-1$
private static final String OTRE_AGENT_JAR_FILENAME = "otre_agent.jar"; //$NON-NLS-1$
private static final String OTDRE_AGENT_JAR_FILENAME = "otredyn_agent.jar"; //$NON-NLS-1$
private static final String OTRE_PLUGIN_NAME = "org.eclipse.objectteams.otre";
private static final String OTDRE_PLUGIN_NAME = "org.eclipse.objectteams.otredyn";
// data for initializing the above BYTECODE_LIBRARY_PATH:
private static final String BCEL_BUNDLE_NAME = "org.apache.bcel"; //$NON-NLS-1$
private static final String BCEL_VERSION_RANGE = "[5.2.0,5.3.0)"; //$NON-NLS-1$
// data for initializing the ASM_PATH:
private static final String[] ASM_BUNDLE_NAMES = { "org.objectweb.asm", "org.objectweb.asm.tree", "org.objectweb.asm.commons", "org.objectweb.asm.util", "org.objectweb.asm.analysis" }; //$NON-NLS-1$
private static final String ASM_VERSION_RANGE = "[5.0.1,7.2.0)"; //$NON-NLS-1$
private IClasspathEntry[] _cpEntries;
/**
* Return a an array of classpath entry representing the OTRE.
* @return a singleton array.
*/
public IClasspathEntry[] getClasspathEntries()
{
if (_cpEntries == null)
{
IPath fullPath = new Path(OTVariableInitializer.getInstallatedPath(OTDTPlugin.getDefault(), OT_RUNTIME_PLUGIN, "bin")); //$NON-NLS-1$
_cpEntries = new IClasspathEntry[] {JavaCore.newLibraryEntry(fullPath, fullPath, new Path("/"))}; //$NON-NLS-1$
}
return _cpEntries;
}
/** Answer the text that describes the OTRE container in the UI. */
public String getDescription()
{
return OTCoreExtMessages.OTREContainer__Description;
}
/**
* Answer the kind of this classpath container, value = {@link IClasspathContainer#K_APPLICATION}.
*/
public int getKind()
{
// don't mark as K_SYSTEM or K_SYSTEM_DEFAULT, which would prevent jdt.debug from adding this to the runtime classpath.
return IClasspathContainer.K_APPLICATION;
}
/**
* The name of this classpath container as a path, value = "OTRE".
*/
public IPath getPath()
{
return OTRE_CONTAINER_PATH;
}
/**
* Answer the path of the "otre_min.jar" archive, which is placed on the bootclasspath when running OT/J programs.
* @return resolved path
*/
public static IPath getOtreMinJarPath () {
if (OTRE_MIN_JAR_PATH == null)
OTRE_MIN_JAR_PATH = OTDTPlugin.getResolvedVariablePath(OTDTPlugin.OTDT_INSTALLDIR, "lib/"+OTRE_MIN_JAR_FILENAME); //$NON-NLS-1$
return OTRE_MIN_JAR_PATH;
}
/**
* Answer the path of the "otre_agent.jar" archive, which is passed as a -javaagent to the JVM.
* @return resolved path
*/
public static IPath getOtreAgentJarPath(WeavingScheme scheme) {
switch (scheme) {
case OTRE:
if (OTRE_AGENT_JAR_PATH == null)
OTRE_AGENT_JAR_PATH = OTDTPlugin.getResolvedVariablePath(OTDTPlugin.OTDT_INSTALLDIR, "lib/"+OTRE_AGENT_JAR_FILENAME); //$NON-NLS-1$
return OTRE_AGENT_JAR_PATH;
case OTDRE:
if (OTDRE_AGENT_JAR_PATH == null)
OTDRE_AGENT_JAR_PATH = OTDTPlugin.getResolvedVariablePath(OTDTPlugin.OTDT_INSTALLDIR, "lib/"+OTDRE_AGENT_JAR_FILENAME); //$NON-NLS-1$
return OTDRE_AGENT_JAR_PATH;
default:
throw new IncompatibleClassChangeError("Unexpected enum constant "+scheme);
}
}
/**
* Answer the path of the "otequinoxAgent.jar" archive, which is passed as a -javaagent to the JVM for OT/Equinox debug launches.
* @return resolved path
*/
public static IPath getOtequinoxAgentJarPath() {
return new Path(TransformerPlugin.getOtequinoxAgentPath());
}
/**
* Adds the ObjectTeams classes to the given JavaProject's classpath,
* and ensures the Java compliance is >= 1.5
* Handles both variants, OTRE and OTDRE.
*/
public static void initializeOTJProject(IProject project) throws CoreException
{
if (project == null)
{
return;
}
if (project.hasNature(JavaCore.NATURE_ID))
{
IJavaProject javaPrj = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
IClasspathEntry[] classpath = javaPrj.getRawClasspath();
if (!isOTREAlreadyInClasspath(classpath))
{
addOTREToClasspath(javaPrj, classpath);
}
String javaVersion = javaPrj.getOption(JavaCore.COMPILER_COMPLIANCE, true);
if (javaVersion.compareTo(JavaCore.VERSION_1_5)<0) {
javaPrj.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5);
javaPrj.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5);
javaPrj.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5);
javaPrj.setOption(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
javaPrj.setOption(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
javaPrj.setOption(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
}
}
}
private static boolean isOTREAlreadyInClasspath(IClasspathEntry[] classpath) {
for (int idx = 0; classpath != null && idx < classpath.length; idx++) {
IClasspathEntry entry = classpath[idx];
if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER &&
(entry.getPath().equals(OTRE_CONTAINER_PATH)))
return true;
}
return false;
}
public static IPath getContainerPath() {
return OTRE_CONTAINER_PATH;
}
public static IPath[] getWeaverPaths(WeavingScheme scheme) {
return BYTECODE_WEAVER_PATHS[scheme.ordinal()];
}
/**
* Add the object teams foundation classes to the classpath.
*/
private static void addOTREToClasspath(IJavaProject javaPrj, IClasspathEntry[] classpath)
throws JavaModelException, CoreException
{
IClasspathEntry[] newClasspath = new IClasspathEntry[classpath.length + 1];
System.arraycopy( classpath, 0, newClasspath, 0, classpath.length );
newClasspath[classpath.length] = JavaCore.newContainerEntry(OTRE_CONTAINER_PATH, false);
if (newClasspath[classpath.length] != null)
javaPrj.setRawClasspath( newClasspath, null );
else
throw new CoreException( new Status(
IStatus.ERROR,
OTDTPlugin.PLUGIN_ID,
IStatus.OK,
OTCoreExtMessages.OTREContainer_otre_not_found,
null) );
}
/** Fetch the location of the otre, otdre, bcel and asm bundles into {@link #BYTECODE_WEAVER_PATHS}. */
@SuppressWarnings("deprecation") // class PackageAdmin is "deprecated"
static void findBytecodeLibs(BundleContext context) throws IOException {
ServiceReference<org.osgi.service.packageadmin.PackageAdmin> ref =
(ServiceReference<org.osgi.service.packageadmin.PackageAdmin>) context.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class);
if (ref == null)
throw new IllegalStateException("Cannot connect to PackageAdmin"); //$NON-NLS-1$
org.osgi.service.packageadmin.PackageAdmin packageAdmin = context.getService(ref);
BCEL: {
String bundleName = BCEL_BUNDLE_NAME;
String bundleVersionRange = BCEL_VERSION_RANGE;
for (Bundle bundle : packageAdmin.getBundles(bundleName, bundleVersionRange)) {
BYTECODE_WEAVER_PATHS[WeavingScheme.OTRE.ordinal()] =
new IPath[] {
new Path(FileLocator.toFileURL(bundle.getEntry("/")).getFile()), //$NON-NLS-1$
new Path(OTVariableInitializer.getInstallatedPath(OTDTPlugin.getDefault(), OTRE_PLUGIN_NAME, "bin")) //$NON-NLS-1$
};
break BCEL;
}
throw new RuntimeException("bytecode libarary for OTRE not found"); //$NON-NLS-1$
}
ASM : {
int asm = WeavingScheme.OTDRE.ordinal();
int numBundles = ASM_BUNDLE_NAMES.length+1;
BYTECODE_WEAVER_PATHS[asm] = new IPath[numBundles];
int i = 0;
BYTECODE_WEAVER_PATHS[asm][i++] = new Path(OTVariableInitializer.getInstallatedPath(OTDTPlugin.getDefault(), OTDRE_PLUGIN_NAME, "bin")); //$NON-NLS-1$
for (String bundleName : ASM_BUNDLE_NAMES) {
for (Bundle bundle : packageAdmin.getBundles(bundleName, ASM_VERSION_RANGE)) {
URL bundleEntry = bundle.getEntry("bin"); // source project?
if (bundleEntry == null)
bundleEntry = bundle.getEntry("/"); // binary bundle
BYTECODE_WEAVER_PATHS[asm][i++] = new Path(FileLocator.toFileURL(bundleEntry).getFile()); //$NON-NLS-1$
break;
}
}
if (i == numBundles)
break ASM;
throw new RuntimeException("bytecode libarary for OTDRE not found"); //$NON-NLS-1$
}
}
}