Bug 406518 - migrate OT/Equinox to the standard OSGi WeavingHook
Rename project folders: the new project is the new otequinox.
diff --git a/plugins/org.eclipse.objectteams.otequinox/.classpath b/plugins/org.eclipse.objectteams.otequinox/.classpath
index 304e861..098194c 100644
--- a/plugins/org.eclipse.objectteams.otequinox/.classpath
+++ b/plugins/org.eclipse.objectteams.otequinox/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/plugins/org.eclipse.objectteams.otequinox/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.objectteams.otequinox/.settings/org.eclipse.jdt.core.prefs
index 64ec586..2e0f716 100644
--- a/plugins/org.eclipse.objectteams.otequinox/.settings/org.eclipse.jdt.core.prefs
+++ b/plugins/org.eclipse.objectteams.otequinox/.settings/org.eclipse.jdt.core.prefs
@@ -1,70 +1,100 @@
-#Thu Mar 12 15:19:36 CET 2009
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.objectteams.otdt.compiler.option.pure_java=enabled
diff --git a/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
index 68de648..b41be2e 100644
--- a/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
@@ -1,20 +1,16 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Bundle-Name: %pluginName
+Bundle-Name: OT/J Weaving for OSGi
Bundle-SymbolicName: org.eclipse.objectteams.otequinox;singleton:=true
-Bundle-Version: 2.2.0.qualifier
-Bundle-Vendor: %providerName
-Bundle-Localization: plugin
-Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.6.0,4.0.0)",
- org.eclipse.equinox.registry;bundle-version="[3.5.100,4.0.0)",
- org.eclipse.core.jobs;bundle-version="[3.5.100,4.0.0)",
- org.eclipse.osgi;bundle-version="[3.7.0,4.0.0)",
- org.objectweb.asm;bundle-version="[3.3.1,4.0.0)",
- org.eclipse.objectteams.runtime;bundle-version="[2.0.1,3.0.0)";visibility:=reexport
-Import-Package: org.eclipse.core.internal.runtime;resolution:=optional,
- org.eclipse.objectteams.otequinox.hook;version="[2.1.0,3.0.0)"
+Bundle-Version: 2.3.0.qualifier
Bundle-Activator: org.eclipse.objectteams.otequinox.TransformerPlugin
-Export-Package: org.eclipse.objectteams.otequinox
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-Vendor: Eclipse.org - Object Teams
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.objectteams.runtime;bundle-version="2.3.0";visibility:="reexport",
+ org.eclipse.osgi;bundle-version="3.10.0",
+ org.eclipse.equinox.ds;bundle-version="1.4.100"
+Import-Package: org.osgi.service.component;version="1.2.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
-
+Service-Component: OSGI-INF/weavinghook.xml
+Export-Package: org.eclipse.objectteams.otequinox
diff --git a/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf b/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf
deleted file mode 100644
index 25b3050..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf
+++ /dev/null
@@ -1,10 +0,0 @@
-instructions.install = \
- addProgramProperty(propName:osgi.hook.configurators.include,propValue:org.eclipse.objectteams.otequinox.hook.HookConfigurator); \
- setProgramProperty(propName:osgi.classloader.singleThreadLoads,propValue:false); \
- setProgramProperty(propName:osgi.classloader.lock,propValue:classname); \
- setProgramProperty(propName:ot.equinox,propValue:1);
-instructions.uninstall = \
- removeProgramProperty(propName:osgi.hook.configurators.include,propValue:org.eclipse.objectteams.otequinox.hook.HookConfigurator); \
- setProgramProperty(propName:osgi.classloader.singleThreadLoads,propValue:); \
- setProgramProperty(propName:osgi.classloader.lock,propValue:); \
- setProgramProperty(propName:ot.equinox,propValue:);
diff --git a/plugins/org.eclipse.objectteams.otequinox/OSGI-INF/weavinghook.xml b/plugins/org.eclipse.objectteams.otequinox/OSGI-INF/weavinghook.xml
new file mode 100644
index 0000000..9253e26
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/OSGI-INF/weavinghook.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<component name="weavinghook">
+ <implementation class="org.eclipse.objectteams.internal.osgi.weaving.OTWeavingHook"/>
+ <service>
+ <provide interface="org.osgi.framework.hooks.weaving.WeavingHook"/>
+ <provide interface="org.osgi.framework.hooks.weaving.WovenClassListener"/>
+ </service>
+</component>
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/Status.txt b/plugins/org.eclipse.objectteams.otequinox/Status.txt
new file mode 100644
index 0000000..3083ceb
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/Status.txt
@@ -0,0 +1,28 @@
+See https://bugs.eclipse.org/bugs/show_bug.cgi?id=406518
+
+(0) Register our WeavingHook as early as possible during start-up.
+Done, but need re-thinking. TJ said on equinox-dev: use start level 1
+
+(3) Scan each registered team class
+Done but should try to improve using BundleWiring.getClassLoader()
+
+NOTYET:
+-------
+(5) Add dependencies so that each bound base bundle can see:
+ - the OT runtime (package org.objectteams)
+ - the aspect bundle(s) into which the woven code may call
+
+(8) Subclasses of Thread (and ideally: implementors of Runnable, the latter
+ has not yet been realized) need to be woven to insert a trigger into OT's
+ TeamThreadManager. This mechanism may need to be redesigned entirely.
+
+(10) Detect if more than one version of any bound base bundle is installed.
+ May want to re-think strategy how to handle this case, currently:
+ pick the highest version.
+
+(12) Implement "forced exports", which allows access from an aspect bundle
+ to classes of a base bundle which are not exported from their bundle
+ (subject to checking of aspect permissions, see (9)).
+
+(9) If aspect permission checking is used, we need to veto the loading
+ of classes of any aspect bundle violating the current policy.
diff --git a/plugins/org.eclipse.objectteams.otequinox/about.html b/plugins/org.eclipse.objectteams.otequinox/about.html
deleted file mode 100644
index 66ef6f6..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/about.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
-<title>About</title>
-</head>
-<body lang="EN-US">
-<h2>About This Content</h2>
-
-<p>June 15, 2010</p>
-<h3>License</h3>
-
-<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
-indicated below, the Content is provided to you under the terms and conditions of the
-Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
-at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-For purposes of the EPL, "Program" will mean the Content.</p>
-
-<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
-being redistributed by another party ("Redistributor") and different terms and conditions may
-apply to your use of any object code in the Content. Check the Redistributor's license that was
-provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
-indicated below, the terms and conditions of the EPL still apply to any source code in the Content
-and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
-
-</body>
-</html>
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/about.ini b/plugins/org.eclipse.objectteams.otequinox/about.ini
deleted file mode 100644
index 10f4b53..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/about.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-aboutText=Object Teams -- Equinox integration (OT/Equinox)\n\
-\n\
-Version: 2.2.0\n\
-\n\
-Part of the Eclipse Kepler Simultaneous Release\n\
-\n\
-(c) Copyright Technical University Berlin and others, 2005, 2013\n\
-Visit http://www.eclipse.org/objectteams\n\
-\n\
-Upon installation, OT/Equinox is enabled in your configuration/config.ini file.\n\
-For instructions on how to temporarily disable OT/Equinox see the instructions at:\n\
- http://www.objectteams.org/distrib/features.html#otequinox
-
-
-featureImage=ote_32n.png
-
diff --git a/plugins/org.eclipse.objectteams.otequinox/build.properties b/plugins/org.eclipse.objectteams.otequinox/build.properties
index e8a500f..653e2a9 100644
--- a/plugins/org.eclipse.objectteams.otequinox/build.properties
+++ b/plugins/org.eclipse.objectteams.otequinox/build.properties
@@ -1,14 +1,7 @@
-bin.includes = META-INF/,\
- plugin.xml,\
- .,\
- schema/,\
- about.ini,\
- ote_32n.png,\
- plugin.properties,\
- about.html
-jars.compile.order = .
-src.includes = schema/,\
- about.ini
source.. = src/
-jre.compilation.profile = J2SE-1.5
-javacProjectSettings=true
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ OSGI-INF/
+additional.bundles=org.eclipse.jdt.annotation
diff --git a/plugins/org.eclipse.objectteams.otequinox/ote_32n.png b/plugins/org.eclipse.objectteams.otequinox/ote_32n.png
deleted file mode 100644
index 490ac03..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/ote_32n.png
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.objectteams.otequinox/plugin.properties b/plugins/org.eclipse.objectteams.otequinox/plugin.properties
deleted file mode 100644
index dafa5d9..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/plugin.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-pluginName=Object Teams Equinox Integration
-providerName=Eclipse.org - Object Teams
diff --git a/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindings.exsd b/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindings.exsd
index 7ed4fb7..6a1c4e8 100644
--- a/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindings.exsd
+++ b/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindings.exsd
@@ -143,7 +143,7 @@
Fully qualified name of a team class.
</documentation>
<appInfo>
- <meta.attribute kind="java" basedOn=":org.objectteams.ITeam"/>
+ <meta.attribute kind="java" basedOn="org.objectteams.Team"/>
</appInfo>
</annotation>
</attribute>
@@ -153,7 +153,7 @@
Fully qualified name of the team's super-class if that is not org.objectteams.Team but another team of the same plugin.
</documentation>
<appInfo>
- <meta.attribute kind="java" basedOn=":org.objectteams.ITeam"/>
+ <meta.attribute kind="java" basedOn="org.objectteams.Team"/>
</appInfo>
</annotation>
</attribute>
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
new file mode 100644
index 0000000..e9b8ac3
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
@@ -0,0 +1,141 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2009, 2013 Germany and Technical University Berlin, Germany 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
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.otequinox.ActivationKind;
+import org.osgi.framework.Bundle;
+
+/**
+ * A simple record representing the information read from an extension to org.eclipse.objectteams.otequinox.aspectBindings.
+ * @author stephan
+ * @since 1.3.0 (was a nested class before that)
+ */
+public class AspectBinding {
+ enum State { Initial, TeamsScanned, TeamsActivated };
+
+ public String aspectPlugin;
+ public String basePlugin;
+ public IConfigurationElement[] forcedExports;
+ public ActivationKind[] activations = null;
+ public String[] teamClasses;
+ public List<String>[] subTeamClasses;
+
+ public State state = State.Initial;
+
+ /** Dispenser for team classes indexed by base classes that should trigger activating the team. */
+ private HashMap<String, Set<String>> teamsPerBase = new HashMap<>();
+
+ /** Lookup to find base classes affected by a team (need to be available before instantiate/activate). */
+ HashMap<String, Collection<String>> basesPerTeam = new HashMap<>();
+
+ Set<String> teamsInProgress = new HashSet<>(); // TODO cleanup teams that are done
+
+ public AspectBinding(String aspectId, String baseId, IConfigurationElement[] forcedExportsConfs) {
+ this.aspectPlugin= aspectId;
+ this.basePlugin= baseId;
+ this.forcedExports= forcedExportsConfs;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void initTeams(int count) {
+ this.teamClasses = new String[count];
+ this.subTeamClasses = new List[count]; // new List<String>[count] is illegal!
+ this.activations = new ActivationKind[count];
+ }
+
+ public void setActivation(int i, String specifier) {
+ if (specifier == null)
+ this.activations[i] = ActivationKind.NONE;
+ else
+ this.activations[i] = ActivationKind.valueOf(specifier);
+ }
+ public String toString() {
+ String result = "\tbase plugin "+basePlugin+"\n\tadapted by aspect pluging "+aspectPlugin;
+ for (String teamClass : teamClasses) {
+ result += "\n\t\t + team "+teamClass;
+ }
+ return result;
+ }
+
+ public List<String> getAllTeams() {
+ List<String> all = Arrays.asList(this.teamClasses);
+ if (subTeamClasses != null) {
+ all = new ArrayList<>(all);
+ for (int i = 0; i < subTeamClasses.length; i++)
+ if (subTeamClasses[i] != null)
+ all.addAll(subTeamClasses[i]);
+ }
+ return all;
+ }
+
+ public void addBaseClassNames(String teamName, Collection<String> baseClassNames) {
+ basesPerTeam.put(teamName, baseClassNames);
+ for (String baseClassName : baseClassNames) {
+ Set<String> teams = teamsPerBase.get(baseClassName);
+ if (teams == null)
+ teamsPerBase.put(baseClassName, teams = new HashSet<>());
+ teams.add(teamName);
+ }
+ }
+
+ /** Destructively read the names of teams to load for a given base class. */
+ public synchronized @Nullable Collection<String> getTeamsForBase(String baseClassName) {
+ Set<String> teamNames = teamsPerBase.remove(baseClassName);
+ if (teamNames != null) {
+ teamNames.removeAll(teamsInProgress);
+ teamsInProgress.addAll(teamNames);
+ }
+ return teamNames;
+ }
+
+ public ActivationKind getActivation(String teamClassName) {
+ for (int i=0; i<teamClasses.length; i++) {
+ if (teamClasses[i].equals(teamClassName))
+ return activations[i];
+ }
+ return ActivationKind.NONE;
+ }
+
+ /** Read OT attributes of all teams in aspectBinding and collect affected base classes. */
+ public synchronized void scanTeamClasses(Bundle bundle) {
+ ClassScanner scanner = new ClassScanner();
+ for (String teamName : getAllTeams()) {
+ try {
+ teamName = scanner.readOTAttributes(bundle, teamName);
+ Collection<String> baseClassNames = scanner.getCollectedBaseClassNames();
+ addBaseClassNames(teamName, baseClassNames);
+ log(IStatus.INFO, "Scanned team class "+teamName+", found "+baseClassNames.size()+" base classes");
+ } catch (Exception e) {
+ log(e, "Failed to scan team class "+teamName);
+ }
+ }
+ this.state = State.TeamsScanned;
+ }
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
new file mode 100644
index 0000000..6b6e40c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
@@ -0,0 +1,367 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2008, 2013 Technical University Berlin, Germany 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
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+import static org.eclipse.objectteams.otequinox.Constants.ACTIVATION;
+import static org.eclipse.objectteams.otequinox.Constants.ASPECT_BINDING_EXTPOINT_ID;
+import static org.eclipse.objectteams.otequinox.Constants.BASE_PLUGIN;
+import static org.eclipse.objectteams.otequinox.Constants.CLASS;
+import static org.eclipse.objectteams.otequinox.Constants.ID;
+import static org.eclipse.objectteams.otequinox.Constants.REQUIRED_FRAGMENT;
+import static org.eclipse.objectteams.otequinox.Constants.SELF;
+import static org.eclipse.objectteams.otequinox.Constants.SUPERCLASS;
+import static org.eclipse.objectteams.otequinox.Constants.TEAM;
+import static org.eclipse.objectteams.otequinox.Constants.TRANSFORMER_PLUGIN_ID;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.RegistryFactory;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.otequinox.Constants;
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.objectteams.Team;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.hooks.weaving.WovenClass;
+
+/**
+ * An instance of this class holds the information loaded from extensions
+ * to the <code>aspectBindings</code> extension point.
+ * <p>
+ * Additionally it maintains dynamic data during the process of loading,
+ * instantiating and activating teams.
+ * </p>
+ */
+// parts of this class are moved from org.eclipse.objectteams.otequinox.TransformerPlugin
+@NonNullByDefault
+public class AspectBindingRegistry {
+
+ private static List<String> KNOWN_OTDT_ASPECTS = new ArrayList<String>();
+ static {
+ KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.jdt.ui");
+ KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.compiler.adaptor");
+ KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.refactoring");
+ KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.pde.ui");
+ KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.samples");
+ }
+ /** main internal registry of aspect bindings. */
+ private static HashMap<String, ArrayList<AspectBinding>> aspectBindingsByBasePlugin =
+ new HashMap<String, ArrayList<AspectBinding>>();
+ private static HashMap<String, ArrayList<AspectBinding>> aspectBindingsByAspectPlugin =
+ new HashMap<String, ArrayList<AspectBinding>>();
+ private Set<String> selfAdaptingAspects= new HashSet<String>(); // TODO, never read / evaluated
+
+ private HashMap<String, BaseBundleLoadTrigger> baseTripWires = new HashMap<>();
+
+ Set<String> beingDefined = new HashSet<>(); // shared with OTWeavingHook!
+
+ public AspectBindingRegistry(Set<String> beingDefined) {
+ this.beingDefined = beingDefined;
+ }
+
+ /** Record for one team waiting for instantiation/activation. */
+ static class WaitingTeamRecord {
+ @Nullable Class<? extends Team> teamClass; // ... either this is set
+ @Nullable Team teamInstance; // ... or this
+ AspectBinding aspectBinding;
+ String notFoundClass;
+
+ public WaitingTeamRecord(Class<? extends Team> teamClass, AspectBinding aspectBinding, String notFoundClass) {
+ this.teamClass = teamClass;
+ this.aspectBinding = aspectBinding;
+ this.notFoundClass = notFoundClass;
+ }
+ public WaitingTeamRecord(Team teamInstance, AspectBinding aspectBinding, String notFoundClass) {
+ this.teamInstance = teamInstance;
+ this.aspectBinding = aspectBinding;
+ this.notFoundClass = notFoundClass;
+ }
+ public WaitingTeamRecord(WaitingTeamRecord record, String notFoundClass) {
+ this.teamClass = record.teamClass;
+ this.teamInstance = record.teamInstance;
+ this.aspectBinding = record.aspectBinding;
+ this.notFoundClass = notFoundClass;
+ }
+ public @Nullable String getTeamName() {
+ final Class<? extends Team> clazz = teamClass;
+ if (clazz != null) {
+ return clazz.getName();
+ } else {
+ final Team instance = teamInstance;
+ if (instance != null)
+ return instance.getClass().getName();
+ }
+ return "<unknown team>";
+ }
+ }
+ // records of teams that have been deferred due to unresolved class dependencies:
+ private List<WaitingTeamRecord> deferredTeams = new ArrayList<>();
+
+ public static boolean IS_OTDT = false;
+
+ public boolean isOTDT() {
+ return IS_OTDT;
+ }
+
+ /* Load extensions for org.eclipse.objectteams.otequinox.aspectBindings and check aspect permissions. */
+ public void loadAspectBindings(@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin) {
+ IConfigurationElement[] aspectBindingConfigs = RegistryFactory.getRegistry().getConfigurationElementsFor(
+ TRANSFORMER_PLUGIN_ID, ASPECT_BINDING_EXTPOINT_ID);
+
+ for (int i = 0; i < aspectBindingConfigs.length; i++) {
+ IConfigurationElement currentBindingConfig = aspectBindingConfigs[i];
+
+ //aspect:
+ @SuppressWarnings("null")@NonNull String aspectBundleId= currentBindingConfig.getContributor().getName();
+ IS_OTDT |= KNOWN_OTDT_ASPECTS.contains(aspectBundleId);
+ if (packageAdmin != null) {
+ @SuppressWarnings("deprecation")
+ Bundle[] aspectBundles = packageAdmin.getBundles(aspectBundleId, null);
+ if (aspectBundles == null || aspectBundles.length == 0 || (aspectBundles[0].getState() < Bundle.RESOLVED)) {
+ log(ILogger.ERROR, "aspect bundle "+aspectBundleId+" is not resolved - not loading aspectBindings.");
+ continue;
+ }
+ }
+
+ //base:
+ IConfigurationElement[] basePlugins = currentBindingConfig.getChildren(BASE_PLUGIN);
+ if (basePlugins.length != 1) {
+ log(ILogger.ERROR, "aspectBinding of "+aspectBundleId+" must declare exactly one basePlugin");
+ continue;
+ }
+ String baseBundleId = basePlugins[0].getAttribute(ID);
+ if (baseBundleId == null) {
+ log(ILogger.ERROR, "aspectBinding of "+aspectBundleId+" must specify the id of a basePlugin");
+ continue;
+ }
+
+ //base fragments?
+ IConfigurationElement[] fragments = basePlugins[0].getChildren(REQUIRED_FRAGMENT);
+ if (fragments != null
+ && !checkRequiredFragments(aspectBundleId, baseBundleId, fragments, packageAdmin)) // reported inside
+ continue;
+
+ AspectBinding binding = new AspectBinding(aspectBundleId, baseBundleId, basePlugins[0].getChildren(Constants.FORCED_EXPORTS_ELEMENT));
+ // TODO(SH): maybe enforce that every bundle id is given only once?
+
+ //teams:
+ IConfigurationElement[] teams = currentBindingConfig.getChildren(TEAM);
+ binding.initTeams(teams.length);
+ try {
+ for (int j = 0; j < teams.length; j++) {
+ String teamClass = teams[j].getAttribute(CLASS);
+ binding.teamClasses[j] = teamClass;
+ String activation = teams[j].getAttribute(ACTIVATION);
+ binding.setActivation(j, activation);
+ }
+
+ @NonNull String realBaseBundleId = baseBundleId.toUpperCase().equals(SELF) ? aspectBundleId : baseBundleId;
+ addBindingForBaseBundle(realBaseBundleId, binding);
+ addBindingForAspectBundle(aspectBundleId, binding);
+ if (!baseTripWires.containsKey(realBaseBundleId))
+ baseTripWires.put(realBaseBundleId, new BaseBundleLoadTrigger(realBaseBundleId, this, packageAdmin));
+
+
+ // now that binding.teamClasses is filled connect to super team, if requested:
+ for (int j = 0; j < teams.length; j++) {
+ String superTeamName = teams[j].getAttribute(SUPERCLASS);
+ if (superTeamName != null)
+ addSubTeam(aspectBundleId, binding.teamClasses[j], superTeamName);
+ }
+ log(ILogger.INFO, "registered:\n"+binding);
+ } catch (Throwable t) {
+ log(t, "Invalid aspectBinding extension");
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation") // multiple uses of deprecated but still recommended class PackageAdmin
+ private boolean checkRequiredFragments(String aspectBundleId, String baseBundleId, IConfigurationElement[] fragments,
+ @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin)
+ {
+ // checking only, no real action needed.
+ boolean hasError = false;
+ for (IConfigurationElement fragment : fragments) {
+ String fragId = fragment.getAttribute(ID);
+ if (fragId == null) {
+ log(ILogger.ERROR, "Mandatory attribute \"id\" missing from element \"requiredFragment\" of aspect binding in "+aspectBundleId);
+ return false;
+ }
+ if (packageAdmin == null) {
+ log(ILogger.ERROR, "Not checking required fragment "+fragId+" in aspect binding of "+aspectBundleId+", package admin service not present");
+ return false; // report only once.
+ }
+
+ Bundle[] fragmentBundles = packageAdmin.getBundles(fragId, null);
+ if (fragmentBundles == null || fragmentBundles.length == 0) {
+ log(ILogger.ERROR, "Required fragment "+fragId+" not found in aspect binding of "+aspectBundleId);
+ hasError = true;
+ continue;
+ }
+ Bundle fragmentBundle = fragmentBundles[0];
+ String aspectBindingHint = " (aspect binding of "+aspectBundleId+")";
+ if (packageAdmin.getBundleType(fragmentBundle) != org.osgi.service.packageadmin.PackageAdmin.BUNDLE_TYPE_FRAGMENT) {
+ log(ILogger.ERROR, "Required fragment " + fragId + " is not a fragment" + aspectBindingHint);
+ hasError = true;
+ continue;
+ }
+ Bundle[] hosts = packageAdmin.getHosts(fragmentBundle);
+ if (hosts == null || hosts.length == 0) {
+ if (fragmentBundle.getState() < Bundle.RESOLVED) {
+ log(ILogger.ERROR, "Required fragment " + fragId + " is not resolved" + aspectBindingHint);
+ hasError = true;
+ continue;
+ }
+ log(ILogger.ERROR, "Required fragment "+fragId+" has no host bundle"+aspectBindingHint);
+ hasError = true;
+ continue;
+ }
+ Bundle host = hosts[0];
+ if (!host.getSymbolicName().equals(baseBundleId)) {
+ log(ILogger.ERROR, "Required fragment "+fragId+" has wrong host "+host.getSymbolicName()+aspectBindingHint);
+ hasError = true;
+ }
+ }
+ return !hasError;
+ }
+
+ private static void addBindingForBaseBundle(String baseBundleId, AspectBinding binding) {
+ ArrayList<AspectBinding> bindingList = aspectBindingsByBasePlugin.get(baseBundleId);
+ if (bindingList == null) {
+ bindingList = new ArrayList<AspectBinding>();
+ aspectBindingsByBasePlugin.put(baseBundleId, bindingList);
+ }
+ bindingList.add(binding);
+ }
+
+ private void addBindingForAspectBundle(String aspectBundleId, AspectBinding binding) {
+ ArrayList<AspectBinding> bindingList = aspectBindingsByAspectPlugin.get(aspectBundleId);
+ if (bindingList == null) {
+ bindingList = new ArrayList<AspectBinding>();
+ aspectBindingsByAspectPlugin.put(aspectBundleId, bindingList);
+ }
+ bindingList.add(binding);
+ if (binding.basePlugin.toUpperCase().equals(SELF))
+ selfAdaptingAspects.add(aspectBundleId);
+ }
+
+ /**
+ * Record a sub-class relationship of two teams within the same aspect bundle.
+ *
+ * @param aspectBundleId
+ * @param subTeamName (nullable only until we have JSR 308)
+ * @param teamName
+ */
+ private void addSubTeam(String aspectBundleId, @Nullable String subTeamName, String teamName) {
+ ArrayList<AspectBinding> bindingList = aspectBindingsByAspectPlugin.get(aspectBundleId);
+ if (bindingList == null) {
+ Exception e = new Exception("No such aspect binding");
+ log(e, "Class "+teamName+" not registered (declared to be superclass of team "+subTeamName);
+ } else {
+ for (AspectBinding binding : bindingList)
+ if (binding.teamClasses != null)
+ for (int i=0; i < binding.teamClasses.length; i++)
+ if (binding.teamClasses[i].equals(teamName)) {
+ if (binding.subTeamClasses[i] == null)
+ binding.subTeamClasses[i] = new ArrayList<String>();
+ binding.subTeamClasses[i].add(subTeamName);
+ return;
+ }
+ Exception e = new Exception("No such aspect binding");
+ log(e, "Class "+teamName+" not registered(2) (declared to be superclass of team "+subTeamName);
+ }
+ }
+
+ /**
+ * Given a potential aspect bundle, answer the symbolic names of all base bundles
+ * adapted by the aspect bundle.
+ */
+ public @Nullable String[] getAdaptedBasePlugins(Bundle aspectBundle) {
+ ArrayList<AspectBinding> bindings = aspectBindingsByAspectPlugin.get(aspectBundle.getSymbolicName());
+ if (bindings == null) return null;
+ String[] basePlugins = new String[bindings.size()];
+ for (int i=0; i<basePlugins.length; i++) {
+ basePlugins[i] = bindings.get(i).basePlugin;
+ }
+ return basePlugins;
+ }
+
+ /** Is `symbolicName' the name of a base plugin for which an adapting team is registered? */
+ public boolean isAdaptedBasePlugin(@Nullable String symbolicName) {
+ ArrayList<AspectBinding> list = aspectBindingsByBasePlugin.get(symbolicName);
+ return list != null && !list.isEmpty();
+ }
+
+ /**
+ * Get the list of aspect bindings affecting the given base plugin.
+ */
+ public @Nullable List<AspectBinding> getAdaptingAspectBindings(@Nullable String basePluginName) {
+ return aspectBindingsByBasePlugin.get(basePluginName);
+ }
+
+ /** Check if the given base bundle / base class mandate any loading/instantiation/activation of teams. */
+ public void triggerLoadingHooks(@Nullable String bundleName, @Nullable WovenClass baseClass) {
+ BaseBundleLoadTrigger activation = baseTripWires.get(bundleName);
+ if (activation != null) {
+ if (activation.fire(baseClass, beingDefined))
+ baseTripWires.remove(bundleName);
+ }
+ }
+
+ /** Record the given team classes as waiting for instantiation/activation. */
+ public void addDeferredTeamClasses(List<WaitingTeamRecord> teamClasses) {
+ synchronized (deferredTeams) {
+ deferredTeams.addAll(teamClasses);
+ }
+ }
+
+ /**
+ * Try to instantiate/activate any deferred teams that may be unblocked
+ * by the definition of the given trigger class.
+ */
+ public void instantiateScheduledTeams(String triggerClassName) {
+ List<WaitingTeamRecord> scheduledTeams = null;
+ synchronized(deferredTeams) {
+ for (WaitingTeamRecord record : new ArrayList<>(deferredTeams)) {
+ if (record.notFoundClass.equals(triggerClassName)) {
+ if (scheduledTeams == null)
+ scheduledTeams = new ArrayList<>();
+ if (deferredTeams.remove(record))
+ scheduledTeams.add(record);
+ }
+ }
+ }
+ if (scheduledTeams == null) return;
+ for(WaitingTeamRecord record : scheduledTeams) {
+ log(IStatus.INFO, "Consider for instantiation/activation: team "+record.getTeamName());
+ try {
+ new TeamLoader(deferredTeams, beingDefined).instantiateWaitingTeam(record); // may re-insert to deferredTeams
+ } catch (Exception e) {
+ log(e, "Failed to instantiate team "+record.getTeamName());
+ continue;
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
new file mode 100644
index 0000000..958f310
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
@@ -0,0 +1,84 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2013 GK Software AG
+ *
+ * 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
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.State;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.hooks.weaving.WovenClass;
+
+/**
+ * Each instance of this class represents the fact that a given base bundle has aspect bindings,
+ * which require to load / instantiate / activate one or more teams at a suitable point in time.
+ */
+public class BaseBundleLoadTrigger {
+
+ private AspectBindingRegistry aspectBindingRegistry;
+ @SuppressWarnings("deprecation")
+ private org.osgi.service.packageadmin.PackageAdmin admin;
+
+ private String baseBundleName;
+
+ public BaseBundleLoadTrigger(String bundleSymbolicName, AspectBindingRegistry aspectBindingRegistry,
+ @SuppressWarnings("deprecation") org.osgi.service.packageadmin.PackageAdmin admin)
+ {
+ this.baseBundleName = bundleSymbolicName;
+ this.aspectBindingRegistry = aspectBindingRegistry;
+ this.admin = admin;
+ }
+
+ /**
+ * Signal that the given class is being loaded and trigger any necessary steps:
+ * - scan team & add reverse imports (now)
+ * - load & instantiate & activate (now or later).
+ */
+ public boolean fire(WovenClass baseClass, Set<String> beingDefined) {
+ List<AspectBindingRegistry.WaitingTeamRecord> deferredTeamClasses = new ArrayList<>();
+ List<AspectBinding> aspectBindings = aspectBindingRegistry.getAdaptingAspectBindings(baseBundleName);
+ boolean allDone = true;
+ if (aspectBindings != null) {
+ for (AspectBinding aspectBinding : aspectBindings) {
+ if (aspectBinding.state == State.Initial)
+ log(IStatus.INFO, "Preparing aspect binding for base bundle "+baseBundleName);
+ if (aspectBinding.state == State.TeamsActivated)
+ continue;
+ @SuppressWarnings("deprecation")
+ Bundle[] aspectBundles = admin.getBundles(aspectBinding.aspectPlugin, null);
+ if (aspectBundles == null || aspectBundles.length == 0) {
+ log(IStatus.ERROR, "Cannot find aspect bundle "+aspectBinding.aspectPlugin);
+ continue;
+ }
+ Bundle aspectBundle = aspectBundles[0];
+ if (aspectBinding.state != State.TeamsScanned)
+ aspectBinding.scanTeamClasses(aspectBundle);
+ TeamLoader loading = new TeamLoader(deferredTeamClasses, beingDefined);
+ if (!loading.loadTeamsForBase(aspectBundle, aspectBinding, baseClass))
+ allDone = false;
+ }
+ if (!deferredTeamClasses.isEmpty()) {
+ aspectBindingRegistry.addDeferredTeamClasses(deferredTeamClasses);
+ return false;
+ }
+ }
+ return allDone;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java
new file mode 100644
index 0000000..f8ef150
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java
@@ -0,0 +1,147 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2008, 2013 Technical University Berlin, Germany 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
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer;
+import org.eclipse.objectteams.otre.util.CallinBindingManager;
+import org.osgi.framework.Bundle;
+
+/**
+ * Simple facility for scanning class files for OT Attributes without
+ * actually doing any weaving.
+ *
+ * @author stephan
+ * @since 1.2.0
+ */
+@SuppressWarnings("nls")
+public class ClassScanner
+{
+ // default is "on", leave this switch for trouble shooting and profiling:
+ public static final boolean REPOSITORY_USE_RESOURCE_LOADER = !"off".equals(System.getProperty("otequinox.repository.hook"));
+
+ // collect class names recorded by readOTAttributes:
+
+ // * this version used by the MasterTeamLoader.loadTeams:
+ HashMap<String,ArrayList<String>> baseClassNamesByTeam = new HashMap<String, ArrayList<String>>();
+ // * these fields used by TransformerHook.processClass (collected over multiple readOTAttributes):
+ ArrayList<String> allBaseClassNames = new ArrayList<String>();
+ ArrayList<String> roleClassNames = new ArrayList<String>();
+
+
+ /**
+ * Read all OT byte code attributes for the specified class.
+ * While doing so the names of roles and adapted base classes are collected.
+ *
+ * @param bundle where to look
+ * @param className the class to investigate (team or role)
+ * @param loader the loader (could be null) to use for further classFile lookup
+ * @return the real class name (potentially involving '$' and '__OT__' substitution/insertion
+ * @throws ClassFormatError
+ * @throws IOException
+ * @throws ClassNotFoundException the team or role class was not found
+ */
+ public String readOTAttributes(Bundle bundle, String className)
+ throws ClassFormatError, IOException, ClassNotFoundException
+ {
+ Object loader = REPOSITORY_USE_RESOURCE_LOADER ? bundle : null;
+ Pair<URL,String> result = TeamLoader.findTeamClassResource(className, bundle);
+ if (result == null)
+ throw new ClassNotFoundException(className);
+ URL classFile = result.first;
+ className = result.second;
+ ObjectTeamsTransformer transformer = new ObjectTeamsTransformer();
+ try (InputStream inputStream = classFile.openStream()) {
+ transformer.readOTAttributes(inputStream, classFile.getFile(), loader);
+ }
+ Collection<String> currentBaseNames = transformer.fetchAdaptedBases(); // destructive read
+ if (currentBaseNames != null) {
+ // store per team:
+ ArrayList<String> basesPerTeam = this.baseClassNamesByTeam.get(className);
+ if (basesPerTeam == null) {
+ basesPerTeam = new ArrayList<String>();
+ this.baseClassNamesByTeam.put(className, basesPerTeam);
+ }
+ basesPerTeam.addAll(currentBaseNames);
+ // accumulated store:
+ allBaseClassNames.addAll(currentBaseNames);
+ }
+ readMemberTypeAttributes(bundle, className, transformer);
+ return className;
+ }
+
+ /**
+ * Get the names of the base classes adapted by the given team and
+ * encountered while reading the byte code attributes.
+ * (Destructive read).
+ */
+ public Collection<String> getCollectedBaseClassNames(String teamName) {
+ return this.baseClassNamesByTeam.remove(teamName);
+ }
+
+ /**
+ * Get the names of all adapted base classes encountered while reading the byte code attributes.
+ * (Destructive read).
+ */
+ public Collection<String> getCollectedBaseClassNames() {
+ try {
+ return this.allBaseClassNames;
+ } finally {
+ this.allBaseClassNames = new ArrayList<String>();
+ }
+ }
+
+ /**
+ * Get the names of all member roles encountered while reading the byte code attributes.
+ * (Destructive read).
+ */
+ public Collection<String> getCollectedRoleClassNames() {
+ return this.roleClassNames;
+ }
+
+ /*
+ * Recurse into member types scanning OT attributes.
+ */
+ private void readMemberTypeAttributes(Bundle bundle,
+ String className,
+ ObjectTeamsTransformer transformer)
+ {
+ List<String> roles = CallinBindingManager.getRolePerTeam(className);
+ if (roles != null) {
+ for (String roleName: roles) {
+ log(ILogger.OK, "scanning role "+roleName);
+ try {
+ this.roleClassNames.add(roleName);
+ readOTAttributes(bundle, roleName);
+ } catch (Throwable t) {
+ log(t, "Failed to read OT-Attributes of role "+roleName);
+ }
+ readMemberTypeAttributes(bundle, roleName, transformer);
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Logger.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Logger.java
new file mode 100644
index 0000000..7ee6979
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Logger.java
@@ -0,0 +1,80 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2007, 2013 Fraunhofer Gesellschaft, Munich, Germany,
+ * for its Fraunhofer Institute for Computer Architecture and Software
+ * Technology (FIRST), Berlin, Germany and Technical University Berlin,
+ * Germany, 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
+ *
+ * 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.internal.osgi.weaving;
+
+import org.eclipse.objectteams.otequinox.hook.HookConfigurator;
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.eclipse.osgi.framework.log.FrameworkLog;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+
+
+/**
+ * Log either to console or - as soon as it is initialized - via the TransformerPlugin.
+ *
+ * @author stephan
+ * @since OTDT 1.1.4
+ */
+public class Logger implements ILogger
+{
+ private FrameworkLog fwLog;
+
+ public Logger(FrameworkLog fwLog) {
+ this.fwLog = fwLog;
+ }
+
+ public void log(Throwable t, String msg) {
+ log(HookConfigurator.class.getPackage().getName(), t, msg);
+ }
+ public void log(String pluginID, Throwable t, String msg) {
+ if (this.fwLog != null) {
+ this.fwLog.log(new FrameworkLogEntry(pluginID, FrameworkLogEntry.ERROR, 0, msg, 0, t, null));
+ return;
+ } else {
+ // no success logging, print to console instead:
+ System.err.println("OT/Equinox: "+msg); //$NON-NLS-1$
+ t.printStackTrace();
+ }
+ }
+
+ public void log(int status, String msg) {
+ if (status >= Util.WARN_LEVEL)
+ doLog(HookConfigurator.class.getPackage().getName(), status, msg);
+ }
+ public void log(String pluginID, int status, String msg) {
+ if (status >= Util.WARN_LEVEL)
+ doLog(pluginID, status, msg);
+ }
+
+ public void doLog(int status, String msg) {
+ doLog(HookConfigurator.class.getPackage().getName(), status, msg);
+ }
+ public void doLog(String pluginID, int status, String msg) {
+ if (this.fwLog != null) {
+ this.fwLog.log(new FrameworkLogEntry(pluginID, status, 0, msg, 0, null, null));
+ } else {
+ // no success logging, print to console instead:
+ msg = "OT/Equinox: "+msg; //$NON-NLS-1$
+ if ((status & ERROR) != 0)
+ System.err.println(msg);
+ else
+ System.out.println(msg);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
new file mode 100644
index 0000000..656530c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
@@ -0,0 +1,141 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2013 GK Software AG
+ *
+ * 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
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.objectteams.otequinox.TransformerPlugin;
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.hooks.weaving.WovenClass;
+import org.osgi.framework.hooks.weaving.WovenClassListener;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.component.ComponentContext;
+
+
+/**
+ * This class integrates the OT/J weaver into OSGi using the standard API {@link WeavingHook}.
+ * <p>
+ * Additionally, we listen to events of woven classes changing to state {@link WovenClass#DEFINED}:
+ * </p>
+ * <ul>
+ * <li>Given that {@link AspectBindingRegistry#addDeferredTeamClasses} was used to record
+ * teams that could not be instantiated due to some required class being reported
+ * as {@link NoClassDefFoundError}.</li>
+ * <li>Assuming further that this error happened because the required class was in the process
+ * of being loaded further down the call stack.</li>
+ * <li>If later one of the not-found classes has been defined we use that trigger to
+ * re-attempt instantiating the dependent team(s).</li>
+ * </ul>
+ */
+public class OTWeavingHook implements WeavingHook, WovenClassListener {
+
+ private AspectBindingRegistry aspectBindingRegistry;
+
+ @NonNull Set<String> beingDefined = new HashSet<>(); // shared with AspectBindingRegistry!
+
+
+ /** Call-back from DS framework. */
+ public void activate(ComponentContext context) {
+ this.aspectBindingRegistry = loadAspectBindingRegistry(context.getBundleContext());
+ TransformerPlugin.getDefault().registerAspectBindingRegistry(this.aspectBindingRegistry);
+ }
+
+ @SuppressWarnings("deprecation")
+ private AspectBindingRegistry loadAspectBindingRegistry(BundleContext context) {
+ org.osgi.service.packageadmin.PackageAdmin packageAdmin = null;;
+
+ ServiceReference<?> ref= context.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
+ if (ref!=null)
+ packageAdmin = (org.osgi.service.packageadmin.PackageAdmin)context.getService(ref);
+ else
+ log(ILogger.ERROR, "Failed to load PackageAdmin service. Will not be able to handle fragments.");
+
+ AspectBindingRegistry aspectBindingRegistry = new AspectBindingRegistry(this.beingDefined);
+ aspectBindingRegistry.loadAspectBindings(packageAdmin);
+ return aspectBindingRegistry;
+ }
+
+ @Override
+ public void weave(WovenClass wovenClass) {
+ beingDefined.add(wovenClass.getClassName());
+
+ try {
+ BundleWiring bundleWiring = wovenClass.getBundleWiring();
+ String bundleName = bundleWiring.getBundle().getSymbolicName();
+ String className = wovenClass.getClassName();
+
+ // do whatever is needed *before* loading this class:
+ aspectBindingRegistry.triggerLoadingHooks(bundleName, wovenClass);
+
+ if (requiresWeaving(bundleWiring)) {
+ ObjectTeamsTransformer transformer = new ObjectTeamsTransformer();
+ Class<?> classBeingRedefined = null; // TODO
+ ProtectionDomain protectionDomain = wovenClass.getProtectionDomain();
+ byte[] bytes = wovenClass.getBytes();
+ try {
+ log(IStatus.OK, "About to transform class "+className);
+ byte[] newBytes = transformer.transform(bundleWiring.getBundle(),
+ className, classBeingRedefined, protectionDomain, bytes);
+ if (newBytes != bytes && !Arrays.equals(newBytes, bytes)) {
+ log(IStatus.INFO, "Transformation performed on "+className);
+ wovenClass.setBytes(newBytes);
+ if (otreAdded.add(bundleWiring.getBundle())) {
+ log(IStatus.INFO, "Adding OTRE import to "+bundleName);
+ List<String> imports = wovenClass.getDynamicImports();
+ imports.add("org.objectteams");
+ }
+ }
+ } catch (IllegalClassFormatException e) {
+ log(e, "Failed to transform class "+className);
+ }
+ }
+ } catch (ClassCircularityError cce) {
+ log(cce, "Weaver encountered a circular class dependency");
+ }
+ }
+
+ Set<Bundle> otreAdded = new HashSet<>();
+ @Override
+ public void modified(WovenClass wovenClass) {
+ if (wovenClass.getState() == WovenClass.DEFINED) {
+ beingDefined.remove(wovenClass.getClassName());
+ @SuppressWarnings("null") @NonNull String className = wovenClass.getClassName();
+ aspectBindingRegistry.instantiateScheduledTeams(className);
+ }
+ }
+
+ private boolean requiresWeaving(BundleWiring bundleWiring) {
+ @SuppressWarnings("null")@NonNull
+ Bundle bundle = bundleWiring.getBundle();
+ return aspectBindingRegistry.getAdaptedBasePlugins(bundle) != null
+ || aspectBindingRegistry.isAdaptedBasePlugin(bundle.getSymbolicName());
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Pair.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Pair.java
new file mode 100644
index 0000000..947c35d
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Pair.java
@@ -0,0 +1,25 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2013 GK Software AG
+ *
+ * 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
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+class Pair<A, B> {
+ public A first;
+ public B second;
+ public Pair(A first, B second) {
+ this.first = first;
+ this.second = second;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
new file mode 100644
index 0000000..99ef94a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
@@ -0,0 +1,236 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2013 GK Software AG
+ *
+ * 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
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBindingRegistry.WaitingTeamRecord;
+import org.eclipse.objectteams.otequinox.ActivationKind;
+import org.eclipse.objectteams.otequinox.TransformerPlugin;
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.objectteams.Team;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.hooks.weaving.WovenClass;
+
+/**
+ * This class triggers the actual loading/instantiation/activation of teams.
+ * <p>
+ * It implements a strategy of deferring those teams where instantiation/activation
+ * failed (NoClassDefFoundError), which assumably happens, if one required class
+ * cannot be loaded, because its loading is already in progress further down in
+ * our call stack.
+ * </p><p>
+ * Which teams participate in deferred instantiation is communicated via the list
+ * {@link #deferredTeams}.
+ * </p>
+ */
+public class TeamLoader {
+
+ private List<WaitingTeamRecord> deferredTeams;
+
+ /** did we record the fact that a team needs deferring? */
+ boolean needDeferring;
+
+ private Set<String> beingDefined;
+
+ public TeamLoader(List<WaitingTeamRecord> deferredTeams, Set<String> beingDefined) {
+ this.deferredTeams = deferredTeams;
+ this.beingDefined = beingDefined;
+ }
+
+ /**
+ * Team loading, 1st attempt before the base class is even loaded
+ * Trying to do these phases load/instantiate/activate,
+ * and also adds a reverse import to the base.
+ */
+ public boolean loadTeamsForBase(Bundle aspectBundle, AspectBinding aspectBinding, WovenClass baseClass) {
+ Collection<String> teamsForBase = aspectBinding.getTeamsForBase(baseClass.getClassName());
+ if (teamsForBase == null) return false;
+ List<String> imports = baseClass.getDynamicImports();
+ for (String teamForBase : teamsForBase) {
+ // Add dependency:
+ String packageOfTeam = "";
+ int dot = teamForBase.lastIndexOf('.');
+ if (dot != -1)
+ packageOfTeam = teamForBase.substring(0, dot);
+ imports.add(packageOfTeam);
+ log(IStatus.INFO, "Added dependency from base "+baseClass.getClassName()+" to package '"+packageOfTeam+"'");
+ // Load:
+ Class<? extends Team> teamClass;
+ teamClass = findTeamClass(teamForBase, aspectBundle);
+ if (teamClass == null) {
+ log(new ClassNotFoundException("Not found: "+teamForBase), "Failed to load team "+teamForBase);
+ continue;
+ }
+ // Instantiate?
+ ActivationKind activationKind = aspectBinding.getActivation(teamForBase);
+ if (activationKind == ActivationKind.NONE)
+ continue;
+ Team teamInstance = instantiateTeam(aspectBinding, teamClass, teamForBase);
+ if (teamInstance == null)
+ continue;
+ // Activate?
+ activateTeam(aspectBinding, teamForBase, teamInstance, activationKind);
+ }
+ return true;
+ }
+
+ /** Team loading, subsequent attempts. */
+ public void instantiateWaitingTeam(WaitingTeamRecord record)
+ throws InstantiationException, IllegalAccessException
+ {
+ Team teamInstance = record.teamInstance;
+ String teamName = record.getTeamName();
+ if (teamInstance == null) {
+ // Instantiate (we only get here if activationKind != NONE)
+ teamInstance = instantiateTeam(record.aspectBinding, record.teamClass, teamName);
+ if (teamInstance == null)
+ return;
+ }
+ // Activate?
+ ActivationKind activationKind = record.aspectBinding.getActivation(teamName);
+ activateTeam(record.aspectBinding, teamName, teamInstance, activationKind);
+ }
+
+ public static Pair<URL,String> findTeamClassResource(String className, Bundle bundle) {
+ for (String candidate : possibleTeamNames(className)) {
+ URL result = bundle.getResource(candidate.replace('.', '/')+".class");
+ if (result != null)
+ return new Pair<>(result, candidate);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Class<? extends Team> findTeamClass(String className, Bundle bundle) {
+ for (String candidate : possibleTeamNames(className)) {
+ try {
+ Class<?> result = bundle.loadClass(candidate);
+ if (result != null)
+ return (Class<? extends Team>) result;
+ } catch (NoClassDefFoundError|ClassNotFoundException e) {
+ // keep looking
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Starting from currentName compute a list of potential binary names of (nested) teams
+ * using "$__OT__" as the separator, to find class parts of nested teams.
+ */
+ public static List<String> possibleTeamNames(String currentName) {
+ List<String> result = new ArrayList<String>();
+ result.add(currentName);
+ char sep = '.'; // assume source name
+ if (currentName.indexOf('$') > -1)
+ // binary name
+ sep = '$';
+ int from = currentName.length()-1;
+ while (true) {
+ int pos = currentName.lastIndexOf(sep, from);
+ if (pos == -1)
+ break;
+ String prefix = currentName.substring(0, pos);
+ String postfix = currentName.substring(pos+1);
+ if (sep=='$') {
+ if (!postfix.startsWith("__OT__"))
+ result.add(0, currentName = prefix+"$__OT__"+postfix);
+ } else {
+ // heuristic:
+ // only replace if parent element looks like a class (expected to start with uppercase)
+ int prevDot = prefix.lastIndexOf('.');
+ if (prevDot > -1 && Character.isUpperCase(prefix.charAt(prevDot+1)))
+ result.add(0, currentName = prefix+"$__OT__"+postfix);
+ else
+ break;
+ }
+ from = pos-1;
+ }
+ return result;
+ }
+
+ private @Nullable Team instantiateTeam(AspectBinding aspectBinding, Class<? extends Team> teamClass, String teamName) {
+ // don't try to instantiate before all base classes successfully loaded.
+ if (!isReadyToLoad(aspectBinding, teamClass, null, teamName))
+ return null;
+
+ try {
+ Team instance = teamClass.newInstance();
+ TransformerPlugin.registerTeamInstance(instance);
+ log(ILogger.INFO, "Instantiated team "+teamName);
+ return instance;
+ } catch (NoClassDefFoundError ncdfe) {
+ needDeferring = true;
+ synchronized(deferredTeams) {
+ deferredTeams.add(new WaitingTeamRecord(teamClass, aspectBinding, ncdfe.getMessage().replace('/','.')));
+ }
+ } catch (Throwable e) {
+ // application error during constructor execution?
+ log(e, "Failed to instantiate team "+teamName);
+ }
+ return null;
+ }
+
+ private void activateTeam(AspectBinding aspectBinding, String teamName, Team teamInstance, ActivationKind activationKind)
+ {
+ // don't try to activate before all base classes successfully loaded.
+ if (!isReadyToLoad(aspectBinding, teamInstance.getClass(), teamInstance, teamName))
+ return;
+ // good to go, so go:
+ try {
+ switch (activationKind) {
+ case ALL_THREADS:
+ teamInstance.activate(Team.ALL_THREADS);
+ log(IStatus.INFO, "Activated team "+teamName);
+ break;
+ case THREAD:
+ teamInstance.activate();
+ log(IStatus.INFO, "Activated team "+teamName);
+ break;
+ //$CASES-OMITTED$
+ default:
+ break;
+ }
+ } catch (Throwable t) {
+ // application errors during activation
+ log(t, "Failed to activate team "+teamName);
+ }
+ }
+ boolean isReadyToLoad(AspectBinding aspectBinding, Class<? extends Team> teamClass, Team teamInstance, String teamName) {
+ for (String baseclass : aspectBinding.basesPerTeam.get(teamName)) {
+ if (this.beingDefined.contains(baseclass)) {
+ synchronized (deferredTeams) {
+ WaitingTeamRecord record = teamInstance != null
+ ? new WaitingTeamRecord(teamInstance, aspectBinding, baseclass)
+ : new WaitingTeamRecord(teamClass, aspectBinding, baseclass);
+ deferredTeams.add(record); // TODO(SH): synchronization, deadlock?
+ }
+ log(IStatus.INFO, "Defer instantation/activation of team "+teamName);
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Util.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Util.java
new file mode 100644
index 0000000..ff85099
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/Util.java
@@ -0,0 +1,123 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany,
+ * for its Fraunhofer Institute for Computer Architecture and Software
+ * Technology (FIRST), Berlin, Germany and Technical University Berlin,
+ * Germany.
+ *
+ * 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
+ * $Id: Util.java 23461 2010-02-04 22:10:39Z stephan $
+ *
+ * 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.internal.osgi.weaving;
+
+import java.util.HashSet;
+import static org.eclipse.core.runtime.IStatus.*;
+
+public class Util
+{
+
+ // configure OT/Equinox debugging:
+ public static int WARN_LEVEL = INFO;
+ public static boolean PROFILE= false;
+ static {
+ String level = System.getProperty("otequinox.debug"); //$NON-NLS-1$
+ if (level != null) {
+ level = level.toUpperCase();
+ if (level.equals("OK")) //$NON-NLS-1$
+ WARN_LEVEL = OK;
+ else if (level.equals("INFO")) //$NON-NLS-1$
+ WARN_LEVEL = INFO;
+ else if (level.startsWith("WARN")) //$NON-NLS-1$
+ WARN_LEVEL = WARNING;
+ else if (level.startsWith("ERR")) //$NON-NLS-1$
+ WARN_LEVEL = ERROR;
+ else
+ WARN_LEVEL = OK;
+ }
+ PROFILE= (System.getProperty("otequinox.profile") != null); //$NON-NLS-1$
+ }
+
+ /** Profiling data: */
+ enum ProfileKind { BaseTransformation, AspectTransformation, SuperClassFetching }
+ private static long[] profileTimes= new long[ProfileKind.values().length];
+ private static long systemStartTime= System.nanoTime();
+
+ static HashSet<String> PLATFORM_BUNDLES = null;
+
+ @SuppressWarnings("nls")
+ private static void checkInit() {
+ if (PLATFORM_BUNDLES == null) {
+ PLATFORM_BUNDLES = new HashSet<String>();
+ // FIXME: reconsider:
+ for (String bundle : new String[] { "org.eclipse.equinox.common",
+ "org.eclipse.update.configurator",
+ "org.eclipse.core.runtime",
+ "org.eclipse.equinox.registry",
+ "org.eclipse.equinox.app",
+ "org.eclipse.equinox.ds",
+ "org.eclipse.equinox.event",
+ "org.eclipse.equinox.util",
+ "org.eclipse.osgi.services",
+ "org.eclipse.core.runtime.compatibility.auth",
+ "org.eclipse.equinox.preferences",
+ "org.eclipse.equinox.simpleconfigurator",
+ "org.eclipse.core.jobs",
+ "org.eclipse.core.runtime.compatibility",
+ "org.eclipse.equinox.p2.core",
+ "org.eclipse.equinox.p2.reconciler.dropins",
+ "org.eclipse.equinox.p2.directorywatcher",
+ "org.eclipse.ecf",
+ "org.eclipse.ecf.identity",
+ "org.eclipse.ecf.filetransfer",
+ "org.eclipse.ecf.provider.filetransfer",
+ "org.eclipse.ecf.provider.filetransfer.httpclient",
+ "org.apache.commons.httpclient",
+ // for Eclipse 4.x:
+ "org.eclipse.swt",
+ "org.eclipse.e4.ui.css.core",
+ "org.eclipse.e4.ui.css.swt.theme",
+ "org.eclipse.core.contenttype"
+ })
+ PLATFORM_BUNDLES.add(bundle);
+ }
+ }
+
+ static boolean isPlatformBundle(String bundleName) {
+ checkInit();
+ return PLATFORM_BUNDLES.contains(bundleName);
+ }
+
+ @SuppressWarnings("nls")
+ public static void profile(long startTime, ProfileKind kind, String msg, Logger logger)
+ {
+ long now= System.nanoTime();
+ long delta= (now-startTime) / getActiveCount();
+ long total= (profileTimes[kind.ordinal()]+= delta);
+ msg = msg.substring(msg.lastIndexOf('.')+1);
+ logger.doLog(INFO, "Profile "+kind.name()+": "+m(delta)+"("+m(total)+"/"+m(now-systemStartTime)+") ["+msg+"]");
+ }
+ // nano-to milli conversion
+ private static double m(long l) {
+ return (l/1000000.0);
+ }
+
+ private static int getActiveCount() {
+ ThreadGroup group= Thread.currentThread().getThreadGroup();
+ ThreadGroup parent= group.getParent();
+ while (parent != null) {
+ group= parent;
+ parent= group.getParent();
+ }
+ return group.activeCount();
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java
deleted file mode 100644
index 87b7c6e..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2009 Germany and Technical University Berlin, Germany.
- *
- * 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
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Technical University Berlin - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox;
-
-import org.eclipse.objectteams.otequinox.hook.AspectPermission;
-
-/**
- * Answer for an aspect binding request. See extension point org.eclipse.objectteams.otequinox.aspectBindingNegotiators.
- *
- * @author stephan
- * @since 1.2.6
- */
-public class AspectBindingRequestAnswer
-{
- /** Should this answer be remembered persistently? */
- public boolean persistent;
- /** Should this answer be applied to all subsequent requests? */
- public boolean allRequests;
- /** The actual answer. */
- public AspectPermission permission;
-
- /**
- * @param persistent Should this answer be remembered persistently?
- * @param allRequests Should this answer be applied to all subsequent requests?
- * @param permission One of DENY, GRANT, UNDEFINED (let others decide).
- */
- public AspectBindingRequestAnswer(boolean persistent, boolean allRequests, AspectPermission permission) {
- this.persistent = persistent;
- this.allRequests = allRequests;
- this.permission = permission;
- }
-
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
new file mode 100644
index 0000000..0fc118a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
@@ -0,0 +1,67 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2007, 2009 Technical University Berlin, Germany.
+ *
+ * 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
+ *
+ * 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.otequinox;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.osgi.framework.Bundle;
+
+/**
+ * This slice of the IOTEquinoxService provides features to query the
+ * registry of aspectBindings.
+ *
+ * @author stephan
+ * @since OTDT 1.1.4
+ */
+public interface IAspectRegistry {
+
+ /** Are we running within the OTDT? */
+ public boolean isOTDT();
+
+ /** Is `symbolicName' the name of a base plugin for which an adapting team is registered? */
+ public boolean isAdaptedBasePlugin(String baseBundleName);
+
+ /**
+ * Get the names of aspect plugins adapting a given base plugin.
+ * @param basePlugin base plugin.
+ * @return non-null array of symbolic names of aspect plugins.
+ */
+ public @NonNull String[] getAdaptingAspectPlugins(Bundle baseBundle);
+
+ /**
+ * Get the plugin IDs of all base plugins adapted by this aspect plugin.
+ * If this plugin is not an aspect plugin return null.
+ * @param aspectBundle potential aspect plugin
+ * @return array of base plugin IDs or null.
+ */
+ public @Nullable String[] getAdaptedBasePlugins(Bundle aspectBundle);
+
+ /**
+ * Does `bundle' have internal teams, i.e., teams that adapt classes from their
+ * enclosing plug-in only?
+ * @param bundle
+ * @return
+ */
+ public boolean hasInternalTeams(Bundle bundle);
+
+ /**
+ * Does the symbolic name refer to an aspect bundle for which some permission was denied?
+ * @param symbolicName
+ * @return
+ */
+ public boolean isDeniedAspectPlugin(String symbolicName);
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java
deleted file mode 100644
index 3e16c0d..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2009 Germany and Technical University Berlin, Germany.
- *
- * 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
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Technical University Berlin - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox;
-
-import org.eclipse.objectteams.otequinox.hook.AspectPermission;
-
-/**
- * Interface for extenders wishing to participate in negotiation about aspect binding requests
- * including forced exports.
- *
- * @author stephan
- * @since 1.2.6
- */
-public interface IAspectRequestNegotiator {
-
- /**
- * Check whether a request for forced exports should be granted.
- * @param aspectBundleSymbolicName the aspect issuing the request
- * @param baseBundleSymbolicName the affected base bundle
- * @param basePackage the affected base package
- * @param previousNegotiation the result of negotations up-to this point
- * @return a structure holding the answer, must not be null.
- */
- AspectBindingRequestAnswer checkForcedExport(String aspectBundleSymbolicName, String baseBundleSymbolicName, String basePackage, AspectPermission previousNegotiation);
-
- /**
- * Check whether a request for an aspect binding should be granted.
- * @param aspectBundleSymbolicName the aspect issuing the request
- * @param baseBundleSymbolicName the affected base bundle
- * @param teamClass an affecting team class involved in this aspect binding
- * @param previousNegotiation the result of negotations up-to this point
- * @return a structure holding the answer, must not be null.
- */
- AspectBindingRequestAnswer checkAspectBinding(String aspectBundleSymbolicName, String baseBundleSymbolicName, String teamClass, AspectPermission previousNegotiation);
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
index b4893f0..fe1001b 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
@@ -1,582 +1,76 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2004, 2010 Fraunhofer Gesellschaft, Munich, Germany,
- * for its Fraunhofer Institute for Computer Architecture and Software
- * Technology (FIRST), Berlin, Germany and Technical University Berlin,
- * Germany.
- *
- * 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
- *
- * 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.otequinox;
-import static org.eclipse.objectteams.otequinox.Constants.*;
+import static org.eclipse.objectteams.otequinox.Constants.TRANSFORMER_PLUGIN_ID;
-import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
import java.util.List;
-import java.util.Set;
-import org.eclipse.core.internal.runtime.InternalPlatform;
-import org.eclipse.core.runtime.IConfigurationElement; //from: org.eclipse.equinox.registry
-import org.eclipse.core.runtime.RegistryFactory;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.objectteams.otequinox.internal.ASMByteCodeAnalyzer;
-import org.eclipse.objectteams.otequinox.internal.AspectBinding;
-import org.eclipse.objectteams.otequinox.internal.AspectPermissionManager;
-import org.eclipse.objectteams.otequinox.internal.JobAndThreadListener;
-import org.eclipse.objectteams.otequinox.internal.MasterTeamLoader;
-import org.eclipse.objectteams.otequinox.internal.TransformerServiceDelegate;
-import org.eclipse.objectteams.otequinox.hook.ClassScanner;
-import org.eclipse.objectteams.otequinox.hook.HookConfigurator;
-import org.eclipse.objectteams.otequinox.hook.IAspectRegistry;
-import org.eclipse.objectteams.otequinox.hook.IByteCodeAnalyzer;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBindingRegistry;
import org.eclipse.objectteams.otequinox.hook.ILogger;
-import org.eclipse.objectteams.otequinox.hook.IOTEquinoxService;
-import org.eclipse.objectteams.otequinox.hook.IOTTransformer;
+import org.eclipse.objectteams.otre.ClassLoaderAccess;
+import org.objectteams.Team;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.packageadmin.PackageAdmin;
-/**
- * The main class (activator) of the transformer plugin.
- * It maintains the aspect registry of this plugin.
- * This class optionally uses {@link InternalPlatform} for the purpose of accessing the workspace location,
- * i.e., if this class is not found, no workspace location will be used.
- *
- * @author stephan
- */
-@SuppressWarnings("restriction") // accessing InternalPlatform
-public class TransformerPlugin implements BundleActivator, IOTEquinoxService
-{
- private static List<String> KNOWN_OTDT_ASPECTS = new ArrayList<String>();
- static {
- KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.jdt.ui");
- KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.compiler.adaptor");
- KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.refactoring");
- KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.pde.ui");
- KNOWN_OTDT_ASPECTS.add("org.eclipse.objectteams.otdt.samples");
- }
- /** main internal registry of aspect bindings. */
- private static HashMap<String, ArrayList<AspectBinding>> aspectBindingsByBasePlugin =
- new HashMap<String, ArrayList<AspectBinding>>();
- private static HashMap<String, ArrayList<AspectBinding>> aspectBindingsByAspectPlugin =
- new HashMap<String, ArrayList<AspectBinding>>();
- // map base bundle name to list of adapted base class names
- private static HashMap<String, ArrayList<String>> adaptedBaseClassNames =
- new HashMap<String, ArrayList<String>>();
- // set of aspect plug-ins which have internal teams:
- private Set<String> selfAdaptingAspects= new HashSet<String>();
-
- /** Aspect Permissions and Negotiation (delegate to dedicated manager). */
- private AspectPermissionManager permissionManager;
-
- /** The instance that is created by the framework. */
- private static TransformerPlugin instance;
- private ServiceRegistration<IOTEquinoxService> serviceRegistration;
- private ServiceRegistration<IOTTransformer> serviceRegistration2;
+public class TransformerPlugin implements BundleActivator, IAspectRegistry {
- /* unevaluated content of liftingParticipant extension: */
- private IConfigurationElement liftingParticipantConfig;
- /* Field of <code>org.objectteams.Team</code> holding a configured lifting participant: */
- private static final String LIFTING_PARTICIPANT_FIELD = "_OT$liftingParticipant";
+ private static BundleContext context;
- private ILogger log;
-
- /** instances which may have pending team classes waiting for instantiation. */
- private HashMap<Bundle,List<MasterTeamLoader>> masterTeamLoaders = new HashMap<Bundle, List<MasterTeamLoader>>();
-
- /** Service needed for handling fragments */
- private PackageAdmin packageAdmin;
-
- // note: actually List<Team> but Team cannot be mentioned in this plugin.
- private List<Object> teamInstances = new ArrayList<Object>();
-
- public static boolean IS_OTDT = false;
-
- public boolean isOTDT() {
- return IS_OTDT;
- }
-
- public TransformerPlugin() {
- instance = this;
- }
- public void start(BundleContext context) throws Exception {
- if (!HookConfigurator.OT_EQUINOX_ENABLED)
- throw new BundleException("Not starting the transformer plugin because OT/Equinox has not been enabled (set system property \"ot.equinox\").");
-
- this.log = HookConfigurator.getLogger();
- log(ILogger.INFO, "activating org.eclipse.objectteams.otequinox");
-
- ServiceReference<?> ref= context.getServiceReference(PackageAdmin.class.getName());
- if (ref!=null)
- this.packageAdmin = (PackageAdmin)context.getService(ref);
- else
- this.log(ILogger.ERROR, "Failed to load PackageAdmin service. Will not be able to handle fragments.");
-
- this.permissionManager = new AspectPermissionManager(this.log, context.getBundle(), this.packageAdmin);
- this.permissionManager.loadAspectBindingNegotiators(context);
- loadAspectBindings();
- loadLiftingParticipant();
- this.serviceRegistration = context.registerService(IOTEquinoxService.class, this, new Hashtable<String, Object>());
- this.serviceRegistration2 = context.registerService(IOTTransformer.class, new TransformerServiceDelegate(), new Hashtable<String, Object>());
- Job.getJobManager().addJobChangeListener(new JobAndThreadListener());
- }
-
- /* be a good citizen: clean up. */
- public void stop(BundleContext context) throws Exception {
- serviceRegistration.unregister();
- serviceRegistration2.unregister();
+ static BundleContext getContext() {
+ return context;
}
- public static TransformerPlugin getDefault() {
- return instance;
- }
+ private static ILog log;
+ private static TransformerPlugin plugin;
+
+ private AspectBindingRegistry aspectBindingRegistry;
+ private List<Team> teamInstances = new ArrayList<>();
- /** public API: Do we know about any team that has not yet been initiaized as requested? */
- public static boolean isWaitingForTeams() {
- synchronized (instance.masterTeamLoaders) {
- if (!instance.masterTeamLoaders.isEmpty())
- return true;
- }
- synchronized (aspectBindingsByBasePlugin) {
- for (ArrayList<AspectBinding> aspects : aspectBindingsByBasePlugin.values())
- for (AspectBinding aspectBinding : aspects)
- if (!aspectBinding.activated)
- return true;
- }
- return false;
- }
-
- /**
- * Internal API for TransformerHook:
- * see {@link IAspectRegistry#isDeniedAspectPlugin(String)}
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
- public boolean isDeniedAspectPlugin(String symbolicName) {
- return this.permissionManager.isDeniedAspectPlugin(symbolicName);
- }
-
- /* Load extensions for org.eclipse.objectteams.otequinox.aspectBindings and check aspect permissions. */
- private void loadAspectBindings() {
- IConfigurationElement[] aspectBindingConfigs = RegistryFactory.getRegistry().getConfigurationElementsFor(
- TRANSFORMER_PLUGIN_ID, ASPECT_BINDING_EXTPOINT_ID);
+ public void start(BundleContext bundleContext) throws Exception {
+ plugin = this;
+ TransformerPlugin.context = bundleContext;
- for (int i = 0; i < aspectBindingConfigs.length; i++) {
- IConfigurationElement currentBindingConfig = aspectBindingConfigs[i];
-
- //aspect:
- String aspectBundleId= currentBindingConfig.getContributor().getName();
- IS_OTDT |= KNOWN_OTDT_ASPECTS.contains(aspectBundleId);
- Bundle[] aspectBundles = packageAdmin.getBundles(aspectBundleId, null);
- if (aspectBundles == null || aspectBundles.length == 0 || (aspectBundles[0].getState() < Bundle.RESOLVED)) {
- log(ILogger.ERROR, "aspect bundle "+aspectBundleId+" is not resolved - not loading aspectBindings.");
- continue;
- }
-
- //base:
- IConfigurationElement[] basePlugins = currentBindingConfig.getChildren(BASE_PLUGIN);
- if (basePlugins.length != 1) {
- log(ILogger.ERROR, "aspectBinding of "+aspectBundleId+" must declare exactly one basePlugin");
- continue;
- }
- String baseBundleId = basePlugins[0].getAttribute(ID);
-
- //base fragments?
- IConfigurationElement[] fragments = basePlugins[0].getChildren(REQUIRED_FRAGMENT);
- if (fragments != null && !checkRequiredFragments(aspectBundleId, baseBundleId, fragments)) // reported inside
- continue;
-
- AspectBinding binding = new AspectBinding(aspectBundleId, baseBundleId, basePlugins[0].getChildren(Constants.FORCED_EXPORTS_ELEMENT));
- // TODO(SH): maybe enforce that every bundle id is given only once?
-
- //teams:
- IConfigurationElement[] teams = currentBindingConfig.getChildren(TEAM);
- binding.initTeams(teams.length);
- try {
- for (int j = 0; j < teams.length; j++) {
- String teamClass = teams[j].getAttribute(CLASS);
- binding.teamClasses[j] = teamClass;
- String activation = teams[j].getAttribute(ACTIVATION);
- binding.setActivation(j, activation);
- }
-
- String realBaseBundleId = baseBundleId.toUpperCase().equals(SELF) ? aspectBundleId : baseBundleId;
- addBindingForBaseBundle(realBaseBundleId, binding);
- addBindingForAspectBundle(aspectBundleId, binding);
-
- // now that binding.teamClasses is filled connect to super team, if requested:
- for (int j = 0; j < teams.length; j++) {
- String superTeamName = teams[j].getAttribute(SUPERCLASS);
- if (superTeamName != null)
- addSubTeam(aspectBundleId, binding.teamClasses[j], superTeamName);
- }
- log(ILogger.INFO, "registered:\n"+binding);
- } catch (Throwable t) {
- log(t, "Invalid aspectBinding extension");
- }
- }
- }
-
- private boolean checkRequiredFragments(String aspectBundleId, String baseBundleId, IConfigurationElement[] fragments)
- {
- // checking only, no real action needed.
- boolean hasError = false;
- for (IConfigurationElement fragment : fragments) {
- String fragId = fragment.getAttribute(ID);
- if (fragId == null) {
- log(ILogger.ERROR, "Mandatory attribute \"id\" missing from element \"requiredFragment\" of aspect binding in "+aspectBundleId);
- return false;
- }
- if (packageAdmin == null) {
- log(ILogger.ERROR, "Not checking required fragment "+fragId+" in aspect binding of "+aspectBundleId+", package admin service not present");
- return false; // report only once.
- }
-
- Bundle[] fragmentBundles = packageAdmin.getBundles(fragId, null);
- if (fragmentBundles == null || fragmentBundles.length == 0) {
- log(ILogger.ERROR, "Required fragment "+fragId+" not found in aspect binding of "+aspectBundleId);
- hasError = true;
- continue;
- }
- Bundle fragmentBundle = fragmentBundles[0];
- String aspectBindingHint = " (aspect binding of "+aspectBundleId+")";
- if (packageAdmin.getBundleType(fragmentBundle) != PackageAdmin.BUNDLE_TYPE_FRAGMENT) {
- log(ILogger.ERROR, "Required fragment " + fragId + " is not a fragment" + aspectBindingHint);
- hasError = true;
- continue;
- }
- Bundle[] hosts = packageAdmin.getHosts(fragmentBundle);
- if (hosts == null || hosts.length == 0) {
- if (fragmentBundle.getState() < Bundle.RESOLVED) {
- log(ILogger.ERROR, "Required fragment " + fragId + " is not resolved" + aspectBindingHint);
- hasError = true;
- continue;
- }
- log(ILogger.ERROR, "Required fragment "+fragId+" has no host bundle"+aspectBindingHint);
- hasError = true;
- continue;
- }
- Bundle host = hosts[0];
- if (!host.getSymbolicName().equals(baseBundleId)) {
- log(ILogger.ERROR, "Required fragment "+fragId+" has wrong host "+host.getSymbolicName()+aspectBindingHint);
- hasError = true;
- }
- }
- return !hasError;
- }
-
-
- private static void addBindingForBaseBundle(String baseBundleId, AspectBinding binding) {
- ArrayList<AspectBinding> bindingList = aspectBindingsByBasePlugin.get(baseBundleId);
- if (bindingList == null) {
- bindingList = new ArrayList<AspectBinding>();
- aspectBindingsByBasePlugin.put(baseBundleId, bindingList);
- }
- bindingList.add(binding);
- }
-
- private void addBindingForAspectBundle(String aspectBundleId, AspectBinding binding) {
- ArrayList<AspectBinding> bindingList = aspectBindingsByAspectPlugin.get(aspectBundleId);
- if (bindingList == null) {
- bindingList = new ArrayList<AspectBinding>();
- aspectBindingsByAspectPlugin.put(aspectBundleId, bindingList);
- }
- bindingList.add(binding);
- if (binding.basePlugin.toUpperCase().equals(SELF))
- selfAdaptingAspects.add(aspectBundleId);
- }
+ acquireLog(bundleContext);
- /**
- * Record a sub-class relationship of two teams within the same aspect bundle.
- *
- * @param aspectBundleId
- * @param subTeamName
- * @param teamName
- */
- private void addSubTeam(String aspectBundleId, String subTeamName, String teamName) {
- ArrayList<AspectBinding> bindingList = aspectBindingsByAspectPlugin.get(aspectBundleId);
- if (bindingList == null) {
- Exception e = new Exception("No such aspect binding");
- log(e, "Class "+teamName+" not registered (declared to be superclass of team "+subTeamName);
- } else {
- for (AspectBinding binding : bindingList)
- if (binding.teamClasses != null)
- for (int i=0; i < binding.teamClasses.length; i++)
- if (binding.teamClasses[i].equals(teamName)) {
- if (binding.subTeamClasses[i] == null)
- binding.subTeamClasses[i] = new ArrayList<String>();
- binding.subTeamClasses[i].add(subTeamName);
- return;
- }
- Exception e = new Exception("No such aspect binding");
- log(e, "Class "+teamName+" not registered(2) (declared to be superclass of team "+subTeamName);
- }
+ OTREInit();
}
- /* Load extension for org.eclipse.objectteams.otequinox.liftingParticipant. */
- private void loadLiftingParticipant() {
- IConfigurationElement[] liftingParticipantConfigs = RegistryFactory.getRegistry().getConfigurationElementsFor(
- TRANSFORMER_PLUGIN_ID, LIFTING_PARTICIPANT_EXTPOINT_ID);
-
- if (liftingParticipantConfigs.length != 1) {
- if (liftingParticipantConfigs.length > 1)
- log(ILogger.ERROR, "Cannot install more than one lifting participant.");
- return;
- }
- this.liftingParticipantConfig = liftingParticipantConfigs[0];
- // defer initialization until when o.o.Team is naturally being loaded.
- }
-
- /**
- * Callback to initialize class <code>org.objectteams.Team</code> after it has been loaded.
- * Here it is used to initialized a lifting participant if such an extension is defined.
- */
- public void initializeOOTeam(Class<?> ooTeam) {
- if (this.liftingParticipantConfig == null)
- return;
+ @SuppressWarnings("restriction")
+ private void acquireLog(BundleContext bundleContext) {
try {
- // can't directly access class Team in this plugin:
- Field participantField = ooTeam.getDeclaredField(TransformerPlugin.LIFTING_PARTICIPANT_FIELD);
-
- Object participantInstance = liftingParticipantConfig.createExecutableExtension(CLASS);
-
- participantField.set(null/*no target, field is static*/, participantInstance);
-
- log(ILogger.INFO, "registered lifting participant:\n\t"+participantInstance.getClass().getName());
-
- } catch (Throwable t) {
- log(t, "Invalid lifting participant extension");
+ TransformerPlugin.log = org.eclipse.core.internal.runtime.InternalPlatform.getDefault().getLog(bundleContext.getBundle());
+ } catch (NullPointerException npe) {
+ // WTF?
}
}
- /**
- * Internal API for TransformerHook:
- * see {@link IAspectRegistry#getAdaptedBasePlugins(Bundle)}
- */
- public String[] getAdaptedBasePlugins(Bundle aspectBundle) {
- ArrayList<AspectBinding> bindings = aspectBindingsByAspectPlugin.get(aspectBundle.getSymbolicName());
- if (bindings == null) return null;
- String[] basePlugins = new String[bindings.size()];
- for (int i=0; i<basePlugins.length; i++) {
- basePlugins[i] = bindings.get(i).basePlugin;
- }
- return basePlugins;
- }
-
- /** Is `symbolicName' the name of a base plugin for which an adapting team is registered? */
- public boolean isAdaptedBasePlugin(String symbolicName) {
- ArrayList<AspectBinding> list = aspectBindingsByBasePlugin.get(symbolicName);
- return list != null && !list.isEmpty();
- }
-
- /**
- * public API:
- * {@link IAspectRegistry#getAdaptingAspectPlugins(Bundle)}
- */
- public String[] getAdaptingAspectPlugins(Bundle basePlugin) {
- return getAdaptingAspectPlugins(basePlugin.getSymbolicName());
- }
- /**
- * public API:
- * Get the names of aspect plugins adapting a given base plugin.
- * @param basePluginName symbolic name of a base plugin.
- * @return non-null array of symbolic names of aspect plugins.
- */
- public String[] getAdaptingAspectPlugins(String basePluginName) {
- ArrayList<AspectBinding> list = aspectBindingsByBasePlugin.get(basePluginName);
-
- if (list == null)
- return new String[0];
-
- String[] aspects = new String[list.size()];
- for (int i=0; i< list.size(); i++)
- aspects[i] = list.get(i).aspectPlugin;
-
- return aspects;
- }
-
- /**
- * Recored the names of base classes adapted by a given team from a given aspect bundle.
- */
- public void storeAdaptedBaseClassNames(String aspectBundleName, String teamName, Collection<String> baseClassNames)
- {
- // search the base plugin being adapted by the given team:
- String basePlugin = null;
- bindings:
- for (AspectBinding aspectBinding : aspectBindingsByAspectPlugin.get(aspectBundleName)) {
- for (String aspectTeamClass : aspectBinding.teamClasses)
- if (aspectTeamClass.equals(teamName)) {
- basePlugin = aspectBinding.basePlugin;
- break bindings;
- }
- }
- if (basePlugin == null && selfAdaptingAspects.contains(aspectBundleName))
- basePlugin = aspectBundleName;
- if (basePlugin == null) {
- log(ILogger.ERROR, "Base plugin for team "+teamName+" from "+aspectBundleName+" not found!");
- return;
- }
- // merge base class names into existing:
- synchronized (adaptedBaseClassNames) {
- ArrayList<String> baseBundleClassNames = adaptedBaseClassNames.get(basePlugin);
- if (baseBundleClassNames == null) {
- baseBundleClassNames = new ArrayList<String>();
- adaptedBaseClassNames.put(basePlugin, baseBundleClassNames);
- }
- baseBundleClassNames.addAll(baseClassNames);
+ private void OTREInit() {
+ try {
+ ClassLoaderAccess.setLoadClass(Bundle.class.getMethod("loadClass", String.class));
+ ClassLoaderAccess.setGetResource(Bundle.class.getMethod("getResource", String.class));
+ } catch (NoSuchMethodException | SecurityException e) {
+ log(e, "Failed to wire an OSGi class into the OTRE");
}
}
- /**
- * Internal API for TransformerHook:
- * see {@link org.eclipse.objectteams.otequinox.hook.ITeamLoader#loadTeams(Bundle, IClassScanner)}
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
- public boolean loadTeams(Bundle baseBundle, ClassScanner classScanner) {
- ArrayList<AspectBinding> bindings = aspectBindingsByBasePlugin.get(baseBundle.getSymbolicName());
- return delegateToMasterTeamLoader(baseBundle, classScanner, bindings);
- }
-
- /**
- * Internal API for TransformerHook:
- * see {@link org.eclipse.objectteams.otequinox.hook.IAspectRegistry#hasInternalTeams(Bundle)}
- */
- public boolean hasInternalTeams(Bundle bundle) {
- return selfAdaptingAspects.contains(bundle.getSymbolicName());
- }
-
- /**
- * Internal API for TransformerHook:
- * see {@link org.eclipse.objectteams.otequinox.hook.ITeamLoader#loadInternalTeams(Bundle,ClassScanner)}
- */
- public boolean loadInternalTeams(Bundle bundle, ClassScanner scanner) {
- ArrayList<AspectBinding> selfBindings = new ArrayList<AspectBinding>();
- synchronized (aspectBindingsByAspectPlugin) {
- ArrayList<AspectBinding> bindings = aspectBindingsByAspectPlugin.get(bundle.getSymbolicName());
- if (bindings == null)
- return false;
- for (int i = 0; i < bindings.size(); )
- if (bindings.get(i).basePlugin.toUpperCase().equals(SELF))
- selfBindings.add(bindings.remove(i));
- else
- i++;
- }
- return delegateToMasterTeamLoader(bundle, scanner, selfBindings);
+ public void stop(BundleContext bundleContext) throws Exception {
+ TransformerPlugin.context = null;
}
- // this performs some work for load[Internal]Teams:
- // create®ister a MasterTeamLoader and use it for loading the teams.
- private boolean delegateToMasterTeamLoader(Bundle baseBundle,
- ClassScanner scanner,
- ArrayList<AspectBinding> bindings)
- {
- if (bindings == null || bindings.isEmpty())
- return false;
- MasterTeamLoader masterTeamLoader = new MasterTeamLoader(baseBundle);
- boolean success = masterTeamLoader.loadTeams(baseBundle, scanner, bindings);
- if (success)
- addMasterTeamLoader(baseBundle, masterTeamLoader);
- return success;
- }
-
- /**
- * Internal API for TransformerHook:
- * see {@link org.eclipse.objectteams.otequinox.hook.ITeamLoader#instantiateTeams(Bundle)}
- */
- public void instantiateTeams(Bundle baseBundle, String triggerClassname) {
- instance.internalInstantiateTeams(baseBundle, triggerClassname);
- }
-
- /** Add a master team loader which may hold a list of teams waiting for instantiation.
- */
- private void addMasterTeamLoader(Bundle baseBundle, MasterTeamLoader masterTeamLoader) {
- synchronized (this.masterTeamLoaders) {
- List<MasterTeamLoader> loaders = this.masterTeamLoaders.get(baseBundle);
- if (loaders == null) {
- loaders = new ArrayList<MasterTeamLoader>();
- this.masterTeamLoaders.put(baseBundle, loaders);
- }
- loaders.add(masterTeamLoader);
- }
- }
-
-
- /**
- * Instantiate all teams affecting the given base bundle. Don't, however, load the class who's loading
- * triggered this call.
- *
- * This method checks whether the AspectPermissionManager.isReady(). If not, defer instantiation and
- * return the set of all affected base classes for use as a trigger for deferred instantiation.
- *
- * @param baseBundle
- * @param triggerClassname if non-null: the name of a base class who's loading triggered this instantiation.
- */
- private void internalInstantiateTeams(Bundle baseBundle, String triggerClassname)
- {
- List<MasterTeamLoader> loaders = null;
- synchronized (this.masterTeamLoaders) {
- loaders= this.masterTeamLoaders.get(baseBundle);
- if (this.masterTeamLoaders.isEmpty() || loaders == null)
- return;
-
- // check permission for forcedExports of all adapting aspect bundles
- // (do this only if team loaders are found, but before any side effects occur)
- synchronized (aspectBindingsByBasePlugin) {
- List<AspectBinding> aspects= aspectBindingsByBasePlugin.get(baseBundle.getSymbolicName());
- if (aspects != null) {
- if (this.permissionManager.isReady()) {
- for (AspectBinding aspectBinding : aspects)
- if (!this.permissionManager.checkForcedExports(aspectBinding.aspectPlugin, baseBundle.getSymbolicName(), aspectBinding.forcedExports))
- return; // don't activate teams of rejected aspect bundle
- } else {
- this.permissionManager.addForcedExportsObligations(aspects, baseBundle);
- }
- }
- }
-
- loaders = new ArrayList<MasterTeamLoader>(loaders);
- this.masterTeamLoaders.remove(baseBundle);
- }
- while (!loaders.isEmpty()) {
- // be sure not to hold any lock during this statement:
- List<Object> newInstances = loaders.remove(0).instantiateLoadedTeams(baseBundle, triggerClassname, this.permissionManager);
- synchronized (this.teamInstances) {
- this.teamInstances.addAll(newInstances);
- }
- }
- // mark the fact that all teams adapting this base bundle have now been activated:
- synchronized (aspectBindingsByBasePlugin) {
- List<AspectBinding> aspects= aspectBindingsByBasePlugin.get(baseBundle.getSymbolicName());
- if (aspects != null)
- for (AspectBinding aspectBinding : aspects)
- aspectBinding.activated= true;
- }
- }
-
- /** Copy all registered team instances into the given list,
- * which must by of type List<Team>; (can't mention Team in this plugin).
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static synchronized void getTeamInstances(List list) {
- list.addAll(instance.teamInstances);
- }
-
// configure OT/Equinox debugging:
public static int WARN_LEVEL = ILogger.ERROR;
static {
@@ -596,29 +90,94 @@
}
}
- public void log (Throwable ex, String msg) {
+ public static void log (Throwable ex, String msg) {
msg = "OT/Equinox: "+msg;
System.err.println(msg);
ex.printStackTrace();
- this.log.log(TRANSFORMER_PLUGIN_ID, ex, msg);
+ if (log != null)
+ log.log(new Status(IStatus.ERROR, TRANSFORMER_PLUGIN_ID, msg, ex));
+ else
+ System.err.println(msg);
}
- public void log(int status, String msg) {
+ public static void log(int status, String msg) {
if (status >= WARN_LEVEL)
doLog(status, msg);
}
- public void doLog(int status, String msg) {
+ private static void doLog(int status, String msg) {
msg = "OT/Equinox: "+msg;
- this.log.log(TRANSFORMER_PLUGIN_ID, status, msg);
- }
-
- public IByteCodeAnalyzer getByteCodeAnalyzer() {
- return new ASMByteCodeAnalyzer();
+ if (log != null)
+ log.log(new Status(status, TRANSFORMER_PLUGIN_ID, msg));
+ else
+ System.err.println(msg);
}
- public static boolean useDynamicWeaving() {
+
+
+ public static TransformerPlugin getDefault() {
+ return plugin;
+ }
+
+ public void registerAspectBindingRegistry(AspectBindingRegistry aspectBindingRegistry) {
+ this.aspectBindingRegistry = aspectBindingRegistry;
+ }
+
+ /**
+ * public API:
+ * {@link IAspectRegistry#getAdaptingAspectPlugins(Bundle)}
+ */
+ public @NonNull String[] getAdaptingAspectPlugins(Bundle basePlugin) {
+ return getAdaptingAspectPlugins(basePlugin.getSymbolicName());
+ }
+
+ public @NonNull String[] getAdaptingAspectPlugins(String id) {
+ List<AspectBinding> aspectBindings = this.aspectBindingRegistry.getAdaptingAspectBindings(id);
+ if (aspectBindings == null)
+ return new String[0];
+ String[] result = new String[aspectBindings.size()];
+ for (int i = 0; i < result.length; i++)
+ result[i] = aspectBindings.get(i).aspectPlugin;
+ return result;
+ }
+
+ public static void registerTeamInstance(Team instance) {
+ plugin.teamInstances.add(instance);
+ }
+ /**
+ * Copy all registered team instances into the given list,
+ */
+ public static synchronized void getTeamInstances(List<Team> list) {
+ list.addAll(plugin.teamInstances);
+ }
+
+ @Override
+ public boolean isOTDT() {
+ // TODO Auto-generated method stub
return false;
}
-}
+ @Override
+ public boolean isAdaptedBasePlugin(String baseBundleName) {
+ return this.aspectBindingRegistry.isAdaptedBasePlugin(baseBundleName);
+ }
+
+ @Override
+ public String[] getAdaptedBasePlugins(Bundle aspectBundle) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean hasInternalTeams(Bundle bundle) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isDeniedAspectPlugin(String symbolicName) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/ASMByteCodeAnalyzer.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/ASMByteCodeAnalyzer.java
deleted file mode 100644
index f2906d3..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/ASMByteCodeAnalyzer.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2008 Oliver Frank.
- *
- * 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
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Oliver Frank - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.eclipse.objectteams.otequinox.hook.IByteCodeAnalyzer;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.commons.EmptyVisitor;
-
-/**
- * This class performs some fast readClass analyses
- * to determine further processing.
- *
- * @author Oliver Frank
- * @since 1.2.3
- */
-public class ASMByteCodeAnalyzer implements IByteCodeAnalyzer {
- private static final int ACC_TEAM = 0x8000;
-
- private static class ClassInformation {
- private boolean isTeam;
- private String superClassName;
-
- public ClassInformation(boolean isTeam, String superClassName) {
- super();
- this.isTeam = isTeam;
- this.superClassName = superClassName;
- }
-
- public boolean isTeam() {
- return isTeam;
- }
-
- public String getSuperClassName() {
- if (superClassName != null)
- return superClassName.replace('/', '.');
- return null;
- }
- }
-
- private static class MyVisitor extends EmptyVisitor {
- MyVisitor() { super();}
- private boolean isTeam;
- private String superClassName;
-
- public boolean isTeam() {
- return isTeam;
- }
-
- public String getSuperClassName() {
- return superClassName;
- }
-
- @Override
- public void visit(int version, int access, String name,
- String signature, String superName, String[] interfaces) {
- superClassName = superName;
- isTeam = (access & ACC_TEAM) != 0;
- }
- }
-
- private Map<String, ClassInformation> classInformationMap =
- new ConcurrentHashMap<String, ClassInformation>(512, 0.75f, 4);
-
- /**
- * {@inheritDoc}
- */
- public String getSuperclass(InputStream classStream, String className) {
- try {
- return getClassInformation(null, classStream, className)
- .getSuperClassName();
- } catch (IOException e) {
- return null;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public String getSuperclass(byte[] classBytes, String className) {
- try {
- return getClassInformation(classBytes, null, className)
- .getSuperClassName();
- } catch (IOException e) {
- return null;
- }
- }
-
- public boolean isTeam(byte[] classBytes, String className)
- throws IOException {
- return getClassInformation(classBytes, null, className).isTeam();
- }
-
- private ClassInformation getClassInformation(byte[] classBytes,
- InputStream classStream, String className) throws IOException
- {
- ClassInformation classInformation = classInformationMap.get(className);
- if (classInformation != null) {
- return classInformation;
- }
- if (classBytes != null) {
- classInformation = this.getClassInformationPrivate(classBytes);
- } else {
- classInformation = this.getClassInformationPrivate(classStream);
- }
- classInformationMap.put(className, classInformation);
- return classInformation;
- }
-
-
- private ClassInformation getClassInformationPrivate(InputStream classStream)
- throws IOException {
- return getClassInformationPrivate(new ClassReader(classStream));
- }
-
- private ClassInformation getClassInformationPrivate(byte[] classBytes) {
- return getClassInformationPrivate(new ClassReader(classBytes));
- }
-
- private ClassInformation getClassInformationPrivate(ClassReader reader) {
- MyVisitor visitor = new MyVisitor();
-
- reader.accept(visitor, 0);
- return new ClassInformation(visitor.isTeam(), visitor
- .getSuperClassName());
- }
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectBinding.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectBinding.java
deleted file mode 100644
index c33deec..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectBinding.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2009 Germany and Technical University Berlin, Germany.
- *
- * 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
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Technical University Berlin - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox.internal;
-
-import java.util.List;
-
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.objectteams.otequinox.ActivationKind;
-
-/**
- * A simple record representing the information read from an extension to org.eclipse.objectteams.otequinox.aspectBindings.
- * @author stephan
- * @since 1.3.0 (was a nested class before that)
- */
-public class AspectBinding {
- public String aspectPlugin;
- public String basePlugin;
- public IConfigurationElement[] forcedExports;
- public ActivationKind[] activations = null;
- public String[] teamClasses;
- public List<String>[] subTeamClasses;
- public boolean activated= false;
-
- public AspectBinding(String aspectId, String baseId, IConfigurationElement[] forcedExportsConfs) {
- this.aspectPlugin= aspectId;
- this.basePlugin= baseId;
- this.forcedExports= forcedExportsConfs;
- }
-
- @SuppressWarnings("unchecked")
- public void initTeams(int count) {
- this.teamClasses = new String[count];
- this.subTeamClasses = new List[count]; // new List<String>[count] is illegal!
- this.activations = new ActivationKind[count];
- }
-
- public void setActivation(int i, String specifier) {
- if (specifier == null)
- this.activations[i] = ActivationKind.NONE;
- else
- this.activations[i] = ActivationKind.valueOf(specifier);
- }
- public String toString() {
- String result = "\tbase plugin "+basePlugin+"\n\tadapted by aspect pluging "+aspectPlugin;
- for (String teamClass : teamClasses) {
- result += "\n\t\t + team "+teamClass;
- }
- return result;
- }
-}
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectPermissionManager.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectPermissionManager.java
deleted file mode 100644
index befb818..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/AspectPermissionManager.java
+++ /dev/null
@@ -1,615 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2009 Germany and Technical University Berlin, Germany.
- *
- * 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
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Technical University Berlin - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox.internal;
-
-import static org.eclipse.objectteams.otequinox.hook.AspectPermission.*;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-
-import org.eclipse.core.internal.runtime.InternalPlatform;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.RegistryFactory;
-import org.eclipse.objectteams.otequinox.ActivationKind;
-import org.eclipse.objectteams.otequinox.AspectBindingRequestAnswer;
-import org.eclipse.objectteams.otequinox.Constants;
-import org.eclipse.objectteams.otequinox.IAspectRequestNegotiator;
-import org.eclipse.objectteams.otequinox.TransformerPlugin;
-import org.eclipse.objectteams.otequinox.internal.MasterTeamLoader.TeamClassRecord;
-import org.eclipse.osgi.service.datalocation.Location;
-import org.eclipse.objectteams.otequinox.hook.AspectPermission;
-import org.eclipse.objectteams.otequinox.hook.HookConfigurator;
-import org.eclipse.objectteams.otequinox.hook.ILogger;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.service.packageadmin.PackageAdmin;
-
-/**
- * Manage permissions of aspect bundles requesting to apply aspectBindings and forcedExports.
- * The following pieces of information are checked:
- * <ul>
- * <li>properties set in installation-wide config.ini or as command line args (handled by {@link HookConfigurator} (plus internal class OTStorageHook))</li>
- * <li>defaults set per workspace (file negotiationDefaults.txt)</li>
- * <li>individual GRANT/DENY per workspace (files grantedForcedExports.txt, deniedForcedExports.txt)</li>
- * <li>answers from registered negotiators (extension point org.eclipse.objectteams.otequinox.aspectBindingNegotiators, see {@link IAspectRequestNegotiator})</li>
- * </ul>
- *
- * <p>
- * The final answer for a given request is combined from all sources where the priority of any {@link #DENY} answer is highest,
- * of {@link #UNDEFINED} is lowest.
- * </p>
- * <p>
- * If a negotiator has determined a decision and its answer has the <code>persistent</code> flag set,
- * this particular aspect permission is stored as per-workspace configuration.
- * </p>
- * @author stephan
- * @since 1.2.6
- */
-@SuppressWarnings("restriction")
-public class AspectPermissionManager {
-
- // property names for default configuration:
- private static final String FORCED_EXPORT_DEFAULT = "forced.export.default";
- private static final String ASPECT_BINDING_DEFAULT = "aspect.binding.default";
-
- // workspace files where negotiation configuration is stored:
- private static final String NEGOTIATION_DEFAULTS_FILE = "negotiationDefaults.txt";
- private static final String GRANTED_FORCED_EXPORTS_FILE = "grantedForcedExports.txt";
- private static final String DENIED_FORCED_EXPORTS_FILE = "deniedForcedExports.txt";
-
-
- // set of aspect plug-ins for which some permission has been denied:
- private Set<String> deniedAspects = new HashSet<String>();
- // default permission for aspect bindings:
- private AspectPermission defaultAspectBindingPermission = GRANT;
- // default permission for forced exports:
- private AspectPermission defaultForcedExportPermission = UNDEFINED; // not yet granted, but open for receiving a GRANT
- // for negotiation of aspect binding requests (incl. forced export):
- private List<IAspectRequestNegotiator> negotiators = new ArrayList<IAspectRequestNegotiator>();
-
-
- // collect all forced exports (denied/granted), granted should balance to an empty structure.
- // structure is: aspect-id -> (base bundle x base package)*
- private HashMap<String, ArrayList<String[]>> deniedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
- private HashMap<String, ArrayList<String[]>> grantedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
-
- // key is aspectId+"->"+baseId, value is array of team names
- private HashMap<String, Set<String>> deniedTeamsByAspectBinding = new HashMap<String, Set<String>>();
- private HashMap<String, Set<String>> grantedTeamsByAspectBinding = new HashMap<String, Set<String>>();
-
- // the workspace directory for storing the state of this plugin
- private IPath otequinoxState;
- // back link needed for accessing the state location:
- private Bundle transformerBundle;
- // helper instance needed to stop bundles by name
- private PackageAdmin packageAdmin;
- // shared logger:
- private ILogger log;
-
- public AspectPermissionManager(ILogger log, Bundle bundle, PackageAdmin packageAdmin) {
- this.log = log;
- this.transformerBundle = bundle;
- this.packageAdmin = packageAdmin;
- }
-
- /* local cache for isReady(): */
- private boolean isWaitingForLocation = true;
-
- /** Before using this permission manager a client must check whether we're ready (instance location set). */
- public boolean isReady() {
- if (!isWaitingForLocation)
- return true;
- try {
- InternalPlatform platform = InternalPlatform.getDefault();
- Location instanceLocation = platform.getInstanceLocation();
- if (!instanceLocation.isSet())
- return false; // not yet capable
- this.isWaitingForLocation = false;
- fetchAspectBindingPermssionsFromWorkspace();
- } catch (NoClassDefFoundError ncdfe) {
- this.log.log(ILogger.WARNING, "Optional class InternalPlatform not found, cannot access workspace location");
- this.isWaitingForLocation = false;
- return true;
- }
- if (!this.obligations.isEmpty())
- for (Runnable job : this.obligations)
- job.run();
- return true;
- }
-
- /**
- * Fetch stored permissions from this plugin's workspace state.
- *
- * @pre instance location should be set (see {@link #isReady()}),
- * otherwise will silently return without accessing workspace settings.
- */
- private void fetchAspectBindingPermssionsFromWorkspace()
- {
- try {
- this.otequinoxState = InternalPlatform.getDefault().getStateLocation(this.transformerBundle, true);
- } catch (NoClassDefFoundError ncdfe) {
- this.log.log(ILogger.WARNING, "Optional class InternalPlatform not found, cannot access workspace location");
- return;
- }
-
- // defaults:
- IPath configFilePath = this.otequinoxState.append(NEGOTIATION_DEFAULTS_FILE);
- File configFile = new File(configFilePath.toOSString());
- if (configFile.exists()) {
- Properties props = new Properties();
- try {
- boolean migrated = false; // TODO(SH): remove this migration support in 1.3.0
- props.load(new FileInputStream(configFile));
- String value = (String) props.get(ASPECT_BINDING_DEFAULT);
- if (value != null)
- try {
- defaultAspectBindingPermission = AspectPermission.valueOf(value);
- } catch (IllegalArgumentException iae) {
- if ("DONT_CARE".equals(value)) {
- defaultAspectBindingPermission = AspectPermission.UNDEFINED;
- migrated = true;
- } else {
- // this code should remain even after 1.3.0:
- defaultAspectBindingPermission = AspectPermission.DENY;
- log(iae, "Cannot set default aspect permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
- }
- }
- value = (String) props.get(FORCED_EXPORT_DEFAULT);
- if (value != null)
- try {
- defaultForcedExportPermission = AspectPermission.valueOf(value);
- } catch (IllegalArgumentException iae) {
- if ("DONT_CARE".equals(value)) {
- defaultForcedExportPermission = AspectPermission.UNDEFINED;
- migrated = true;
- } else {
- // this code should remain even after 1.3.0:
- defaultForcedExportPermission = AspectPermission.DENY;
- log(iae, "Cannot set default forced exports permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
- }
- }
- if (migrated)
- writeNegotiationDefaults(configFile);
- } catch (IOException ioex) {
- log(ioex, "Failed to read configuration file "+configFilePath.toOSString());
- }
- } else {
- try {
- File stateDir = new File(this.otequinoxState.toOSString());
- if (!stateDir.exists())
- stateDir.mkdirs();
- configFile.createNewFile();
- writeNegotiationDefaults(configFile);
- } catch (IOException ioex) {
- log(ioex, "Failed to create configuration file "+configFilePath.toOSString());
- }
- }
-
- // explicitly denied:
- configFilePath = this.otequinoxState.append(DENIED_FORCED_EXPORTS_FILE);
- configFile = new File(configFilePath.toOSString());
- if (configFile.exists())
- HookConfigurator.parseForcedExportsFile(configFile, DENY);
-
- // explicitly granted:
- configFilePath = this.otequinoxState.append(GRANTED_FORCED_EXPORTS_FILE);
- configFile = new File(configFilePath.toOSString());
- if (configFile.exists())
- HookConfigurator.parseForcedExportsFile(configFile, GRANT);
- }
-
- private void writeNegotiationDefaults(File configFile)
- throws IOException
- {
- FileWriter writer = new FileWriter(configFile);
- writer.append(ASPECT_BINDING_DEFAULT+'='+defaultAspectBindingPermission.toString()+'\n');
- writer.append(FORCED_EXPORT_DEFAULT+'='+defaultForcedExportPermission.toString()+'\n');
- writer.flush();
- writer.close();
- log(ILogger.INFO, "Created aspect binding defaults file "+configFile.getCanonicalPath());
- }
-
-
- /** Load extensions for EP org.eclipse.objectteams.otequinox.aspectBindingNegotiators. */
- public void loadAspectBindingNegotiators(BundleContext context) {
- IConfigurationElement[] aspectBindingNegotiatorsConfigs = RegistryFactory.getRegistry().getConfigurationElementsFor(
- Constants.TRANSFORMER_PLUGIN_ID, Constants.ASPECT_NEGOTIATOR_EXTPOINT_ID);
- for (int i = 0; i < aspectBindingNegotiatorsConfigs.length; i++) {
- IConfigurationElement currentNegotiatorConfig = aspectBindingNegotiatorsConfigs[i];
- try {
- Object negotiator = currentNegotiatorConfig.createExecutableExtension("class");
- if (negotiator != null)
- this.negotiators.add(((IAspectRequestNegotiator)negotiator));
- } catch (CoreException e) {
- log(e, "Failed to instantiate extension "+currentNegotiatorConfig);
- }
- }
- }
-
- /** Delegatee of internal API {@link TransformerPlugin#isDeniedAspectPlugin(String)}. */
- public boolean isDeniedAspectPlugin(String symbolicName) {
- return this.deniedAspects.contains(symbolicName);
- }
-
-
- /**
- * Check whether a given aspect requests forced exports from base,
- * and whether these requests are granted/denied by checking all available sources.
- *
- * Clients should ask {@link #isReady()} (ie., instance location is set) before calling this method,
- * otherwise workspace settings have to be silently ignored (any error should be signaled by client).
- *
- * @param aspectId symbolic name of the aspect bundle
- * @param baseBundleId symbolic name of the bound base bundle
- * @param forcedExports any forced exports requested in this aspect binding.
- * @return whether all requests (if any) have been granted
- */
- public boolean checkForcedExports(String aspectId, String baseBundleId, IConfigurationElement[] forcedExports)
- {
- if (forcedExports == null || forcedExports.length == 0)
- return true;
-
- ArrayList<String[]> deniedForcedExports = getConfiguredForcedExports(aspectId, DENY, deniedForcedExportsByAspect);
- ArrayList<String[]> grantedForcedExports= getConfiguredForcedExports(aspectId, GRANT, grantedForcedExportsByAspect);
-
- // iterate all requested forcedExports to search for a matching permission:
- for (IConfigurationElement forcedExport : forcedExports) { // [0..1] (as defined in the schema)
- String forcedExportsRequest = forcedExport.getValue();
- if (forcedExportsRequest == null)
- continue;
- for (String singleForcedExportRequest : forcedExportsRequest.split(","))
- {
- singleForcedExportRequest = singleForcedExportRequest.trim();
-
- String[] listEntry;
- boolean grantReported = false;
- AspectPermission negotiatedPermission = this.defaultForcedExportPermission;
-
- // DENY by default?
- if (negotiatedPermission == DENY) {
- log(ILogger.ERROR, "Default denial of forced export regarding package "+singleForcedExportRequest+
- " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
- this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
- return false; // NOPE!
- }
-
- // DENY from configuration?
- listEntry = findRequestInList(baseBundleId, singleForcedExportRequest, deniedForcedExports);
- if (listEntry != null) {
- log(ILogger.ERROR, "Explicit denial of forced export regarding package "+singleForcedExportRequest+
- " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
- this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
- return false; // NOPE!
- }
-
- // GRANT from configuration?
- listEntry = findRequestInList(baseBundleId, singleForcedExportRequest, grantedForcedExports);
- if (listEntry != null) {
- log(ILogger.INFO, "Forced export granted for "+aspectId+": "+singleForcedExportRequest+" (from bundle "+baseBundleId+")");
- grantReported = true;
- grantedForcedExports.remove(listEntry);
- negotiatedPermission = GRANT;
- }
-
- // default and persistent configuration did not DENY, proceed to the negotiators:
- boolean shouldPersist = false;
- for (IAspectRequestNegotiator negotiator : this.negotiators) {
- AspectBindingRequestAnswer answer = negotiator.checkForcedExport(aspectId, baseBundleId, singleForcedExportRequest, negotiatedPermission);
- if (answer != null) {
- if (answer.permission.compareTo(negotiatedPermission) > 0) // increasing priority of answer?
- {
- shouldPersist = answer.persistent;
- negotiatedPermission = answer.permission;
- // locally store as default for subsequent requests (not persistent, see below):
- if (answer.allRequests)
- this.defaultForcedExportPermission = negotiatedPermission;
- if (negotiatedPermission == DENY)
- break; // end of discussion.
- }
- }
- }
-
- // make decision persistent?
- if (shouldPersist && negotiatedPermission != UNDEFINED)
- // FIXME(SH): handle "allRequests":
- persistForcedExportsAnswer(aspectId, baseBundleId, singleForcedExportRequest, negotiatedPermission);
-
- // report:
- if (negotiatedPermission == GRANT) {
- if (!grantReported)
- log(ILogger.INFO, "Negotiation granted forced export for "+aspectId+
- ": "+singleForcedExportRequest+" (from bundle "+baseBundleId+')');
- } else {
- String verb = "did not grant";
- if (negotiatedPermission == DENY)
- verb = "denied";
- log(ILogger.ERROR, "Negotiation "+verb+" forced export for "+aspectId+
- ": "+singleForcedExportRequest+" (from bundle "+baseBundleId+")"+
- ". Aspect is not activated.");
- this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
- return false; // don't install illegal aspect
- }
- }
- }
- if (!grantedForcedExports.isEmpty())
- reportUnmatchForcedExports(aspectId, grantedForcedExports);
- return true;
- }
-
- /**
- * Get the forced exports configured for a given aspect bundle with permission <code>perm</code>.
- * Consult {@link HookConfigurator} and store the result in <code>map</code>.
- *
- * @param aspectId symbolic name of the aspect in focus
- * @param perm are we asking about DENY or GRANT?
- * @param map in/out param for storing results from OTStorageHook
- * @return list of pairs (base bundle x base package)
- */
- private ArrayList<String[]> getConfiguredForcedExports(String aspectId,
- AspectPermission perm,
- HashMap<String, ArrayList<String[]>> map)
- {
- ArrayList<String[]> forcedExports= map.get(aspectId);
- if (forcedExports == null) {
- // fetch declarations from config.ini or other locations.
- forcedExports= HookConfigurator.getForcedExportsByAspect(aspectId, perm);
- map.put(aspectId, forcedExports);
- }
- return forcedExports;
- }
-
- private String[] findRequestInList(String baseBundleId, String basePackage, ArrayList<String[]> list) {
- if (list != null)
- for (String[] singleExport : list)
- if ( singleExport[0].equals(baseBundleId)
- && singleExport[1].equals(basePackage))
- {
- return singleExport;
- }
- return null;
- }
-
- /**
- * If the structure of grantedForcedExports is not empty we have mismatches between forced-export declarations.
- * Report these mismatches as warnings.
- */
- void reportUnmatchForcedExports(String aspectId, ArrayList<String[]> unmatchedForcedExports)
- {
- for (String[] export: unmatchedForcedExports) {
- String baseId = export[0];
- String pack = export[1];
- log(ILogger.WARNING, "Aspect "+aspectId+
- " does not declare forced export of package "+
- pack+" from bundle "+baseId+
- " as declared in config.ini (or system property)");
- }
- }
-
- /* Simple strategy to append a forced export to a file (existing or to be created). */
- private void persistForcedExportsAnswer(String aspectId, String baseBundleId, String basePackage, AspectPermission negotiatedPermission)
- {
- if (this.otequinoxState == null) {
- log(ILogger.ERROR, "Can't persist forcedExports permission, no workspace location accessable.");
- return;
- }
- try {
- String fileName = (negotiatedPermission == DENY) ? DENIED_FORCED_EXPORTS_FILE : GRANTED_FORCED_EXPORTS_FILE;
- IPath forcedExportsPath = this.otequinoxState.append(fileName);
- File forcedExportsFile = new File(forcedExportsPath.toOSString());
- if (!forcedExportsFile.exists())
- forcedExportsFile.createNewFile();
- FileWriter writer = new FileWriter(forcedExportsFile, true); // FIXME(SH): consider merge (after decision about file format)
- writer.append('\n');
- writer.append(baseBundleId);
- writer.append("\n[\n\t");
- writer.append(basePackage);
- writer.append(";x-friends:=\"");
- writer.append(aspectId);
- writer.append("\"\n]\n");
- writer.flush();
- writer.close();
- } catch (IOException ioe) {
- log(ioe, "Failed to persist negotiation result");
- }
- }
-
- /**
- * Check permission for the aspect binding of one specific team.
- *
- * Clients should ask {@link #isReady()} (ie., instance location is set) before calling this method,
- * otherwise workspace settings have to be silently ignored (any error should be signaled by client).
- *
- * @param aspectBundleId
- * @param baseBundleId
- * @param teamClass
- * @return whether this team is permitted to adapt classes from the given base bundle.
- */
- boolean checkTeamBinding(String aspectBundleId, String baseBundleId, String teamClass)
- {
- boolean shouldReportGrant = false; // grant by default should not be reported
- AspectPermission negotiatedPermission = this.defaultAspectBindingPermission;
-
- // DENY by default?
- if (negotiatedPermission == DENY) {
- log(ILogger.ERROR, "Default denial of aspect binding regarding base bundle "+baseBundleId+
- " as requested by bundle "+aspectBundleId+"; bundle not activated");
- this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerHook.
- return false; // NOPE!
- }
-
-
- String key = aspectBundleId+"->"+baseBundleId;
-
- // denied from configuration?
- Set<String> deniedTeams = deniedTeamsByAspectBinding.get(key);
- if (deniedTeams != null && !deniedTeams.isEmpty()) {
- if (deniedTeams.contains(teamClass)) {
- deniedAspects.add(aspectBundleId);
- return false;
- }
- }
-
- // granted from configuration?
- Set<String> grantedTeams = grantedTeamsByAspectBinding.get(key);
- if (grantedTeams != null && grantedTeams.contains(teamClass)) {
- negotiatedPermission = GRANT;
- shouldReportGrant = true;
- }
-
- // default and persistent configuration did not DENY, proceed to the negotiators:
- boolean shouldPersist = false;
- for (IAspectRequestNegotiator negotiator : this.negotiators) {
- AspectBindingRequestAnswer answer = negotiator.checkAspectBinding(aspectBundleId, baseBundleId, teamClass, negotiatedPermission);
- if (answer != null) {
- if (answer.permission.compareTo(negotiatedPermission) > 0) // increasing priority of answer?
- {
- shouldPersist = answer.persistent;
- negotiatedPermission = answer.permission;
- shouldReportGrant = negotiatedPermission == GRANT;
- // locally store as default for subsequent requests:
- if (answer.allRequests)
- this.defaultAspectBindingPermission = negotiatedPermission;
-
- if (negotiatedPermission == DENY)
- break; // end of discussion.
- }
- }
- }
-
- // make decision persistent?
- if (shouldPersist && negotiatedPermission != UNDEFINED)
- persistTeamBindingAnswer(aspectBundleId, baseBundleId, teamClass, negotiatedPermission);
-
- // report:
- if (negotiatedPermission == GRANT) {
- if (shouldReportGrant)
- log(ILogger.INFO, "Negotiation granted aspect binding for "+aspectBundleId+
- " to base bundle "+baseBundleId+" by means of team "+teamClass+'.');
- } else {
- String verb = "did not grant";
- if (negotiatedPermission == DENY)
- verb = "denied";
- log(ILogger.ERROR, "Negotiation "+verb+" aspect binding for "+aspectBundleId+
- " to base bundle "+baseBundleId+" by means of team "+teamClass+
- ". Aspect is not activated.");
- this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerHook.
- return false; // don't install illegal aspect
- }
- return true;
- }
-
- private void persistTeamBindingAnswer(String aspectBundleId, String baseBundleId, String teamClass, AspectPermission negotiatedPermission)
- {
- // FIXME(SH): implement persisting these!
- }
-
- void log (Throwable ex, String msg) {
- msg = "OT/Equinox: "+msg;
- this.log.log(Constants.TRANSFORMER_PLUGIN_ID, ex, msg);
- }
-
- void log(int status, String msg) {
- if (status >= TransformerPlugin.WARN_LEVEL)
- this.log.log(Constants.TRANSFORMER_PLUGIN_ID, status, "OT/Equinox: "+msg);
- }
-
- List<Runnable> obligations = new ArrayList<Runnable>();
- public void addBaseBundleObligations(final List<Object> teamInstances, final ArrayList<TeamClassRecord> teamClasses, final Bundle baseBundle) {
- schedule(new Runnable() {
- public void run() {
- List<TeamClassRecord> teamsToRevert = new ArrayList<TeamClassRecord>();
- // aspect bindings:
- for (TeamClassRecord teamClass : teamClasses)
- if (!checkTeamBinding(teamClass.aspectBundle.getSymbolicName(), baseBundle.getSymbolicName(), teamClass.teamName))
- teamsToRevert.add(teamClass);
- if (!teamsToRevert.isEmpty())
- revert(teamsToRevert);
- }
- void revert(List<TeamClassRecord> teamsToRevert) {
- try {
- Set<Bundle> bundlesToStop = new HashSet<Bundle>();
- Class<?>[] deactivationArgumentTypes = new Class[]{Thread.class};
- Object[] deactivationArguments = new Object[] {TeamClassRecord.get_ALL_THREADS()};
- for (int i=0, c=0; c< teamsToRevert.size(); c++) {
- TeamClassRecord teamClass = teamClasses.get(c);
- if (teamClass.activation != ActivationKind.NONE) {
- Object teamInstance = teamInstances.get(i++);
- Method deactivationMethod = teamClass.clazz.getMethod("deactivate", deactivationArgumentTypes);
- deactivationMethod.invoke(teamInstance, deactivationArguments);
- // could also check if roles are present already ...
- }
- bundlesToStop.add(teamClass.aspectBundle);
- }
- for (Bundle bundle : bundlesToStop) {
- log(ILogger.ERROR, "Stopping aspect bundle "+bundle.getSymbolicName()+" with denied aspect binding(s)");
- bundle.stop();
- }
- } catch (Exception e) {
- log(e, "Failed to revert aspect bundle with denied aspect bindings.");
- }
- }
- });
- }
-
- public void addForcedExportsObligations(final List<AspectBinding> aspects, final Bundle baseBundle) {
- schedule(new Runnable () {
- public void run() {
- for (AspectBinding aspectBinding : aspects)
- if (!checkForcedExports(aspectBinding.aspectPlugin, baseBundle.getSymbolicName(), aspectBinding.forcedExports))
- stopIllegalBundle(aspectBinding.aspectPlugin);
- }
- });
- }
-
- void schedule(Runnable job) {
- if (isReady()) // became ready since last query?
- job.run();
- else
- synchronized(obligations) {
- obligations.add(job);
- }
- }
-
- void stopIllegalBundle(String symbolicName) {
- String msgCore = "stop bundle "+symbolicName+" whose requests for forced exports have been denied";
- if (this.packageAdmin == null) {
- log(ILogger.ERROR, "Needing to "+msgCore+" but package admin is not available");
- } else {
- Bundle[] bundles = this.packageAdmin.getBundles(symbolicName, null);
- if (bundles == null)
- log(ILogger.ERROR, "Needing to "+msgCore+" but bundle cannot be retrieved");
- else
- try {
- bundles[0].stop();
- } catch (BundleException e) {
- log(e, "Failed to " + msgCore);
- }
- }
- }
-
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/JobAndThreadListener.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/JobAndThreadListener.java
deleted file mode 100644
index 47bdc55..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/JobAndThreadListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2010 GK Software AG
- *
- * 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
- * $Id$
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Stephan Herrmann - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox.internal;
-
-import java.util.HashSet;
-
-import org.eclipse.core.runtime.jobs.IJobChangeEvent;
-import org.eclipse.core.runtime.jobs.IJobChangeListener;
-import org.objectteams.TeamThreadManager;
-
-/**
- * This listener ensures that each worker threads is made known to the OTRE
- * as soon as is starts running Jobs.
- *
- * @since 0.7.1 (incubation)
- */
-public class JobAndThreadListener implements IJobChangeListener {
-
- private HashSet<Thread> knownThreads = new HashSet<Thread>();
-
- public void aboutToRun(IJobChangeEvent event) {
- Thread current = Thread.currentThread();
- synchronized (this.knownThreads) {
- if (this.knownThreads.contains(current))
- return;
- this.knownThreads.add(current);
- }
- TeamThreadManager.newThreadStarted(false, null);
- }
-
- public void awake(IJobChangeEvent event) {
- }
-
- public void done(IJobChangeEvent event) {
- // FIXME(SH): implement thread ended strategy
- }
-
- public void running(IJobChangeEvent event) {
- }
-
- public void scheduled(IJobChangeEvent event) {
- }
-
- public void sleeping(IJobChangeEvent event) {
- }
-
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/MasterTeamLoader.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/MasterTeamLoader.java
deleted file mode 100644
index 7333aeb..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/MasterTeamLoader.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany,
- * for its Fraunhofer Institute for Computer Architecture and Software
- * Technology (FIRST), Berlin, Germany and Technical University Berlin,
- * Germany.
- *
- * 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
- * $Id: MasterTeamLoader.java 23468 2010-02-04 22:34:27Z stephan $
- *
- * 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.otequinox.internal;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.core.internal.registry.osgi.OSGIUtils;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.objectteams.otequinox.ActivationKind;
-import org.eclipse.objectteams.otequinox.TransformerPlugin;
-import org.eclipse.osgi.framework.internal.core.BundleHost;
-import org.eclipse.objectteams.otequinox.hook.ClassScanner;
-import org.eclipse.objectteams.otequinox.hook.ILogger;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-
-/**
- * Each instance of this class is responsible for loading all teams adapting a specific base plugin.
- * It stores the team classes loaded successfully.
- * After team loading a call to instantiateLoadedTeams() shall be issued to instantiate
- * those teams, but that call pre-assumes that adapted base classes have already been loaded.
- *
- * @author stephan
- * @version $Id: MasterTeamLoader.java 23468 2010-02-04 22:34:27Z stephan $
- */
-@SuppressWarnings("restriction")
-public class MasterTeamLoader {
-
- /** A simple record describing a configured and loaded team class: */
- static class TeamClassRecord {
- // store these info to check consistency among different aspectBindings mentioning the same team class:
- static Set<Class<?>> allInstantiatedTeams = new HashSet<Class<?>>();
- static Map<Class<?>, ActivationKind> allActivations = new HashMap<Class<?>, ActivationKind>();
-
- /** The bundle providing this team classs. */
- Bundle aspectBundle;
- /** The qualified team name. */
- String teamName;
- /** The loaded team class. */
- Class<?> clazz;
- /** The activation kind which was requested from the extension. */
- ActivationKind activation;
- /**
- * @param clazz the loaded team class
- * @param activation the activation kind which was requested from the extension
- */
- TeamClassRecord(Class<?> clazz, ActivationKind activation) {
- this.clazz = clazz;
- this.activation = activation;
- }
-
- public TeamClassRecord(Bundle aspectBundle, String teamName, ActivationKind activation) throws Exception {
- this.activation = activation;
- this.aspectBundle = aspectBundle;
- this.teamName = teamName;
- // enable to revert to early loading:
- //this.clazz = this.aspectBundle.loadClass(this.teamName);
- }
-
- /** Constant from org.objectteams.Team acquired via reflection. */
- static Thread ALL_THREADS = null;
-
- /** Retrieve org.objectteams.Team.ALL_THREADS. */
- static synchronized Thread get_ALL_THREADS()
- throws Exception
- {
- if (ALL_THREADS == null) {
- Class<?> ooTeam = Class.forName("org.objectteams.Team");
- Field constantField = ooTeam.getDeclaredField("ALL_THREADS");
- ALL_THREADS = (Thread)constantField.get(null);
- }
- return ALL_THREADS;
- }
- void readOTAttributes(ClassScanner scanner)
- throws Exception, IOException
- {
- readOTAttributes(scanner, this.teamName);
- }
-
- void readOTAttributes(ClassScanner scanner, String teamName)
- throws Exception, IOException
- {
- TransformerPlugin.getDefault().log(IStatus.OK, "reading attributes of team "+teamName);
- ClassLoader loader = (ClassLoader) ((BundleHost)aspectBundle).getLoaderProxy().getBundleLoader().createClassLoader();
- trying: {
- for(String candidateName : possibleTeamNames(teamName)) {
- try {
- scanner.readOTAttributes(aspectBundle, candidateName, loader);
- break trying;
- } catch (ClassNotFoundException e) {
- // keep going if we still have candidates
- }
- }
- throw new ClassNotFoundException(teamName);
- }
- Collection<String> baseClassNames = scanner.getCollectedBaseClassNames(teamName);
- if (baseClassNames != null && !baseClassNames.isEmpty())
- TransformerPlugin.getDefault().storeAdaptedBaseClassNames(this.aspectBundle.getSymbolicName(), teamName, baseClassNames);
- }
-
- public boolean isAlreadyHandled() throws ClassNotFoundException {
- if (this.clazz == null)
- loadClass();
- return allInstantiatedTeams.contains(this.clazz);
- }
-
- public Object newInstance() throws Exception {
- if (this.clazz == null)
- loadClass();
- allInstantiatedTeams.add(this.clazz); // do this before accessing the constructor to avoid circularity (see Trac #257).
- Object newInstance = this.clazz.newInstance();
- return newInstance;
- }
-
- private void loadClass() throws ClassNotFoundException {
- for (String candidateName : possibleTeamNames(this.teamName)) {
- try {
- this.clazz = this.aspectBundle.loadClass(candidateName);
- return;
- } catch (ClassNotFoundException ex) {
- // keep going if we still have candidates
- }
- }
- throw new ClassNotFoundException(this.teamName);
- }
-
- /**
- * Starting from currentName compute a list of potential binary names of (nested) teams
- * using "$__OT__" as the separator, to find class parts of nested teams.
- */
- private List<String> possibleTeamNames(String currentName) {
- List<String> result = new ArrayList<String>();
- result.add(currentName);
- char sep = '.'; // assume source name
- if (currentName.indexOf('$') > -1)
- // binary name
- sep = '$';
- int from = currentName.length()-1;
- while (true) {
- int pos = currentName.lastIndexOf(sep, from);
- if (pos == -1)
- break;
- String prefix = currentName.substring(0, pos);
- String postfix = currentName.substring(pos+1);
- if (sep=='$') {
- if (!postfix.startsWith("__OT__"))
- result.add(0, currentName = prefix+"$__OT__"+postfix);
- } else {
- // heuristic:
- // only replace if parent element looks like a class (expected to start with uppercase)
- int prevDot = prefix.lastIndexOf('.');
- if (prevDot > -1 && Character.isUpperCase(prefix.charAt(prevDot+1)))
- result.add(0, currentName = prefix+"$__OT__"+postfix);
- else
- break;
- }
- from = pos-1;
- }
- return result;
- }
-
- public void markAsActivated() {
- allActivations.put(this.clazz, this.activation);
- }
-
- public ActivationKind getActualActivation() {
- ActivationKind kind = allActivations.get(this.clazz);
- if (kind == null)
- return ActivationKind.NONE;
- return kind;
- }
- }
-
- Bundle baseBundle;
-
- /** Team classes waiting for activation. */
- private List<TeamClassRecord> teamClasses = new ArrayList<TeamClassRecord>();
-
- private HashMap<Bundle,List<String>> baseBundleToAspectName = new HashMap<Bundle, List<String>>();
-
- public MasterTeamLoader(Bundle baseBundle) {
- this.baseBundle = baseBundle;
- }
-
- /**
- * Load all teams adapting baseBundle and the adapted base classes.
- * TODO(SH): No checks are yet performed, whether the teams found in extensions actually
- * match the given baseBundle.
- *
- * @param baseBundle an adaptable base bundle which was just activated.
- * @param classScanner helper for reading OT bytecode attributes.
- * @param bindings declared aspect bindings for this bundle
- * @return whether or not teams have been loaded successfully
- */
- public boolean loadTeams(Bundle baseBundle, ClassScanner classScanner, ArrayList<AspectBinding> bindings)
- {
- for (final AspectBinding binding : bindings) {
- String aspectBundleName = binding.aspectPlugin;
-
- log(IStatus.OK, ">>> TransformerPlugin loading aspect plugin "+aspectBundleName+" <<<");
-
- final Bundle aspectBundle = OSGIUtils.getDefault().getBundle(aspectBundleName);
- if (aspectBundle == null) {
- Throwable t = new Exception("Aspect bundle "+aspectBundleName+" does not exist.");
- t.fillInStackTrace();
- log(t, "Failed to load teams for an aspect plugin.");
- }
-
- // load and store the team classes:
- for (int i = 0; i < binding.teamClasses.length; i++) {
- try {
- TeamClassRecord teamClassRecord = new TeamClassRecord(
- aspectBundle, binding.teamClasses[i],
- binding.activations[i]
- );
- this.teamClasses.add(teamClassRecord);
- teamClassRecord.readOTAttributes(classScanner); // disable to revert to early loading
- if (binding.subTeamClasses[i] != null)
- for (String subTeamName : binding.subTeamClasses[i])
- teamClassRecord.readOTAttributes(classScanner, subTeamName); // FIXME(SH): really use the same TeamClassRecord??
-
- } catch (Throwable t) {
- log(t, "Exception occurred while loading team class"); //$NON-NLS-1$
- }
- }
-
- // store aspectBundleName for PHASE 2:
- List<String> aspectNames = baseBundleToAspectName.get(baseBundle);
- if (aspectNames == null)
- baseBundleToAspectName.put(baseBundle, aspectNames = new ArrayList<String>());
- aspectNames.add(aspectBundleName);
- }
- return !this.teamClasses.isEmpty();
- }
-
- /**
- * Instantiate all team classes loaded before.
- * Before doing so all adapted base classes have to be loaded, too.
- *
- * @pre the AspectPermissionManager should be ready (ie., instance location is set), otherwise
- * workspace settings have to be ignored (error should be signaled by client).
- *
- * @param baseBundle only teams adapting this base bundle should be instantiated
- * @param triggerClassname loading of this class triggered this instantiation (may be null)
- * @param permissionManager helper for checking permissions of aspectBinding / forcedExport
- * @return list of team instances (maybe empty). Null signal that instantiation had to be deferred.
- */
- public List<Object> instantiateLoadedTeams(Bundle baseBundle, String triggerClassname, AspectPermissionManager permissionManager)
- {
- List<Object> teamInstances = new ArrayList<Object>(this.teamClasses.size());
-
- // permission checking can be performed now or later, depending on readiness:
- boolean permissionManagerReady = permissionManager.isReady();
-
- // ==== check permissions before we start activating:
- if (permissionManagerReady) { // otherwise we will register pending obligations below.
- boolean hasDenial = false;
- for (TeamClassRecord teamClass : this.teamClasses)
- if (!permissionManager.checkTeamBinding(teamClass.aspectBundle.getSymbolicName(), baseBundle.getSymbolicName(), teamClass.teamName))
- {
- hasDenial = true;
- try {
- teamClass.aspectBundle.stop();
- log(ILogger.ERROR, "Stopped bundle "+teamClass.aspectBundle.getSymbolicName()+" which requests unconfirmed aspect binding(s).");
- } catch (BundleException e) {
- log(e, "Failed to stop bundle "+teamClass.aspectBundle.getSymbolicName()+" which requests unconfirmed aspect binding(s).");
- }
- }
- if (hasDenial)
- return teamInstances; // still empty list
- }
-
- // ==== instantiate the teams:
- for (TeamClassRecord teamClass : this.teamClasses) {
- if (teamClass.activation == ActivationKind.NONE)
- continue;
- try {
- if (teamClass.isAlreadyHandled()) { // previously instantiated due to a different aspectBinding/basePlugin?
- ActivationKind actualActivation = teamClass.getActualActivation();
- if ( actualActivation != teamClass.activation
- && actualActivation != ActivationKind.NONE
- && teamClass.activation != ActivationKind.NONE)
- {
- log(IStatus.WARNING, "Conflicting activation requests in aspect bindings for team class "+teamClass.teamName);
- }
- } else {
- Object newTeam = teamClass.newInstance();
- teamInstances.add(newTeam);
-
- Class<?>[] activationArgumentTypes = new Class[0];
- Object[] activationArguments = null;
- switch(teamClass.activation) {
- case ALL_THREADS:
- activationArgumentTypes = new Class[]{Thread.class};
- activationArguments = new Object[] {TeamClassRecord.get_ALL_THREADS()};
- // fall through
- case THREAD:
- Method activationMethod = teamClass.clazz.getMethod("activate", activationArgumentTypes);
- activationMethod.invoke(newTeam, activationArguments);
- log(IStatus.OK, ">>> instantiated team: "+teamClass.clazz+", activation: "+teamClass.activation+" <<<");
- teamClass.markAsActivated();
- break;
- case NONE:
- // nothing ;-)
- }
- }
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- if (!permissionManagerReady)
- permissionManager.addBaseBundleObligations(teamInstances, new ArrayList<TeamClassRecord>(this.teamClasses), baseBundle);
- return teamInstances;
- }
-
- void log(int status, String msg) {
- TransformerPlugin.getDefault().log(status, msg);
- }
- void log(Throwable t, String msg) {
- TransformerPlugin.getDefault().log(t, msg);
- }
-}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/TransformerServiceDelegate.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/TransformerServiceDelegate.java
deleted file mode 100644
index 7918543..0000000
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/internal/TransformerServiceDelegate.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**********************************************************************
- * This file is part of "Object Teams Development Tooling"-Software
- *
- * Copyright 2010 Stephan Herrmann
- *
- * 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
- * $Id$
- *
- * Please visit http://www.eclipse.org/objectteams for updates and contact.
- *
- * Contributors:
- * Stephan Herrmann - Initial API and implementation
- **********************************************************************/
-package org.eclipse.objectteams.otequinox.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.instrument.ClassFileTransformer;
-import java.util.Collection;
-import java.util.List;
-
-import org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer;
-import org.eclipse.objectteams.otre.util.CallinBindingManager;
-
-import org.eclipse.objectteams.otequinox.hook.IOTTransformer;
-
-/**
- * Service implementation for providing org.eclipse.objectteams.otequinox.hook with an
- * access to the OTRE.
- *
- * @author stephan
- * @since 0.7.0
- */
-public class TransformerServiceDelegate implements IOTTransformer {
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.objectteams.otequinox.hook.IOTTransformer#getNewTransformer()
- */
- public ClassFileTransformer getNewTransformer() {
- return new ObjectTeamsTransformer();
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.objectteams.otequinox.hook.IOTTransformer#readOTAttributes(java.io.InputStream, java.lang.String, java.lang.ClassLoader)
- */
- public Object readOTAttributes(InputStream openStream, String file, ClassLoader loader)
- throws ClassFormatError, IOException
- {
- ObjectTeamsTransformer transformer = new ObjectTeamsTransformer();
- transformer.readOTAttributes(openStream, file, loader);
- return transformer;
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.objectteams.otequinox.hook.IOTTransformer#fetchAdaptedBases(java.lang.Object)
- */
- public Collection<String> fetchAdaptedBases(Object token) {
- try {
- return ((ObjectTeamsTransformer)token).fetchAdaptedBases();
- } catch (ClassCastException cce) {
- throw new IllegalArgumentException("Provided token is not an ObjectTeamsTransformer");
- }
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.objectteams.otequinox.hook.IOTTransformer#getRolesPerTeam(java.lang.String)
- */
- public List<String> getRolesPerTeam(String teamClassName) {
- return CallinBindingManager.getRolePerTeam(teamClassName);
- }
-
-}