Bug 549282 - [otdre] avoid logging CNFE below
TeamLoader.findUnloadableBaseClass()
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 85da45e..7e1f4dc 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
@@ -32,6 +32,7 @@
 import org.eclipse.objectteams.internal.osgi.weaving.Util.ProfileKind;
 import org.eclipse.objectteams.otequinox.ActivationKind;
 import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+import org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer;
 import org.objectteams.Team;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.hooks.weaving.WovenClass;
@@ -276,12 +277,17 @@
 			// use a throw-away class loader so we have a fresh chance to load any failed classes later
 			// (only initiating class loader remembers the failure, if this is discarded, the slate is clean):
 			ClassLoader tryLoader = new ClassLoader(teamClass.getClassLoader()) {};
-			for (@SuppressWarnings("null")@NonNull String baseclass : team.baseClassNames)
+			for (@SuppressWarnings("null")@NonNull String baseclass : team.baseClassNames) { 
+				Boolean previous = ObjectTeamsTransformer.initiatedByThrowAwayLoader.get();
 				try {
+					ObjectTeamsTransformer.initiatedByThrowAwayLoader.set(Boolean.TRUE);
 					tryLoader.loadClass(baseclass);
 				} catch (Throwable t) {
 					return baseclass;
+				} finally {
+					ObjectTeamsTransformer.initiatedByThrowAwayLoader.set(previous);
 				}
+			}
 		}
 		return null;
 	}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
index bab8ecc..4cf30cf 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
@@ -30,6 +30,7 @@
 import org.eclipse.objectteams.otredyn.bytecode.RedefineStrategyFactory;

 import org.eclipse.objectteams.otredyn.bytecode.asm.verify.OTCheckClassAdapter;

 import org.eclipse.objectteams.otredyn.runtime.TeamManager;

+import org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer;

 import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;

 import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;

 import org.eclipse.objectteams.runtime.IReweavingTask;

@@ -193,26 +194,16 @@
 					try {

 						redefine(definedClass);

 					} catch (ClassNotFoundException cnfe) {

-						throw new RuntimeException("OTDRE: Failed to redefine class: "+this.getName(), cnfe);

+						if (ObjectTeamsTransformer.initiatedByThrowAwayLoader.get() == Boolean.TRUE) {

+							scheduleRetry(definedClass);

+							return;

+						} else {

+							throw new RuntimeException("OTDRE: Failed to redefine class: "+this.getName(), cnfe);

+						}

 					} catch (Throwable t) {

 		//				t.printStackTrace(System.out);

 						// if redefinition failed (ClassCircularity?) install a runnable for deferred redefinition:

-						final Runnable previousTask = TeamManager.pendingTasks.get();

-						TeamManager.pendingTasks.set(new Runnable() {

-							public void run() {

-								if (previousTask != null)

-									previousTask.run();

-								try {

-									redefine(definedClass);

-								} catch (ClassNotFoundException e) {

-									e.printStackTrace(); // should never get here, since we expect CNFE already on the first attempt

-								}

-							}

-							@Override

-							public String toString() {

-								return "Retry "+AsmWritableBoundClass.this.toString();

-							}

-						});

+						scheduleRetry(definedClass);

 						return;

 					}

 				}

@@ -229,6 +220,25 @@
 		}

 	}

 

+	private void scheduleRetry(final Class<?> definedClass) {

+		final Runnable previousTask = TeamManager.pendingTasks.get();

+		TeamManager.pendingTasks.set(new Runnable() {

+			public void run() {

+				if (previousTask != null)

+					previousTask.run();

+				try {

+					redefine(definedClass);

+				} catch (ClassNotFoundException e) {

+					e.printStackTrace(); // should never get here, since we expect CNFE already on the first attempt

+				}

+			}

+			@Override

+			public String toString() {

+				return "Retry "+AsmWritableBoundClass.this.toString();

+			}

+		});

+	}

+

 	protected void superTransformation(Class<?> definedClass) throws IllegalClassFormatException {		

 		AbstractTeam mySuper = getSuperclass();

 		if (mySuper != null && mySuper.isLoaded()) {

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
index d600924..2ea7e2b 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
@@ -38,6 +38,12 @@
  */
 public class ObjectTeamsTransformer implements ClassFileTransformer {
 
+	/**
+	 * API for OT/Equinox, to signal when class loading is initiaed by a throw-away loader,
+	 * which implies that ClassNotFoundException should not be regarded as fatal.
+	 */
+	public static final ThreadLocal<Boolean> initiatedByThrowAwayLoader = new ThreadLocal<Boolean>();
+
 	private IWeavingContext weavingContext;
 	
 	private Set<String> boundBaseClassNames = new HashSet<String>();