Bug 406518 - migrate OT/Equinox to the standard OSGi WeavingHook
- try harder to avoid duplicate imports
- avoid double instantiation/activation of team with multiple bindings
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
index c64986a..e2cc2d8 100644
--- 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
@@ -128,34 +128,32 @@
 			if (dot != -1)
 				packageOfTeam = teamName.substring(0, dot);
 			String packageWithAttribute = packageOfTeam+";"+OT_ASPECT_HOST_ATTRIBUTE+"=\""+aspectPlugin+"\"";
-
-			List<String> imports = baseClass.getDynamicImports();
-			for (String imp : imports)
-				if (imp.equals(packageOfTeam) || imp.equals(packageWithAttribute))
-					return;
 			
-			checkExported: {
-				Bundle aspectBundle = AspectBinding.this.aspectBundle;
-				BundleRevision bundleRevision = aspectBundle != null ? aspectBundle.adapt(BundleRevision.class) : null;
-				if (bundleRevision != null) { // catch uninstalled state
-					for (Capability capability : bundleRevision.getCapabilities(PackageNamespace.PACKAGE_NAMESPACE)) {
-						Object exported = capability.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
-						if (exported instanceof String && exported.equals(packageOfTeam)) {
-							if (capability.getAttributes().containsKey(OT_ASPECT_HOST_ATTRIBUTE)) {
-								imports.add(packageWithAttribute);
-							} else {
-								log(IStatus.WARNING, "Package "+packageOfTeam+" for team "+teamName.substring(dot+1)+" is exported without an 'ot-aspect-host' attribute.");
-								imports.add(packageOfTeam);
+			if (!OTWeavingHook.hasImport(baseClass, packageOfTeam, packageWithAttribute)) {	
+				checkExported: {
+					List<String> imports = baseClass.getDynamicImports();
+					Bundle aspectBundle = AspectBinding.this.aspectBundle;
+					BundleRevision bundleRevision = aspectBundle != null ? aspectBundle.adapt(BundleRevision.class) : null;
+					if (bundleRevision != null) { // catch uninstalled state
+						for (Capability capability : bundleRevision.getCapabilities(PackageNamespace.PACKAGE_NAMESPACE)) {
+							Object exported = capability.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
+							if (exported instanceof String && exported.equals(packageOfTeam)) {
+								if (capability.getAttributes().containsKey(OT_ASPECT_HOST_ATTRIBUTE)) {
+									imports.add(packageWithAttribute);
+								} else {
+									log(IStatus.WARNING, "Package "+packageOfTeam+" for team "+teamName.substring(dot+1)+" is exported without an 'ot-aspect-host' attribute.");
+									imports.add(packageOfTeam);
+								}
+								break checkExported;
 							}
-							break checkExported;
 						}
+						log(IStatus.ERROR, "Package "+packageOfTeam+" for team "+teamName.substring(dot+1)+" is not exported by its bundle "+aspectPlugin);
+					} else {
+						log(IStatus.WARNING, "Can't check exporting of "+teamName+", bundle information for "+aspectPlugin+" is not available");
 					}
-					log(IStatus.ERROR, "Package "+packageOfTeam+" for team "+teamName.substring(dot+1)+" is not exported by its bundle "+aspectPlugin);
-				} else {
-					log(IStatus.WARNING, "Can't check exporting of "+teamName+", bundle information for "+aspectPlugin+" is not available");
 				}
+				log(IStatus.INFO, "Added dependency from base "+baseClass.getClassName()+" to package '"+packageOfTeam+"'");
 			}
-			log(IStatus.INFO, "Added dependency from base "+baseClass.getClassName()+" to package '"+packageOfTeam+"'");
 			if (direction != -1) {
 				importsAddedToSuper = true;
 				final TeamBinding superTeam2 = superTeam;
@@ -191,7 +189,8 @@
 	static class BaseBundle {
 		String bundleName;
 		/** Team classes indexed by base classes that should trigger activating the team. */
-		private HashMap<String, Set<TeamBinding>> teamsPerBase = new HashMap<>();		
+		private HashMap<String, Set<TeamBinding>> teamsPerBase = new HashMap<>();
+		boolean otreAdded;		
 
 		public BaseBundle(String bundleName) {
 			this.bundleName = bundleName;
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
index 942aa12..b01b500 100644
--- 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
@@ -150,7 +150,7 @@
 				@NonNull String realBaseBundleId = baseBundleId.toUpperCase().equals(SELF) ? aspectBundleId : baseBundleId;
 				addBindingForBaseBundle(realBaseBundleId, binding);
 				addBindingForAspectBundle(aspectBundleId, binding);
-				hook.setBaseTripWire(packageAdmin, realBaseBundleId);
+				hook.setBaseTripWire(packageAdmin, realBaseBundleId, baseBundleLookup.get(realBaseBundleId));
 
 				log(IStatus.INFO, "registered:\n"+binding);
 			} catch (Throwable t) {
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
index 29623a5..d44d63d 100644
--- 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
@@ -24,6 +24,7 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.hooks.weaving.WovenClass;
 
@@ -39,13 +40,15 @@
 	private @Nullable org.osgi.service.packageadmin.PackageAdmin admin;
 
 	private String baseBundleName;	
+	@Nullable private BaseBundle baseBundle; // null when representing an aspectBundle with SELF-adapting teams
 	private boolean otreAdded = false;
 	private List<AspectBinding> aspectBindings = new ArrayList<>();
 
-	public BaseBundleLoadTrigger(String bundleSymbolicName, AspectBindingRegistry aspectBindingRegistry, 
+	public BaseBundleLoadTrigger(String bundleSymbolicName, @Nullable BaseBundle baseBundle, AspectBindingRegistry aspectBindingRegistry, 
 			@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin admin) 
 	{
 		this.baseBundleName = bundleSymbolicName;
+		this.baseBundle = baseBundle;
 		this.aspectBindingRegistry = aspectBindingRegistry;
 		this.admin = admin;
 	}
@@ -62,8 +65,10 @@
 
 		// (1) OTRE import added once per base bundle:
 		synchronized(this) {
-			if (!otreAdded) {
+			final BaseBundle baseBundle2 = baseBundle;
+			if (!otreAdded && !(baseBundle2 != null && baseBundle2.otreAdded)) {
 				otreAdded = true;
+				if (baseBundle2 != null) baseBundle2.otreAdded = true;
 				log(IStatus.INFO, "Adding OTRE import to "+baseBundleName);
 				List<String> imports = baseClass.getDynamicImports();
 				imports.add("org.objectteams");
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
index c9980ed..7536630 100644
--- 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
@@ -29,6 +29,7 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
 import org.eclipse.objectteams.internal.osgi.weaving.Util.ProfileKind;
 import org.eclipse.objectteams.otequinox.TransformerPlugin;
 import org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer;
@@ -38,7 +39,9 @@
 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.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.resource.Wire;
 import org.osgi.service.component.ComponentContext;
 
 
@@ -99,10 +102,10 @@
 	 * Callback during AspectBindingRegistry#loadAspectBindings():
 	 * Set-up a trip wire to fire when the mentioned base bundle is loaded.
 	 */
-	void setBaseTripWire(@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin, @NonNull String baseBundleId) 
+	void setBaseTripWire(@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin, @NonNull String baseBundleId, BaseBundle baseBundle) 
 	{
 		if (!baseTripWires.containsKey(baseBundleId))
-			baseTripWires.put(baseBundleId, new BaseBundleLoadTrigger(baseBundleId, aspectBindingRegistry, packageAdmin));
+			baseTripWires.put(baseBundleId, new BaseBundleLoadTrigger(baseBundleId, baseBundle, aspectBindingRegistry, packageAdmin));
 	}
 
 	/** Check if the given base bundle / base class mandate any loading/instantiation/activation of teams. */
@@ -221,4 +224,18 @@
 			instantiateScheduledTeams(className);
 		}
 	}
+
+	static boolean hasImport(WovenClass clazz, String packageName, String packageWithAttribute) {
+		List<String> imports = clazz.getDynamicImports();
+		for (String imp : imports)
+			if (imp.equals(packageName) || imp.equals(packageWithAttribute))
+				return true;
+		for (Wire wire : clazz.getBundleWiring().getRequiredResourceWires(PackageNamespace.PACKAGE_NAMESPACE)) {
+			Object packageValue = wire.getRequirement().getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
+			if (packageName.equals(packageValue) || packageWithAttribute.equals(packageValue))
+				return true;
+		}
+		return false;
+	
+	}
 }
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
index adf0cd1..9e5e72d 100644
--- 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
@@ -156,7 +156,8 @@
 		synchronized(aspectBinding) {
 			if (!isReadyToLoad(aspectBinding, team, teamName, activationKind))
 				return;
-			team.isActivated = true;
+			for (TeamBinding equivalent : team.equivalenceSet)
+				equivalent.isActivated = true;
 		}
 
 		try {