Bug 511696: [otdre] debugger needs to refresh internal cache after
redefineClasses
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/META-INF/MANIFEST.MF
index 390f579..e6e5c37 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/META-INF/MANIFEST.MF
@@ -28,6 +28,7 @@
 Bundle-Activator: org.eclipse.objectteams.otdt.internal.debug.adaptor.OTDebugAdaptorPlugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
 Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.objectteams.otdt.internal.debug.adaptor;x-internal:=true;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor",
- org.eclipse.objectteams.otdt.internal.debug.adaptor.actions;x-internal:=true;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor",
- org.eclipse.objectteams.otdt.internal.debug.adaptor.launching;x-internal:=true;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor"
+Export-Package: org.eclipse.objectteams.otdt.internal.debug.adaptor;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor";x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.debug.adaptor.actions;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor";x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.debug.adaptor.dynamic;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor";x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.debug.adaptor.launching;ot-aspect-host="org.eclipse.objectteams.otdt.debug.adaptor";x-internal:=true
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/plugin.xml b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/plugin.xml
index 29ac957..200ce84 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/plugin.xml
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/plugin.xml
@@ -74,6 +74,11 @@
                class="org.eclipse.objectteams.otdt.internal.debug.adaptor.SourceLookupAdaptor"
                icon="platform:/plugin/org.eclipse.objectteams.otdt.ui/icons/ot/team_obj.gif">
          </team>
+         <team
+               activation="NONE"
+               class="org.eclipse.objectteams.otdt.internal.debug.adaptor.dynamic.RedefineClassesBPListener"
+               icon="platform:/plugin/org.eclipse.objectteams.otdt.ui/icons/ot/team_obj.gif">
+         </team>
       </aspectBinding>
      <aspectBinding
            icon="platform:/plugin/org.eclipse.objectteams.otdt.ui/icons/ot/calloutbinding_obj.gif">
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/OTDebugAdaptorPlugin.java b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/OTDebugAdaptorPlugin.java
index 2eb31bf..a0956c3 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/OTDebugAdaptorPlugin.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/OTDebugAdaptorPlugin.java
@@ -42,4 +42,9 @@
 	public static void logError(String msg) {
 		instance.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, msg));
 	}
