1GGZFP6
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java
index 01e9c70..40a3e82 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java
@@ -187,6 +187,17 @@
 	}

 	

 	/**

+	 * Returns whether the given breakpoint is a Java line breakpoint.

+	 */

+	public static boolean isJavaLineBreakpoint(IMarker breakpoint) {

+		try {

+			return breakpoint.isSubtypeOf(IJavaDebugConstants.JAVA_LINE_BREAKPOINT);

+		} catch (CoreException e) {

+			return false;

+		}

+	}

+	

+	/**

 	 * Returns whether the given breakpoint is a run to line breakpoint.

 	 */

 	public static boolean isRunToLineBreakpoint(IMarker breakpoint) {

diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java
index 3145b4d..7285a59 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java
@@ -37,7 +37,7 @@
 	private final static String ERROR_HCR_NOT_SUPPORTED = ERROR + "hcr.not_supported";

 	private final static String ERROR_HCR_FAILED = ERROR + "hcr.failed";

 	private final static String ERROR_HCR_IGNORED = ERROR + "hcr.ignored";

-	private final static String ERROR_BREAKPOINT_NO_TYPE = ERROR + "breakpoint.no_type";	

+	protected final static String ERROR_BREAKPOINT_NO_TYPE = ERROR + "breakpoint.no_type";	

 	private final static String ERROR_RESUME_NOT_SUPPORTED = ERROR + "resume.not_supported";

 	private final static String ERROR_SUSPEND_NOT_SUPPORTED = ERROR + "suspend.not_supported";

 	private final static String ERROR_TERMINATE_NOT_SUPPORTED = ERROR + "terminate.not_supported";

@@ -763,7 +763,7 @@
 			exceptionBreakpointAdded(breakpoint);

 		} else if (DebugJavaUtils.isMethodEntryBreakpoint(breakpoint)) {

 			methodEntryBreakpointAdded(breakpoint);

-		} else {

+		} else if (DebugJavaUtils.isJavaLineBreakpoint(breakpoint)) {

 			lineBreakpointAdded(breakpoint);

 		}

 	}

@@ -1272,7 +1272,7 @@
 	 * Attempts to install a deferred breakpoint

 	 * into the newly loaded class.

 	 */

-	private void installDeferredBreakpoints(ClassPrepareEvent event) {

+	protected void installDeferredBreakpoints(ClassPrepareEvent event) {

 		String className= jdiGetTypeName(event.referenceType());

 		String topLevelName= className;

 		int index= className.indexOf('$');

@@ -1317,7 +1317,7 @@
 			exceptionBreakpointRemoved(breakpoint);

 		} else if (DebugJavaUtils.isMethodEntryBreakpoint(breakpoint)) {

 			methodEntryBreakpointRemoved(breakpoint);

-		} else {

+		} else if (DebugJavaUtils.isJavaLineBreakpoint(breakpoint)) {

 			lineBreakpointRemoved(breakpoint);

 		}

 	}

diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternBreakpointFactory.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternBreakpointFactory.java
new file mode 100644
index 0000000..4f4f0fc
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternBreakpointFactory.java
@@ -0,0 +1,73 @@
+package org.eclipse.jdt.internal.debug.pattern;

+
+import org.eclipse.core.resources.*;

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.debug.core.DebugException;

+import org.eclipse.debug.core.DebugPlugin;

+import org.eclipse.jdt.debug.core.JDIDebugModel;

+


+/**

+ * Creates pattern breakpoints.  Pattern breakpoints

+ * are only installed in <code>PatternDebugTarget</code>s.

+ */

+public class PatternBreakpointFactory {

+	/**

+	 * Singleton

+	 */

+	private static PatternBreakpointFactory fgDefault;

+	

+	/**

+	 * Singleton

+	 */	

+	public static PatternBreakpointFactory getDefault() {

+		if (fgDefault == null)

+			fgDefault= new PatternBreakpointFactory();

+		return fgDefault;

+	}

+	

+	/**

+	 * Singleton

+	 */

+	private PatternBreakpointFactory() {}

+	

+	public IMarker createLineBreakpoint(IFile file, int line) throws DebugException {

+		BreakpointCreator wr= new BreakpointCreator(file, line);

+


+		try {

+			ResourcesPlugin.getWorkspace().run(wr, null);

+		} catch (CoreException e) {

+			throw new DebugException(e.getStatus());

+		}

+		

+		return wr.getBreakpoint();

+	}

+}

