Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java5
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java181
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleActivation.java174
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java95
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java10
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java18
-rw-r--r--plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java133
7 files changed, 352 insertions, 264 deletions
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
index 9836ec337..8f425ea4d 100644
--- a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
@@ -1,7 +1,7 @@
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
- * Copyright 2009 Germany and Technical University Berlin, Germany.
+ * 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
@@ -11,7 +11,8 @@
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
- * Technical University Berlin - Initial API and implementation
+ * Technical University Berlin - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.internal.osgi.weaving;
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
index bc366f90c..3cb24f9cf 100644
--- a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
@@ -1,3 +1,19 @@
+/**********************************************************************
+ * 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.osgi.weaving.Activator.log;
@@ -6,13 +22,13 @@ import static org.eclipse.objectteams.osgi.weaving.Constants.ASPECT_BINDING_EXTP
import static org.eclipse.objectteams.osgi.weaving.Constants.BASE_PLUGIN;
import static org.eclipse.objectteams.osgi.weaving.Constants.CLASS;
import static org.eclipse.objectteams.osgi.weaving.Constants.ID;
+import static org.eclipse.objectteams.osgi.weaving.Constants.REQUIRED_FRAGMENT;
import static org.eclipse.objectteams.osgi.weaving.Constants.SELF;
import static org.eclipse.objectteams.osgi.weaving.Constants.SUPERCLASS;
import static org.eclipse.objectteams.osgi.weaving.Constants.TEAM;
import static org.eclipse.objectteams.osgi.weaving.Constants.TRANSFORMER_PLUGIN_ID;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -24,12 +40,19 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.objectteams.osgi.weaving.Constants;
-import org.eclipse.objectteams.otequinox.hook.IAspectRegistry;
import org.eclipse.objectteams.otequinox.hook.ILogger;
import org.objectteams.ITeam;
import org.osgi.framework.Bundle;
-import org.osgi.service.packageadmin.PackageAdmin;
+/**
+ * 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 {
@@ -46,17 +69,14 @@ public class AspectBindingRegistry {
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>();
+ private Set<String> selfAdaptingAspects= new HashSet<String>(); // TODO, never read / evaluated
- private HashMap<String, BaseBundleActivation> baseTripWires = new HashMap<>();
+ private HashMap<String, BaseBundleLoadTrigger> baseTripWires = new HashMap<>();
+ /** Record for one team waiting for instantiation/activation. */
static class WaitingTeamRecord {
- @Nullable Class<? extends ITeam> teamClass;
- @Nullable ITeam teamInstance;
+ @Nullable Class<? extends ITeam> teamClass; // ... either this is set
+ @Nullable ITeam teamInstance; // ... or this
AspectBinding aspectBinding;
String notFoundClass;
@@ -100,7 +120,7 @@ public class AspectBindingRegistry {
}
/* Load extensions for org.eclipse.objectteams.otequinox.aspectBindings and check aspect permissions. */
- public void loadAspectBindings(@Nullable PackageAdmin packageAdmin) {
+ public void loadAspectBindings(@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin) {
IConfigurationElement[] aspectBindingConfigs = RegistryFactory.getRegistry().getConfigurationElementsFor(
TRANSFORMER_PLUGIN_ID, ASPECT_BINDING_EXTPOINT_ID);
@@ -111,6 +131,7 @@ public class AspectBindingRegistry {
@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.");
@@ -125,12 +146,16 @@ public class AspectBindingRegistry {
continue;
}
String baseBundleId = basePlugins[0].getAttribute(ID);
-
-// FIXME(SH):
-// //base fragments?
-// IConfigurationElement[] fragments = basePlugins[0].getChildren(REQUIRED_FRAGMENT);
-// if (fragments != null && !checkRequiredFragments(aspectBundleId, baseBundleId, fragments)) // reported inside
-// continue;
+ 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?
@@ -150,7 +175,7 @@ public class AspectBindingRegistry {
addBindingForBaseBundle(realBaseBundleId, binding);
addBindingForAspectBundle(aspectBundleId, binding);
if (!baseTripWires.containsKey(realBaseBundleId))
- baseTripWires.put(realBaseBundleId, new BaseBundleActivation(realBaseBundleId, this, packageAdmin));
+ baseTripWires.put(realBaseBundleId, new BaseBundleLoadTrigger(realBaseBundleId, this, packageAdmin));
// now that binding.teamClasses is filled connect to super team, if requested:
@@ -166,6 +191,55 @@ public class AspectBindingRegistry {
}
}
+ @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);
@@ -214,10 +288,9 @@ public class AspectBindingRegistry {
}
}
-
/**
- * Internal API for TransformerHook:
- * see {@link IAspectRegistry#getAdaptedBasePlugins(Bundle)}
+ * 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());
@@ -234,75 +307,17 @@ public class AspectBindingRegistry {
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(@Nullable 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;
- }
-
+
/**
* Get the list of aspect bindings affecting the given base plugin.
*/
public @Nullable List<AspectBinding> getAdaptingAspectBindings(@Nullable String basePluginName) {
return aspectBindingsByBasePlugin.get(basePluginName);
}
-
- /**
- * 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);
- }
- }
/** Check if the given base bundle / base class mandate any loading/instantiation/activation of teams. */
public void triggerLoadingHooks(@Nullable String bundleName, @Nullable String className) {
- BaseBundleActivation activation = baseTripWires.get(bundleName);
+ BaseBundleLoadTrigger activation = baseTripWires.get(bundleName);
if (activation != null)
activation.fire(className);
}
@@ -338,7 +353,7 @@ public class AspectBindingRegistry {
}
for(WaitingTeamRecord record : currentList) {
try {
- BaseBundleActivation.instantiateWaitingTeam(record, deferredTeams);
+ new TeamLoader(deferredTeams).instantiateWaitingTeam(record);
} catch (Exception e) {
log(e, "Failed to instantiate team "+record.getTeamName());
continue;
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleActivation.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleActivation.java
deleted file mode 100644
index c35d734aa..000000000
--- a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleActivation.java
+++ /dev/null
@@ -1,174 +0,0 @@
-package org.eclipse.objectteams.internal.osgi.weaving;
-
-import static org.eclipse.objectteams.osgi.weaving.Activator.log;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-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.osgi.weaving.ActivationKind;
-import org.eclipse.objectteams.otequinox.hook.ILogger;
-import org.objectteams.ITeam;
-import org.objectteams.Team;
-import org.osgi.framework.Bundle;
-
-/**
- * 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 BaseBundleActivation {
-
- private AspectBindingRegistry aspectBindingRegistry;
- @SuppressWarnings("deprecation")
- private org.osgi.service.packageadmin.PackageAdmin admin;
-
- private String baseBundleName;
-
- private boolean teamsScanned = false;
-
-
- public BaseBundleActivation(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 loading/instantiation/activation. */
- public void fire(String className) {
- List<AspectBindingRegistry.WaitingTeamRecord> deferredTeamClasses = new ArrayList<>();
- List<AspectBinding> aspectBindings = aspectBindingRegistry.getAdaptingAspectBindings(baseBundleName);
- if (aspectBindings != null) {
- for (AspectBinding aspectBinding : aspectBindings) {
- if (aspectBinding.activated)
- continue;
- 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 (shouldScan())
- scanTeamClasses(aspectBundle, aspectBinding);
- if (loadTeams(aspectBundle, aspectBinding, className, deferredTeamClasses))
-// aspectBinding.activated = true; // FIXME(SH): this still spoils team activation, the given class may not be the trigger
- ;
- }
- if (!deferredTeamClasses.isEmpty())
- aspectBindingRegistry.addDeferredTeamClasses(deferredTeamClasses);
- }
- }
-
- private synchronized boolean shouldScan() {
- boolean shouldScan = !teamsScanned;
- teamsScanned = true;
- return shouldScan;
- }
-
- /** Read OT attributes of all teams in aspectBinding and collect affected base classes. */
- private void scanTeamClasses(Bundle bundle, AspectBinding aspectBinding) {
- List<String> allTeams = aspectBinding.getAllTeams();
- ClassScanner scanner = new ClassScanner();
- for (String teamName : allTeams) {
- try {
- scanner.readOTAttributes(bundle, teamName);
- aspectBinding.addBaseClassNames(teamName, scanner.getCollectedBaseClassNames());
- } catch (Exception e) {
- log(e, "Failed to load team class "+teamName);
- }
- }
- }
-
- /** Team loading, 1st attempt (trying to do all three phases load/instantiate/activate). */
- private boolean loadTeams(Bundle aspectBundle, AspectBinding aspectBinding, String className, List<WaitingTeamRecord> deferredTeamClasses) {
- Collection<String> teamsForBase = aspectBinding.getTeamsForBase(className);
- if (teamsForBase == null) return true;
- TeamLoading delegate = new TeamLoading(deferredTeamClasses);
- for (String teamForBase : teamsForBase) {
- // Load:
- Class<? extends ITeam> teamClass;
- try {
- teamClass = (Class<? extends ITeam>) aspectBundle.loadClass(teamForBase);
- } catch (ClassNotFoundException e) {
- log(e, "Failed to load team "+teamForBase);
- continue;
- }
- // Instantiate?
- ActivationKind activationKind = aspectBinding.getActivation(teamForBase);
- if (activationKind == ActivationKind.NONE)
- continue;
- ITeam teamInstance = delegate.instantiateTeam(aspectBinding, teamClass, teamForBase);
- if (teamInstance == null)
- continue;
- // Activate?
- delegate.activateTeam(aspectBinding, teamForBase, teamInstance, activationKind);
- }
- return !delegate.needDeferring; // TODO, need to figure out whether we're done with aspectBinding.
- }
-
- /** Team loading, subsequent attempts. */
- public static void instantiateWaitingTeam(WaitingTeamRecord record, List<WaitingTeamRecord> deferredTeams)
- throws InstantiationException, IllegalAccessException
- {
- ITeam teamInstance = record.teamInstance;
- String teamName = record.getTeamName();
- TeamLoading delegate = new TeamLoading(deferredTeams);
- if (teamInstance == null) {
- // Instantiate (we only get here if activationKind != NONE)
- teamInstance = delegate.instantiateTeam(record.aspectBinding, record.teamClass, teamName);
- if (teamInstance == null)
- return;
- }
- // Activate?
- ActivationKind activationKind = record.aspectBinding.getActivation(teamName);
- delegate.activateTeam(record.aspectBinding, teamName, teamInstance, activationKind);
- }
-
- /* Common parts for both first and subsequent loading attempts. */
- private static class TeamLoading {
- List<WaitingTeamRecord> deferredTeams;
- boolean needDeferring; // did we record the fact that a team needs deferring?
-
- public TeamLoading(List<WaitingTeamRecord> deferredTeams) {
- this.deferredTeams = deferredTeams;
- }
-
- @Nullable ITeam instantiateTeam(AspectBinding aspectBinding, Class<? extends ITeam> teamClass, String teamName) {
- try {
- ITeam instance = teamClass.newInstance();
- log(ILogger.INFO, "Instantiated team "+teamName);
- return instance;
- } catch (NoClassDefFoundError ncdfe) {
- needDeferring = true;
- 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;
- }
- void activateTeam(AspectBinding aspectBinding, String teamName, ITeam teamInstance, ActivationKind activationKind)
- {
- try {
- switch (activationKind) {
- case ALL_THREADS:
- teamInstance.activate(Team.ALL_THREADS);
- break;
- case THREAD:
- teamInstance.activate();
- break;
- //$CASES-OMITTED$
- }
- } catch (NoClassDefFoundError e) {
- deferredTeams.add(new WaitingTeamRecord(teamInstance, aspectBinding, e.getMessage().replace('/','.'))); // TODO(SH): synchronization
- } catch (Throwable t) {
- // application errors during activation
- log(t, "Failed to activate team "+teamName);
- }
- }
- }
-}
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
new file mode 100644
index 000000000..cd8587e16
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
@@ -0,0 +1,95 @@
+/**********************************************************************
+ * 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.osgi.weaving.Activator.log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.osgi.framework.Bundle;
+
+/**
+ * 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;
+
+ private boolean teamsScanned = false;
+
+
+ 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 loading/instantiation/activation. */
+ public void fire(String className) {
+ List<AspectBindingRegistry.WaitingTeamRecord> deferredTeamClasses = new ArrayList<>();
+ List<AspectBinding> aspectBindings = aspectBindingRegistry.getAdaptingAspectBindings(baseBundleName);
+ if (aspectBindings != null) {
+ for (AspectBinding aspectBinding : aspectBindings) {
+ if (aspectBinding.activated)
+ 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 (shouldScan())
+ scanTeamClasses(aspectBundle, aspectBinding);
+ TeamLoader loading = new TeamLoader(deferredTeamClasses);
+ if (loading.loadTeams(aspectBundle, aspectBinding, className))
+// aspectBinding.activated = true; // FIXME(SH): this still spoils team activation, the given class may not be the trigger
+ ;
+ }
+ if (!deferredTeamClasses.isEmpty())
+ aspectBindingRegistry.addDeferredTeamClasses(deferredTeamClasses);
+ }
+ }
+
+ private synchronized boolean shouldScan() {
+ boolean shouldScan = !teamsScanned;
+ teamsScanned = true;
+ return shouldScan;
+ }
+
+ /** Read OT attributes of all teams in aspectBinding and collect affected base classes. */
+ private void scanTeamClasses(Bundle bundle, AspectBinding aspectBinding) {
+ List<String> allTeams = aspectBinding.getAllTeams();
+ ClassScanner scanner = new ClassScanner();
+ for (String teamName : allTeams) {
+ try {
+ scanner.readOTAttributes(bundle, teamName);
+ aspectBinding.addBaseClassNames(teamName, scanner.getCollectedBaseClassNames());
+ } catch (Exception e) {
+ log(e, "Failed to load team class "+teamName);
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java
index 377fe1d6e..ebc053ea9 100644
--- a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/ClassScanner.java
@@ -1,18 +1,18 @@
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
- * Copyright 2008, 2010 Technical University Berlin, Germany.
+ * 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
- * $Id: ClassScanner.java 23461 2010-02-04 22:10:39Z stephan $
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
- * Technical University Berlin - Initial API and implementation
+ * Technical University Berlin - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.internal.osgi.weaving;
@@ -32,8 +32,8 @@ import org.eclipse.objectteams.otre.util.CallinBindingManager;
import org.osgi.framework.Bundle;
/**
- * Bridge for the TransformerPlugin by which it can access the ObjectTeamsTransformer
- * without accessing that OTRE class.
+ * Simple facility for scanning class files for OT Attributes without
+ * actually doing any weaving.
*
* @author stephan
* @since 1.2.0
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
index 3c51b4fb8..3371dfc59 100644
--- a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
@@ -1,3 +1,18 @@
+/**********************************************************************
+ * 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.osgi.weaving.Activator.log;
@@ -14,6 +29,9 @@ import org.osgi.framework.hooks.weaving.WeavingHook;
import org.osgi.framework.hooks.weaving.WovenClass;
import org.osgi.framework.wiring.BundleWiring;
+/**
+ * This class integrates the OT/J weaver into OSGi using the standard API {@link WeavingHook}.
+ */
public class OTWeavingHook implements WeavingHook {
private AspectBindingRegistry aspectBindingRegistry;
diff --git a/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
new file mode 100644
index 000000000..794d7289c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.osgi.weaving/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
@@ -0,0 +1,133 @@
+/**********************************************************************
+ * 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.osgi.weaving.Activator.log;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBindingRegistry.WaitingTeamRecord;
+import org.eclipse.objectteams.osgi.weaving.ActivationKind;
+import org.eclipse.objectteams.otequinox.hook.ILogger;
+import org.objectteams.ITeam;
+import org.objectteams.Team;
+import org.osgi.framework.Bundle;
+
+/**
+ * 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;
+
+ public TeamLoader(List<WaitingTeamRecord> deferredTeams) {
+ this.deferredTeams = deferredTeams;
+ }
+
+ /** Team loading, 1st attempt (trying to do all three phases load/instantiate/activate). */
+ public boolean loadTeams(Bundle aspectBundle, AspectBinding aspectBinding, String className) {
+ Collection<String> teamsForBase = aspectBinding.getTeamsForBase(className);
+ if (teamsForBase == null) return true;
+ for (String teamForBase : teamsForBase) {
+ // Load:
+ Class<? extends ITeam> teamClass;
+ try {
+ teamClass = (Class<? extends ITeam>) aspectBundle.loadClass(teamForBase);
+ } catch (ClassNotFoundException e) {
+ log(e, "Failed to load team "+teamForBase);
+ continue;
+ }
+ // Instantiate?
+ ActivationKind activationKind = aspectBinding.getActivation(teamForBase);
+ if (activationKind == ActivationKind.NONE)
+ continue;
+ ITeam teamInstance = instantiateTeam(aspectBinding, teamClass, teamForBase);
+ if (teamInstance == null)
+ continue;
+ // Activate?
+ activateTeam(aspectBinding, teamForBase, teamInstance, activationKind);
+ }
+ return !needDeferring; // TODO, need to figure out whether we're done with aspectBinding.
+ }
+
+ /** Team loading, subsequent attempts. */
+ public void instantiateWaitingTeam(WaitingTeamRecord record)
+ throws InstantiationException, IllegalAccessException
+ {
+ ITeam 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);
+ }
+
+ private @Nullable ITeam instantiateTeam(AspectBinding aspectBinding, Class<? extends ITeam> teamClass, String teamName) {
+ try {
+ ITeam instance = teamClass.newInstance();
+ log(ILogger.INFO, "Instantiated team "+teamName);
+ return instance;
+ } catch (NoClassDefFoundError ncdfe) {
+ needDeferring = true;
+ 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, ITeam teamInstance, ActivationKind activationKind)
+ {
+ try {
+ switch (activationKind) {
+ case ALL_THREADS:
+ teamInstance.activate(Team.ALL_THREADS);
+ break;
+ case THREAD:
+ teamInstance.activate();
+ break;
+ //$CASES-OMITTED$
+ default:
+ break;
+ }
+ } catch (NoClassDefFoundError e) {
+ deferredTeams.add(new WaitingTeamRecord(teamInstance, aspectBinding, e.getMessage().replace('/','.'))); // TODO(SH): synchronization
+ } catch (Throwable t) {
+ // application errors during activation
+ log(t, "Failed to activate team "+teamName);
+ }
+ }
+}

Back to the top