+	
+	
+	public static void logException(String msg, Exception ex) {
+		instance.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, msg, ex));
+	}
 }
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/dynamic/RedefineClassesBPListener.java b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/dynamic/RedefineClassesBPListener.java
new file mode 100644
index 0000000..7d8f654
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/dynamic/RedefineClassesBPListener.java
@@ -0,0 +1,170 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2017 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.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.internal.debug.adaptor.dynamic;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.jdi.internal.ReferenceTypeImpl;
+import org.eclipse.jdi.internal.ValueCache;
+import org.eclipse.jdi.internal.jdwp.JdwpReferenceTypeID;
+import org.eclipse.jdt.core.dom.Message;
+import org.eclipse.jdt.debug.core.IJavaArray;
+import org.eclipse.jdt.debug.core.IJavaBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaBreakpointListener;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaObject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.core.IJavaType;
+import org.eclipse.jdt.debug.core.IJavaValue;
+import org.eclipse.jdt.debug.core.JDIDebugModel;
+import org.eclipse.objectteams.otdt.core.ext.WeavingScheme;
+import org.eclipse.objectteams.otdt.debug.internal.breakpoints.ClassRedefinitionBreakpoint;
+import org.eclipse.objectteams.otdt.internal.debug.adaptor.OTDebugAdaptorPlugin;
+
+import com.sun.jdi.VirtualMachine;
+
+import base org.eclipse.jdi.internal.VirtualMachineImpl;
+
+/**
+ * Listen to breakpoint hits on InstrumentationImpl.redefineClasses in order to
+ * <ul>
+ * <li>create obsolete {@link ReferenceTypeImpl} from internal cache
+ * <li>refresh breakpoints in the affected type
+ * </ul>
+ * Implemented as a team only to gain access to the cache inside {@link VirtualMachineImpl}.
+ */
+@SuppressWarnings("restriction")
+public team class RedefineClassesBPListener implements IJavaBreakpointListener {
+
+	/**
+	 * Conditionally get a breakpoint listener for class redefinition events (only for OTDRE). 
+	 */
+	public static IJavaBreakpointListener get(WeavingScheme scheme) {
+    	if (scheme == WeavingScheme.OTDRE)
+    		return new RedefineClassesBPListener();
+		return null;
+	}
+
+	@Override
+	public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
+	    if (!breakpoint.getMarker().exists())
+	    	return DONT_CARE;
+	    try {
+		    if (ClassRedefinitionBreakpoint.isRedefineClassesBreakpoint(breakpoint)) {
+		    	handleClassRedefinition(thread);
+				return IJavaBreakpointListener.DONT_SUSPEND;
+		    }
+	    }
+	    catch (Exception ex) {
+	 		OTDebugAdaptorPlugin.logException("RedefineClassesBPListener can't read infos from debugTarget anymore. Disconnected?", ex); //$NON-NLS-1$
+			// if something fails, let the debugger go on
+			return IJavaBreakpointListener.DONT_SUSPEND;
+		}
+
+	    return IJavaBreakpointListener.DONT_CARE;
+	}
+
+	private void handleClassRedefinition(IJavaThread thread) throws DebugException {
+		IStackFrame frame = thread.getTopStackFrame();
+		IVariable[] variables = frame.getVariables(); 
+		IValue values = variables[2].getValue();
+		if (values instanceof IJavaArray) {
+			IJavaValue[] arrayValues = ((IJavaArray) values).getValues();
+			for (IJavaValue value : arrayValues) {
+				if (value instanceof IJavaObject) {
+					IJavaValue clazz = ((IJavaObject) value).sendMessage("getDefinitionClass", "()Ljava/lang/Class;", null, thread, false);
+					IJavaValue name = ((IJavaObject) clazz).sendMessage("getName", "()Ljava/lang/String;", null, thread, false);
+					String className = name.getValueString();
+					VirtualMachine vm = ((org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) thread.getDebugTarget()).getVM();
+					removeTypeFromCache((org.eclipse.jdi.internal.VirtualMachineImpl) vm, className);
+					updateBreakpoints(thread.getDebugTarget(), className);
+				}
+			}
+		}
+	}
+
+	private void removeTypeFromCache(VirtualMachineImpl as VM vm, String typeName) {
+		vm.removeTypeFromCache(typeName);
+	}
+
+	/**
+	 * Gateway to inaccessible cache of ReferenceTypeImpl
+	 */
+	protected class VM playedBy VirtualMachineImpl {
+		@SuppressWarnings("decapsulation")
+		ValueCache getCachedReftypes() -> get ValueCache fCachedReftypes;
+		
+		protected void removeTypeFromCache(String typeName) {
+			List<JdwpReferenceTypeID> found = new ArrayList<>();
+			ValueCache cache = getCachedReftypes();
+			for (Object value : cache.values()) {
+				if (value instanceof ReferenceTypeImpl) { 
+					ReferenceTypeImpl refType = (ReferenceTypeImpl) value;
+					if (refType.name().equals(typeName))
+						found.add(refType.getRefTypeID());
+				}
+			}
+			/* alternative to above loop (but involves a JDWP request:
+			   List<ReferenceType> classes = target.jdiClassesByName(name);
+			 */
+			for (JdwpReferenceTypeID id : found) {
+				cache.remove(id);
+			}
+		}
+	}
+
+	private void updateBreakpoints(IDebugTarget debugTarget, String className) {
+		// cf. JavaHotCodeReplaceManager.redefineTypesJDK() -> target.reinstallBreakpointsIn()
+        IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager();
+        IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(JDIDebugModel.getPluginIdentifier());
+        for (IBreakpoint breakpoint : breakpoints) {
+			if (breakpoint instanceof IJavaLineBreakpoint) {
+				IJavaLineBreakpoint lineBreakpoint = (IJavaLineBreakpoint) breakpoint;
+				try {
+					if (lineBreakpoint.getTypeName().equals(className)) {
+						debugTarget.breakpointRemoved(lineBreakpoint, null);
+						debugTarget.breakpointAdded(lineBreakpoint);
+					}
+				} catch (CoreException e) {
+					OTDebugAdaptorPlugin.logException("Failed to update breakpoint", e);
+				}
+			}
+		}
+	}
+
+	// --- empty implementation of unused hooks: ---
+	@Override
+	public int installingBreakpoint(IJavaDebugTarget target, IJavaBreakpoint breakpoint, IJavaType type) {
+		return IJavaBreakpointListener.DONT_CARE;
+	}
+
+	@Override public void addingBreakpoint(IJavaDebugTarget target, IJavaBreakpoint breakpoint) { }
+	@Override public void breakpointInstalled(IJavaDebugTarget target, IJavaBreakpoint breakpoint) { }
+	@Override public void breakpointRemoved(IJavaDebugTarget target, IJavaBreakpoint breakpoint) { }
+	@Override public void breakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, DebugException exception) { }
+	@Override public void breakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, Message[] errors) { }
+}
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/JDTLaunchingAdaptor.java b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/JDTLaunchingAdaptor.java
index 29edddf..1172980 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/JDTLaunchingAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/JDTLaunchingAdaptor.java
@@ -34,6 +34,7 @@
 import org.eclipse.objectteams.otdt.debug.OTDebugPlugin;
 import org.eclipse.objectteams.otdt.debug.OTVMRunnerAdaptor;
 import org.eclipse.objectteams.otdt.debug.TeamBreakpointInstaller;