+


+/**

+ * @see org.eclipse.core.resources.IWorkspaceRunnable

+ */

+class BreakpointCreator implements IWorkspaceRunnable {

+	protected IMarker fBreakpoint;

+	protected IFile fFile;

+	protected int fLine;

+
	public BreakpointCreator(IFile file, int line) {

+		fFile = file;

+		fLine = line;

+	}

+


+	public IMarker getBreakpoint() {

+		return fBreakpoint;

+	}

+	

+	/**

+	 * @see IWorkspaceRunnable

+	 */

+	public void run(IProgressMonitor monitor) throws CoreException {

+		// create the marker

+		fBreakpoint = fFile.createMarker(JDIDebugModel.getPluginIdentifier() + ".patternBreakpoint");

+		// configure the standard attributes

+		DebugPlugin.getDefault().getBreakpointManager().configureLineBreakpoint(

+			fBreakpoint, JDIDebugModel.getPluginIdentifier(), true, fLine, -1, -1);

+	}

+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugModel.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugModel.java
new file mode 100644
index 0000000..c35c470
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugModel.java
@@ -0,0 +1,75 @@
+package org.eclipse.jdt.internal.debug.pattern;

+


+import com.sun.jdi.VirtualMachine;

+import org.eclipse.core.resources.IWorkspaceRunnable;

+import org.eclipse.core.resources.ResourcesPlugin;

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.debug.core.model.IDebugTarget;

+import org.eclipse.debug.core.model.IProcess;

+import org.eclipse.jdt.debug.core.JDIDebugModel;

+


+/**

+ * Creates PatternDebugTargets

+ */

+public class PatternDebugModel {

+	

+	/**

+	 * The type identifier for a pattern breakpoint.

+	 */

+	public static final String PATTERN_BREAKPOINT = JDIDebugModel.getPluginIdentifier() + ".patternBreakpoint";

+	

+	/**

+	 * The <code>PATTERN</code> field is used to match 

+	 * classfile names to patterns given by breakpoints.

+	 * This is used to install breakpoints.

+	 */

+	public static final String PATTERN= "pattern";

+	

+	/**

+	 * Not to be instantiated.

+	 */

+	private PatternDebugModel() {}

+	

+	/**

+	 * Creates a new PatternDebugTarget.

+	 * @see org.eclipse.jdt.internal.debug.core.JDIDebugModel.newDebugTarget(VirtualMachine, String, IProcess, boolean, boolean)

+	 */

+	public static IDebugTarget newDebugTarget(VirtualMachine vm, String name, IProcess process, boolean allowTerminate, boolean allowDisconnect) {

+		TargetCreator creator= new TargetCreator(vm, name, process, allowTerminate, allowDisconnect);

+		try {

+			ResourcesPlugin.getWorkspace().run(creator, null);

+		} catch (CoreException e) {

+			e.printStackTrace();

+		}

+		return creator.getTarget();

+	}

+


+	/**

+	 * @see org.eclipse.core.resources.IWorkspaceRunnable

+	 */	

+	static class TargetCreator implements IWorkspaceRunnable {

+		IDebugTarget fTarget;

+		VirtualMachine fVM;

+		String fName;

+		IProcess fProcess;

+		boolean fAllowTerminate;

+		boolean fAllowDisconnect;

+		

+		public TargetCreator(VirtualMachine vm, String name, IProcess process, boolean allowTerminate, boolean allowDisconnect) {

+			fVM= vm;

+			fName= name;

+			fProcess= process;

+			fAllowTerminate= allowTerminate;

+			fAllowDisconnect= allowDisconnect;

+		}

+		

+		public void run(IProgressMonitor m) {

+			fTarget= new PatternDebugTarget(fVM, fName, fAllowTerminate, fAllowDisconnect, fProcess);

+		}

+		

+		public IDebugTarget getTarget() {

+			return fTarget;

+		}

+	}

+}

diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugTarget.java
new file mode 100644
index 0000000..cdf19d2
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/pattern/PatternDebugTarget.java
@@ -0,0 +1 @@
+package org.eclipse.jdt.internal.debug.pattern;

import com.sun.jdi.*;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.EventRequest;
import java.util.*;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.IDebugConstants;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.jdt.debug.core.IJavaDebugConstants;
import org.eclipse.jdt.internal.debug.core.*;


/**
 * The <code>PatternDebugTarget</code> extends the JDIDebugTarget
 * to allow for the setting of pattern breakpoints.
 */
public class PatternDebugTarget extends JDIDebugTarget {

	/**
	 * A mapping of source file names to ReferenceType objects.
	 * This mapping is used to set breakpoints in files that have
	 * already been loaded.  This is required becase JDI does not
	 * support searching for pre-loaded classes using a pattern
	 * like it does in the ClassPrepareRequest mechanism.
	 */
	protected Map fReferenceTypes;
	
	protected Map fInstalledPatternBreakpoints;

	public PatternDebugTarget(VirtualMachine jvm, String name, boolean supportTerminate, boolean supportDisconnect, IProcess process) {
		super(jvm, name, supportTerminate, supportDisconnect, process);
		fReferenceTypes= new HashMap(10);
		fInstalledPatternBreakpoints= new HashMap(10);
	}
	
	/**
	 * Attempts to install a deferred breakpoint
	 * into the newly loaded class.
	 */
	protected void installDeferredBreakpoints(ClassPrepareEvent event) {
		String sourceName= null;
		try {
			sourceName= event.referenceType().sourceName().trim();
		} catch (AbsentInformationException e) {
		}
		if (sourceName == null || sourceName.endsWith(".java")) {
			super.installDeferredBreakpoints(event);
			return;
		}
		
		// Only pattern breakpoints from here on.
		String typeName= event.referenceType().name();
		if (typeName == null)
			return;
		Iterator i= fDeferredBreakpointsByClass.keySet().iterator();
		while(i.hasNext()) {
			String pattern= (String)i.next();
			if (typeName.startsWith(pattern)) {
				ArrayList markers= (ArrayList) fDeferredBreakpointsByClass.get(pattern);
				if (markers != null) {
					//no longer need to listen for this class load
					//ClassPrepareRequest request= (ClassPrepareRequest) fClassPrepareRequestsByClass.remove(pattern);
					//getEventRequestManager().deleteEventRequest(request);
					Iterator itr= ((ArrayList) markers.clone()).iterator();
					while (itr.hasNext()) {
						IMarker marker= (IMarker) itr.next();
						patternBreakpointAdded(marker);
					}			
				}
				return;
			}
		}
	}
	
	public void breakpointAdded(IMarker breakpoint) {
		if (isPatternBreakpoint(breakpoint)) {
			patternBreakpointAdded(breakpoint);
		} else {
			super.breakpointAdded(breakpoint);
		}
	}
	
	public void breakpointRemoved(IMarker breakpoint, IMarkerDelta delta) {
		if (isPatternBreakpoint(breakpoint)) {
			patternBreakpointRemoved(breakpoint);
		} else {
			super.breakpointRemoved(breakpoint, delta);
		}
	}
	
	/**
	 * Installs or defers the given breakpoint
	 */
	protected void patternBreakpointAdded(IMarker breakpoint)  {
		List types= null;
		String pattern = getPattern(breakpoint);
		if (fReferenceTypes != null) {
			types = (List)fReferenceTypes.get(breakpoint.getResource().getName());
		}	
		if (types == null || types.isEmpty()) {
			defer(breakpoint, pattern);
		} else {
			// try to install
			Iterator i= types.iterator();
			while(i.hasNext()) {
				ReferenceType type= (ReferenceType) i.next();
				if (!installLineBreakpoint(breakpoint, type)) {
					// install did not succeed - could be an inner type not yet loaded
					defer(breakpoint, pattern);
				}
			}
		}
	}
	
	/**
	 * Attempts to create an instance of <code>java.lang.ThreadDeath</code> in the target VM.
	 * This instance will be used to terminate threads in the target VM.
	 * Note that if a thread death instance is not created threads will return <code>false</code>
	 * to <code>ITerminate#canTerminate()</code>.
	 */
	protected void createThreadDeathInstance(ThreadReference threadRef) {
		/** Pattern Support
		if (fThreadDeathAttempts == MAX_THREAD_DEATH_ATTEMPTS) {
			if (fUniversalClassPrepareReq != null) {
				try {
					getEventRequestManager().deleteEventRequest(fUniversalClassPrepareReq);
					fClassPrepareRequestsByClass.remove("*");
				} catch (RuntimeException e) {
					internalError(e);
				}
				fUniversalClassPrepareReq = null;
			}
			return;
		}
		*/
		fThreadDeathAttempts++;
		// Try to create an instance of java.lang.ThreadDeath
		// NB: This has to be done when the VM is interrupted by an event
		if (fThreadDeath == null) {
			JDIThread jt = findThread(threadRef);
			if (jt.canPerformEvaluation()) {
				// invalid state to perform an evaluation
				return;
			}
			//non NLS
			List classes= jdiClassesByName("java.lang.ThreadDeath");
			if (classes != null && classes.size() != 0) {
				ClassType threadDeathClass= (ClassType) classes.get(0);
				Method constructor= null;
				try {
					constructor= threadDeathClass.concreteMethodByName("<init>", "()V");
				} catch (RuntimeException e) {
					internalError(e);
					return;
				}
				try {
					fThreadDeath= threadDeathClass.newInstance(threadRef, constructor, new LinkedList(), ClassType.INVOKE_SINGLE_THREADED);
				} catch (ClassNotLoadedException e) {
					internalError(e);
				} catch (InvalidTypeException e) {
					internalError(e);
				} catch (InvocationException e) {
					internalError(e);
				} catch (IncompatibleThreadStateException e) {
					internalError(e);
				} catch (RuntimeException e) {
					internalError(e);
				}
				if (fThreadDeath != null) {
					try {
						fThreadDeath.disableCollection(); // This object is going to be used for the lifetime of the VM. 
						/** Pattern Support, continue to listen to all classloads
						if (fUniversalClassPrepareReq != null) {
							getEventRequestManager().deleteEventRequest(fUniversalClassPrepareReq);
							fClassPrepareRequestsByClass.remove("*");
						} */
					} catch (RuntimeException e) {
						fThreadDeath= null;
						internalError(e);
					}
				}
			}
		}
	}
	
	/**
	 * A class has been loaded.  
	 * Attempt to install any applicable deferred breakpoints.
	 * Attempt to create a ThreadDeath instance if required.
	 */
	protected void handleClassLoad(ClassPrepareEvent event) {
		registerClass(event);
		super.handleClassLoad(event);
	}
	
	/**
	 * Adds the source name and reference type to 
	 * the <code>fReferenceType</code> list.  Since
	 * multiple reference types can exist for one source file, 
	 * we must be careful to hold onto all of them.
	 */
	protected void registerClass(ClassPrepareEvent event) {
		ReferenceType type= event.referenceType();
		String sourceName= null;
		try {
			sourceName= type.sourceName().trim();
		} catch (AbsentInformationException e) {
			return;
		}
		if(!sourceName.endsWith(".java")) {
			List list= (List)fReferenceTypes.get(sourceName);
			if (list == null) {
				list= new ArrayList(4);
				fReferenceTypes.put(sourceName, list);
			}				
			list.add(type);	
		}
	}		
	
	protected String getPattern(IMarker breakpoint) {
		try {
			return (String)breakpoint.getAttribute(PatternDebugModel.PATTERN);
		} catch (CoreException e) {
		}
		return null;
	}
	
	protected void patternBreakpointRemoved(IMarker breakpoint) {
		// one-to-many relationship between breakpoints and requests.
		List requests= (List)fInstalledPatternBreakpoints.remove(breakpoint);
		if (requests == null) {
			//deferred breakpoint
			if (!breakpoint.exists()) {
				//resource no longer exists
				return;
			}
			String pattern= getPattern(breakpoint);
			if (pattern == null) {
				internalError(ERROR_BREAKPOINT_NO_TYPE);
				return;
			}
			List markers= (List) fDeferredBreakpointsByClass.get(pattern);
			if (markers == null) {
				return;
			}

			markers.remove(breakpoint);
			if (markers.isEmpty()) {
				fDeferredBreakpointsByClass.remove(pattern);
			}
		} else {
			//installed breakpoints
			Iterator i= requests.iterator(); 
			while(i.hasNext()) {
				BreakpointRequest request= (BreakpointRequest)i.next();
				try {
					// cannot delete an expired request
					if (!isExpired(request)) {
						getEventRequestManager().deleteEventRequest(request); // disable & remove
					}
				} catch (VMDisconnectedException e) {
					return;
				} catch (RuntimeException e) {
					internalError(e);
				}
			}
		}
	}
	
	/**
	 * Creates, installs, and returns a line breakpoint request at
	 * the given location for the given breakpoint.
	 * 
	 * Since the JSP page support allows many of the same class to
	 * be running, we must keep a one-to-many map of the breakpoint
	 * requests.
	 */
	protected BreakpointRequest createLineBreakpointRequest(Location location, IMarker breakpoint) {
		if (!isPatternBreakpoint(breakpoint)) {
			return super.createLineBreakpointRequest(location, breakpoint);
		}
		BreakpointRequest request = null;
		try {
			request= getEventRequestManager().createBreakpointRequest(location);
			request.putProperty(IDebugConstants.BREAKPOINT_MARKER, breakpoint);
			List requests= (List)fInstalledPatternBreakpoints.get(breakpoint);
			if (requests == null) {
				requests= new ArrayList(4);
				fInstalledPatternBreakpoints.put(breakpoint, requests);
			}
			requests.add(request);
			int hitCount= DebugJavaUtils.getHitCount(breakpoint);
			if (hitCount > 0) {
				request.addCountFilter(hitCount);
				request.putProperty(IJavaDebugConstants.HIT_COUNT, new Integer(hitCount));
				request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.FALSE);
			} 
			request.setEnabled(getBreakpointManager().isEnabled(breakpoint));
			request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
		} catch (VMDisconnectedException e) {
			List requests= (List)fInstalledPatternBreakpoints.get(breakpoint);
			requests.remove(request);
			return null;
		} catch (RuntimeException e) {
			List requests= (List)fInstalledPatternBreakpoints.get(breakpoint);
			requests.remove(request);
			internalError(e);
			return null;
		}
		return request;
	}
	
	protected boolean isPatternBreakpoint(IMarker marker) {
		try {
			return marker.getType().equals(PatternDebugModel.PATTERN_BREAKPOINT);
		} catch (CoreException e) {
			return false;
		}
	}			
}



\ No newline at end of file
diff --git a/org.eclipse.jdt.debug/plugin.xml b/org.eclipse.jdt.debug/plugin.xml
index 0944802..d592a26 100644
--- a/org.eclipse.jdt.debug/plugin.xml
+++ b/org.eclipse.jdt.debug/plugin.xml
@@ -93,4 +93,17 @@
          name="methodHandle">

    </attribute>

 </extension>

+<extension

+      id="patternBreakpoint"

+      point="org.eclipse.core.resources.markers">

+   <super

+         type="org.eclipse.debug.core.lineBreakpoint">

+   </super>

+   <persistent

+         value="true">

+   </persistent>

+   <attribute

+         name="pattern">

+   </attribute>

+</extension>

 </plugin>