+import org.eclipse.objectteams.otdt.internal.debug.adaptor.dynamic.RedefineClassesBPListener;
 import org.eclipse.pde.internal.ui.IPDEUIConstants;
 
 import base org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
@@ -147,11 +148,14 @@
 				this.fAdaptor = null;
 				return;
 			}
-			this.fAdaptor = new OTVMRunnerAdaptor(getJavaProject(config));
+			IJavaProject javaProject = getJavaProject(config);
+			this.fAdaptor = new OTVMRunnerAdaptor(javaProject);
 			this.fAdaptor.setAdaptationArgs(config, mode, launch);
 			// install OT-breakpoints
-			if (ILaunchManager.DEBUG_MODE.equals(mode))
-				TeamBreakpointInstaller.installTeamBreakpoints(getJavaProject(config));
+			if (ILaunchManager.DEBUG_MODE.equals(mode)) {
+				TeamBreakpointInstaller.installTeamBreakpoints(javaProject,
+						RedefineClassesBPListener.get(this.fAdaptor.getWeavingScheme()));
+			}
 		}
 
 		// --- VM Arguments: ---
diff --git a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/PDELaunchingAdaptor.java b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/PDELaunchingAdaptor.java
index e008838..0c35cbd 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/PDELaunchingAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug.adaptor/src/org/eclipse/objectteams/otdt/internal/debug/adaptor/launching/PDELaunchingAdaptor.java
@@ -25,6 +25,7 @@
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.internal.core.util.Util;
 import org.eclipse.objectteams.otdt.core.ext.OTREContainer;
@@ -33,6 +34,7 @@
 import org.eclipse.objectteams.otdt.debug.TeamBreakpointInstaller;
 import org.eclipse.objectteams.otdt.internal.debug.adaptor.DebugMessages;
 import org.eclipse.objectteams.otdt.internal.debug.adaptor.OTDebugAdaptorPlugin;
+import org.eclipse.objectteams.otdt.internal.debug.adaptor.dynamic.RedefineClassesBPListener;
 import org.eclipse.objectteams.otequinox.TransformerPlugin;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.core.plugin.IPluginModelBase;
@@ -125,13 +127,15 @@
 	 * Installs breakpoints needed for the TeamMonitor into org.objectteams.Team.
 	 * Needs to find a project with OTJavaNature to do this.
 	 */
-	static void installOOTBreakpoints(IProject[] projects) throws CoreException
+	static void installOOTBreakpoints(IProject[] projects, String weavingMode) throws CoreException
 	{
 		if (projects != null)
 			for (IProject project : projects) 
 				// find org.objectteams.Team in any OT/J Project:
 				if (project.getNature(JavaCore.OTJ_NATURE_ID) != null) {
-					TeamBreakpointInstaller.installTeamBreakpoints(JavaCore.create(project));
+					IJavaProject javaProject = JavaCore.create(project);
+					TeamBreakpointInstaller.installTeamBreakpoints(javaProject,
+							RedefineClassesBPListener.get(WeavingScheme.valueOf(weavingMode)));
 					return; // good, done.
 				}
 		logException(null, Status.WARNING, DebugMessages.OTLaunching_no_OTJ_project_found);
@@ -166,9 +170,9 @@
 			if (isOTLaunch(configuration))
 				try {
 					IProject[] projects = getProjectsForProblemSearch(configuration, mode);
-					if (ILaunchManager.DEBUG_MODE.equals(mode))
-						PDELaunchingAdaptor.installOOTBreakpoints(projects);
 					determineWeavingMode(projects);
+					if (ILaunchManager.DEBUG_MODE.equals(mode))
+						PDELaunchingAdaptor.installOOTBreakpoints(projects, weavingMode);
 				} catch (DebugException dex) {
 					throw dex;
 				} catch (CoreException ex) {
diff --git a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/OTVMRunnerAdaptor.java b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/OTVMRunnerAdaptor.java
index a7c53f8..a6c9c2b 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/OTVMRunnerAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/OTVMRunnerAdaptor.java
@@ -66,6 +66,10 @@
 		this.weavingScheme = OTJavaNature.getWeavingScheme(javaProject);
 	}
 	
+	public WeavingScheme getWeavingScheme() {
+		return this.weavingScheme;
+	}
+
 	/**
 	 * Store the original arguments as passed to {@link ILaunchConfigurationDelegate#launch(ILaunchConfiguration, String, ILaunch, org.eclipse.core.runtime.IProgressMonitor)}
 	 * @param configuration see first argument of {@link ILaunchConfigurationDelegate#launch(ILaunchConfiguration, String, ILaunch, org.eclipse.core.runtime.IProgressMonitor) launch(..)}
diff --git a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/TeamBreakpointInstaller.java b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/TeamBreakpointInstaller.java
index 923c052..d46b1d4 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/TeamBreakpointInstaller.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/TeamBreakpointInstaller.java
@@ -32,9 +32,12 @@
 import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.jdt.core.IJavaProject;

 import org.eclipse.jdt.core.IType;

-import org.eclipse.jdt.core.JavaModelException;

+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.debug.core.IJavaBreakpointListener;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
-import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;

+import org.eclipse.jdt.debug.core.JDIDebugModel;
+import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
+import org.eclipse.objectteams.otdt.debug.internal.breakpoints.ClassRedefinitionBreakpoint;
 import org.eclipse.objectteams.otdt.debug.internal.breakpoints.OOTBreakpoints;
 
 /**
@@ -48,15 +51,22 @@
  */

 public class TeamBreakpointInstaller

 {

-    private static Hashtable<String, IBreakpoint> OT_BREAKPOINTS = new Hashtable<String, IBreakpoint>(5);

+    private static Hashtable<String, IBreakpoint> OT_BREAKPOINTS = new Hashtable<String, IBreakpoint>(5);
+
+    /** Optional listener for Instrumentation.redefineClasses (when running under OTDRE). */
+    private static IJavaBreakpointListener dynListener;
 
     /**
      * Request breakpoints to be installed once a new launch fires.
      * @param project used for lookup of org.objectteams.Team, i.e., this class must be in the projects classpath.
      * @throws CoreException various reasons, like could not find class org.objectteams.Team or could not create a breakpoint.
      */

-    public static void installTeamBreakpoints(IJavaProject project) throws CoreException

+    public static void installTeamBreakpoints(IJavaProject project, /*Nullable*/IJavaBreakpointListener dynListener)
+    		throws CoreException

     {       
+    	TeamBreakpointInstaller.dynListener = dynListener;
+    	if (dynListener != null)
+        	JDIDebugModel.addJavaBreakpointListener(dynListener);
         DebugPlugin.getDefault().addDebugEventListener(new IDebugEventSetListener() {
         	// since we want to avoid using the breakpoint manager (thus hiding synthetic breakpoints from the UI),
         	// we have to track creation of the debug target in order to manually install our breakpoints into the target:
@@ -82,7 +92,10 @@
 			}
 		});

         try

-        {

+        {
+        	if (dynListener != null && !OT_BREAKPOINTS.containsKey(ClassRedefinitionBreakpoint.BREAKPOINT_REDEFINE_CLASSES))
+        		OT_BREAKPOINTS.put(ClassRedefinitionBreakpoint.BREAKPOINT_REDEFINE_CLASSES,
+        				ClassRedefinitionBreakpoint.createRedefineClassesBreakpoint(project));

             IType oot = project.findType(new String(IOTConstants.STR_ORG_OBJECTTEAMS_TEAM));

             if (oot != null)

             {            	

@@ -115,7 +128,11 @@
 
     /** Unregister any previously installed breakpoints, so that the next launch will be without. */

     public static void uninstallTeamBreakpoints() throws CoreException

-    {

+    {
+    	if (dynListener != null) {
+    		JDIDebugModel.removeJavaBreakpointListener(dynListener);
+    		dynListener = null;
+    	}

         OT_BREAKPOINTS.clear();

     }
 }

diff --git a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/ClassRedefinitionBreakpoint.java b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/ClassRedefinitionBreakpoint.java
new file mode 100644
index 0000000..78dfc60
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/ClassRedefinitionBreakpoint.java
@@ -0,0 +1,66 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2017 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.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.debug.internal.breakpoints;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.debug.core.IJavaBreakpoint;
+import org.eclipse.objectteams.otdt.debug.OTDebugPlugin;
+
+public class ClassRedefinitionBreakpoint {
+	
+	public static final String BREAKPOINT_REDEFINE_CLASSES = OTDebugPlugin.PLUGIN_ID + "InstrumentationBreakpoint.redefineClasses"; //$NON-NLS-1$
+
+	static final String OT_SYNTHETIC_BREAKPOINT = OTDebugPlugin.PLUGIN_ID + "InstrumentationBreakpoint"; //$NON-NLS-1$
+	
+	static final String INSTRUMENTATION_IMPL = "sun.instrument.InstrumentationImpl"; //$NON-NLS-1$
+	static final String REDEFINE_CLASSSES = "redefineClasses"; //$NON-NLS-1$
+	static final String REDEFINE_CLASSSES_SIGNATURE = "([Ljava/lang/instrument/ClassDefinition;)V"; //$NON-NLS-1$
+
+    public static IJavaBreakpoint createRedefineClassesBreakpoint(IJavaProject project) throws CoreException {
+    	
+    	try {
+    		IType instrumentation = project.findType(INSTRUMENTATION_IMPL);
+    		if (instrumentation != null) {
+    			Map<String, Object> attributes = getBreakpointAttributes();
+    			attributes.put(BREAKPOINT_REDEFINE_CLASSES, Boolean.TRUE);
+    			return OOTBreakpoints.createMethodBreakpoint(instrumentation, REDEFINE_CLASSSES, REDEFINE_CLASSSES_SIGNATURE, false, -1, attributes);
+    		}
+    	}
+    	catch (JavaModelException ex) {
+    		throw new CoreException(new Status(IStatus.WARNING, OTDebugPlugin.PLUGIN_ID, IStatus.OK, "Cannot set breakpoints for tracking class redefinition", ex)); //$NON-NLS-1$
+    	}
+    	return null;
+    }
+
+    public static final boolean isRedefineClassesBreakpoint(IBreakpoint breakpoint) throws CoreException {
+        return breakpoint.getMarker().getAttribute(BREAKPOINT_REDEFINE_CLASSES) != null;
+    }
+    
+    private static Map<String, Object> getBreakpointAttributes() {
+        Map<String, Object> attrs = new HashMap<>();
+        attrs.put(OT_SYNTHETIC_BREAKPOINT, Boolean.TRUE);
+        return attrs;
+    }
+}
diff --git a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/OOTBreakpoints.java b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/OOTBreakpoints.java
index 4c7fb38..e867478 100644
--- a/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/OOTBreakpoints.java
+++ b/plugins/org.eclipse.objectteams.otdt.debug/src/org/eclipse/objectteams/otdt/debug/internal/breakpoints/OOTBreakpoints.java
@@ -56,6 +56,8 @@
 	public static final String ATTR_OT_BREAKPOINT_IMPLICIT_ACT   = OTDebugPlugin.PLUGIN_ID + ".TeamBreakpoint.ImplicitActivateMethod";
 	public static final String ATTR_OT_BREAKPOINT_IMPLICIT_DEACT = OTDebugPlugin.PLUGIN_ID + ".TeamBreakpoint.ImplicitDeactivateMethod";
 
+	private static final String FINALIZE = "finalize";
+	private static final String EMPTY_SIGNATURE = "()V";
 	
 	//associated with "public Team() {}"
     public static int getTeamConstructorLineNumber()
@@ -112,7 +114,8 @@
     {
     	Map<String, Boolean> finalizeMethodAttributes = getBreakpointAttributes();
     	finalizeMethodAttributes.put(OOTBreakpoints.ATTR_OT_BREAKPOINT_FINALIZE, Boolean.TRUE);
-    	return createOOTMethodBreakpoint(oot, getFinalizeMethodLineNumber(), finalizeMethodAttributes);    	
+    	return createMethodBreakpoint(oot, FINALIZE, EMPTY_SIGNATURE, true,
+    			getFinalizeMethodLineNumber(), finalizeMethodAttributes);    	
     }
         
     public static IBreakpoint createOOTActivateBreakpoint(IType oot)throws CoreException
@@ -158,16 +161,17 @@
 		return breakpoint;
 	}
     
-	public static IBreakpoint createOOTMethodBreakpoint(IType oot, int linenumber, Map attributes)
+	public static IJavaBreakpoint createMethodBreakpoint(IType type, String selector, String signature,
+			boolean entry, int linenumber, Map attributes)
 			throws CoreException
 	{
-		IResource teamResource = oot.getJavaProject().getResource();
+		IResource resource = type.getJavaProject().getResource();
 		IJavaBreakpoint breakpoint = JDIDebugModel.createMethodBreakpoint(
-				teamResource, 
-				oot.getFullyQualifiedName(), 
-				"finalize", 
-				"()V",
-				true /*entry*/, false /*exit*/, false /*native*/,
+				resource, 
+				type.getFullyQualifiedName(), 
+				selector, 
+				signature,
+				entry, !entry, false /*native*/,
 				linenumber, 
 				-1, -1, 0, 
 				false /*register*/, 
diff --git a/plugins/org.eclipse.objectteams.otdt.pde.ui/src/org/eclipse/objectteams/otdt/internal/pde/ui/OTEquinoxCommonLaunching.java b/plugins/org.eclipse.objectteams.otdt.pde.ui/src/org/eclipse/objectteams/otdt/internal/pde/ui/OTEquinoxCommonLaunching.java
deleted file mode 100644
index 742981b..0000000
--- a/plugins/org.eclipse.objectteams.otdt.pde.ui/src/org/eclipse/objectteams/otdt/internal/pde/ui/OTEquinoxCommonLaunching.java
+++ /dev/null
@@ -1,83 +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: OTEquinoxCommonLaunching.java 23470 2010-02-05 19:13:24Z 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.otdt.internal.pde.ui;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.debug.core.ILaunchManager;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.objectteams.otdt.debug.OTDebugPlugin;
-import org.eclipse.objectteams.otdt.debug.TeamBreakpointInstaller;
-
-/**
- * Shared implementation of OTEclipseApplicationLaunchConfiguration and OTEquinoxLaunchConfiguration
- * 
- * @author stephan
- * @since OTDT 1.1.3
- */
-public class OTEquinoxCommonLaunching 
-{
-	static final String HOOK_CONFIGURATOR = "-Dosgi.hook.configurators.include=org.eclipse.objectteams.otequinox.hook.HookConfigurator";//$NON-NLS-1$
-	static final String CLASSLOADER_LOCKING = "-Dosgi.classloader.lock=classname"; //$NON-NLS-1$
-	static final String REPOSITORY_WORKAROUND = "-Dot.equinox"; //$NON-NLS-1$ // this causes the WORKAROUND_REPOSITORY flag being set to true in OTRE.
-	static final String OT_DEBUG_VMARG = "-Dot.debug"; //$NON-NLS-1$
-	static final String[] OT_VM_ARGS = { HOOK_CONFIGURATOR, CLASSLOADER_LOCKING, REPOSITORY_WORKAROUND };
-	static final String[] OT_VM_DEBUG_ARGS = { HOOK_CONFIGURATOR, CLASSLOADER_LOCKING, REPOSITORY_WORKAROUND, OT_DEBUG_VMARG };
-
-	static String[] extendVMArguments(String[] args, String mode) {
-		String[] otArgs = OT_VM_ARGS;
-		if (mode != null && mode.equals(ILaunchManager.DEBUG_MODE))
-			otArgs = OT_VM_DEBUG_ARGS;
-	
-		if (args == null || args.length == 0)
-			return otArgs;
-	
-		String[] combinedArgs = new String[args.length + otArgs.length];
-		System.arraycopy(args, 0, combinedArgs, 0, args.length);
-		System.arraycopy(otArgs, 0, combinedArgs, args.length, otArgs.length);
-		return combinedArgs;
-	}
-	
-	static void installOOTBreakpoints(IProject[] projects)
-			throws CoreException 
-	{
-		IJavaProject jp = null;
-		if (projects != null) {
-			for (IProject project : projects) {
-				// find org.objectteams.Team in any OT/J Project:
-				if (project.getNature(JavaCore.OTJ_NATURE_ID) != null) {
-					jp = JavaCore.create(project);
-					TeamBreakpointInstaller.installTeamBreakpoints(jp);
-					break;
-				}
-			}
-		}
-		if (jp == null)
-			OTDebugPlugin.getDefault().getLog().log(
-					new Status(Status.WARNING, 
-							   OTPDEUIPlugin.PLUGIN_ID, 
-							   0, 
-							   OTPDEUIMessages.NoOTJPluginProject, 
-							   null));
-	}
-}