*** empty log message ***
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.classpath b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.classpath
new file mode 100644
index 0000000..64c5e31
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.project b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.project
new file mode 100644
index 0000000..6a6f79d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.wst.xsl.jaxp.debug.ui</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+	</natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..d1c389a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Thu Jul 31 15:17:34 BST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..56a75ce
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: XSL JAXP Debug UI (Incubating)
+Bundle-SymbolicName: org.eclipse.wst.xsl.jaxp.debug.ui;singleton:=true
+Bundle-Version: 0.5.0.qualifier
+Bundle-Activator: org.eclipse.wst.xsl.jaxp.debug.ui.internal.JAXPDebugUIPlugin
+Bundle-Vendor: Eclipse.org
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.debug.ui;bundle-version="3.4.0",
+ org.eclipse.wst.xsl.debug.ui;bundle-version="0.5.0",
+ org.eclipse.core.variables;bundle-version="3.2.100",
+ org.eclipse.ui.ide;bundle-version="3.4.0",
+ org.eclipse.wst.xsl.launching,
+ org.eclipse.jdt.debug.ui;bundle-version="3.3.0",
+ org.eclipse.wst.xsl.jaxp.launching;bundle-version="0.5.0",
+ org.eclipse.wst.xsl.jaxp.debug;bundle-version="0.5.0",
+ org.eclipse.jface.text;bundle-version="3.4.0",
+ org.eclipse.wst.sse.ui;bundle-version="1.1.0",
+ org.eclipse.wst.xsl.ui;bundle-version="0.5.0",
+ org.eclipse.wst.sse.core;bundle-version="1.1.300",
+ org.eclipse.wst.xml.core;bundle-version="1.1.300",
+ org.eclipse.wst.xml.ui;bundle-version="1.0.400"
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/about.html b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/about.html
new file mode 100644
index 0000000..ed30003
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/about.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+
+<BODY lang="EN-US">
+
+<H3>About This Content</H3>
+
+<P>August, 2008</P>
+
+<H3>License</H3>
+
+<P>The Eclipse Foundation makes available all content in this plug-in 
+("Content"). Unless otherwise indicated below, the Content is provided to you 
+under the terms and conditions of the Eclipse Public License Version 1.0 
+("EPL"). A copy of the EPL is available at
+<A href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/org/documents/epl-v10.php</A>. 
+For purposes of the EPL, "Program" will mean the Content.</P>
+
+<P>If you did not receive this Content directly from the Eclipse Foundation, the 
+Content is being redistributed by another party ("Redistributor") and different 
+terms and conditions may apply to your use of any object code in the Content. 
+Check the Redistributor’s license that was provided with the Content. If no such 
+license exists, contact the Redistributor. Unless otherwise indicated below, the 
+terms and conditions of the EPL still apply to any source code in the Content 
+and such source code may be obtained at
+<A href="http://www.eclipse.org/">http://www.eclipse.org/</A>.</P>
+
+</BODY>
+</HTML>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/build.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/build.properties
new file mode 100644
index 0000000..44e050d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               about.html,\
+               icons/
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/icons/xslt_processor.gif b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/icons/xslt_processor.gif
new file mode 100644
index 0000000..5e71289
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/icons/xslt_processor.gif
Binary files differ
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/plugin.xml b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/plugin.xml
new file mode 100644
index 0000000..b716f1d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/plugin.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+	<extension point="org.eclipse.debug.ui.launchConfigurationTabs">
+		<tab
+			class="org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.XSLProcessorTab2"
+			group="org.eclipse.wst.xsl.internal.debug.ui.launchConfigurationTabGroup.xslt"
+			id="org.eclipse.wst.xsl.debug.ui.jaxp.tabs.processor" name="Processor">
+			<associatedDelegate
+				delegate="org.eclipse.wst.xsl.launching.internal.jaxp.JAXPLaunchConfigurationDelegate">
+			</associatedDelegate>
+			<placement after="org.eclipse.wst.xsl.internal.debug.ui.tabs.output">
+			</placement>
+		</tab>
+		<tab class="org.eclipse.jdt.debug.ui.launchConfigurations.JavaJRETab"
+			group="org.eclipse.wst.xsl.internal.debug.ui.launchConfigurationTabGroup.xslt"
+			id="org.eclipse.jdt.debug.ui.javaJRETab" name="JRE">
+			<associatedDelegate
+				delegate="org.eclipse.wst.xsl.launching.internal.jaxp.JAXPLaunchConfigurationDelegate">
+			</associatedDelegate>
+			<placement after="org.eclipse.wst.xsl.debug.ui.jaxp.tabs.processor">
+			</placement>
+		</tab>
+		<tab class="org.eclipse.jdt.debug.ui.launchConfigurations.JavaClasspathTab"
+			group="org.eclipse.wst.xsl.internal.debug.ui.launchConfigurationTabGroup.xslt"
+			id="org.eclipse.jdt.debug.ui.javaClasspathTab" name="Classpath">
+			<associatedDelegate
+				delegate="org.eclipse.wst.xsl.launching.internal.jaxp.JAXPLaunchConfigurationDelegate">
+			</associatedDelegate>
+			<placement after="org.eclipse.jdt.debug.ui.javaJRETab">
+			</placement>
+		</tab>
+	</extension>
+	<extension point="org.eclipse.ui.preferencePages">
+		<page category="org.eclipse.wst.xsl.ui.preferences.BasePreferencePage"
+			class="org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences.ProcessorsPreferencePage"
+			id="org.eclipse.wst.xsl.ui.preferences.java" name="JAXP Processors">
+		</page>
+	</extension>
+ <extension
+       point="org.eclipse.ui.views">
+    <view
+          class="org.eclipse.wst.xsl.jaxp.debug.ui.internal.views.ResultView"
+          id="org.eclipse.wst.xsl.jaxp.debug.ui.resultview"
+          name="Result"
+          category="org.eclipse.wst.xml">
+    </view>
+ </extension>
+  <extension
+        point="org.eclipse.ui.perspectiveExtensions">
+     <perspectiveExtension
+           targetID="org.eclipse.debug.ui.DebugPerspective">
+        <view
+              id="org.eclipse.wst.xsl.jaxp.debug.ui.view1"
+              minimized="false"
+              relationship="stack"
+              relative="org.eclipse.ui.console.ConsoleView"
+              visible="false">
+        </view>
+     </perspectiveExtension>
+  </extension>
+ 
+ 	<extension point="org.eclipse.debug.ui.contextViewBindings">
+		<contextViewBinding
+			contextId="org.eclipse.wst.xsl.debug.ui.context"
+			viewId="org.eclipse.wst.xsl.jaxp.debug.ui.resultview">
+		</contextViewBinding>
+	</extension>
+ 
+</plugin>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/JAXPDebugUIPlugin.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/JAXPDebugUIPlugin.java
new file mode 100644
index 0000000..d79b21d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/JAXPDebugUIPlugin.java
@@ -0,0 +1,61 @@
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchListener;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.wst.xsl.launching.config.BaseLaunchHelper;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class JAXPDebugUIPlugin extends AbstractUIPlugin {
+
+	// The plug-in ID
+	public static final String PLUGIN_ID = "org.eclipse.wst.xsl.jaxp.debug.ui";
+
+	// The shared instance
+	private static JAXPDebugUIPlugin plugin;
+	
+	/**
+	 * The constructor
+	 */
+	public JAXPDebugUIPlugin() {
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		plugin = this;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		plugin = null;
+		super.stop(context);
+	}
+
+	/**
+	 * Returns the shared instance
+	 *
+	 * @return the shared instance
+	 */
+	public static JAXPDebugUIPlugin getDefault() {
+		return plugin;
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/AddProcessorDialog.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/AddProcessorDialog.java
new file mode 100644
index 0000000..8f0125e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/AddProcessorDialog.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.InstallStandin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.ProcessorMessages;
+import org.eclipse.wst.xsl.jaxp.launching.IDebugger;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class AddProcessorDialog extends StatusDialog
+{
+	private final InstallStandin standinProcessor;
+	private final IProcessorType[] processorTypes;
+	private IProcessorType selectedProcessorType;
+	private ComboViewer processorTypeField;
+	private ProcessorLibraryBlock fLibraryBlock;
+	private Text processorNameField;
+	private final IStatus[] fStati;
+	private int fPrevIndex = -1;
+	private final InstalledProcessorsBlock block;
+	private boolean adding;
+
+	public AddProcessorDialog(InstalledProcessorsBlock block, Shell parent, IProcessorType[] types, IProcessorInstall install)
+	{
+		super(parent);
+		setShellStyle(getShellStyle() | SWT.RESIZE);
+		this.block = block;
+		fStati = new IStatus[5];
+		for (int i = 0; i < fStati.length; i++)
+		{
+			fStati[i] = Status.OK_STATUS;
+		}
+		processorTypes = types;
+		selectedProcessorType = install != null ? install.getProcessorType() : types[0];
+		InstallStandin standin = null;
+		if (install == null)
+		{
+			adding = true;
+			standin = new InstallStandin(JAXPRuntime.createUniqueProcessorId(selectedProcessorType), "", selectedProcessorType.getId(), null, new IProcessorJar[0]); //$NON-NLS-1$
+		}
+		else
+		{
+			standin = new InstallStandin(install);
+		}
+		standinProcessor = standin;
+	}
+
+	@Override
+	protected void configureShell(Shell newShell)
+	{
+		super.configureShell(newShell);
+		// TODO PlatformUI.getWorkbench().getHelpSystem().setHelp...
+	}
+
+	protected void createDialogFields(Composite parent)
+	{
+		GridData gd;
+		Label label;
+
+		label = new Label(parent, SWT.NONE);
+		label.setText(ProcessorMessages.AddProcessorDialog_processorName);
+		processorNameField = new Text(parent, SWT.BORDER);
+		gd = new GridData(SWT.NONE, SWT.NONE, false, false);
+		gd.widthHint = convertWidthInCharsToPixels(50);
+		gd.horizontalSpan = 2;
+		processorNameField.setLayoutData(gd);
+
+		label = new Label(parent, SWT.NONE);
+		label.setText(ProcessorMessages.AddProcessorDialog_processorType);
+		processorTypeField = new ComboViewer(parent, SWT.READ_ONLY);
+		gd = new GridData();
+		gd.horizontalSpan = 2;
+		processorTypeField.getCombo().setLayoutData(gd);
+		processorTypeField.setContentProvider(new IStructuredContentProvider()
+		{
+
+			private Object input;
+
+			public Object[] getElements(Object inputElement)
+			{
+				return (IProcessorType[]) input;
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+				input = newInput;
+			}
+		});
+		processorTypeField.setLabelProvider(new LabelProvider()
+		{
+			@Override
+			public String getText(Object element)
+			{
+				return ((IProcessorType) element).getLabel();
+			}
+		});
+
+	}
+
+	protected void createFieldListeners()
+	{
+		processorTypeField.addSelectionChangedListener(new ISelectionChangedListener()
+		{
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				updateProcessorType();
+			}
+		});
+
+		processorNameField.addModifyListener(new ModifyListener()
+		{
+			public void modifyText(ModifyEvent e)
+			{
+				setProcessorNameStatus(validateProcessorName());
+				updateStatusLine();
+			}
+		});
+	}
+
+	protected String getProcessorName()
+	{
+		return processorNameField.getText();
+	}
+
+	@Override
+	protected Control createDialogArea(Composite ancestor)
+	{
+		Composite parent = (Composite) super.createDialogArea(ancestor);
+		((GridLayout) parent.getLayout()).numColumns = 3;
+//		((GridData) parent.getLayoutData()).heightHint = 400;
+//		((GridData) parent.getLayoutData()).widthHint = 400;
+
+		createDialogFields(parent);
+
+		Label l = new Label(parent, SWT.NONE);
+		l.setText(ProcessorMessages.AddProcessorDialog_jars);
+		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		gd.horizontalSpan = 3;
+		l.setLayoutData(gd);
+
+		fLibraryBlock = new ProcessorLibraryBlock(this);
+		Control block = fLibraryBlock.createControl(parent);
+		gd = new GridData(GridData.FILL_BOTH);
+		gd.horizontalSpan = 3;
+		block.setLayoutData(gd);
+
+		initializeFields();
+		createFieldListeners();
+		applyDialogFont(parent);
+		
+		return parent;
+	}
+
+	private void updateProcessorType()
+	{
+		int selIndex = processorTypeField.getCombo().getSelectionIndex();
+		if (selIndex == fPrevIndex)
+		{
+			return;
+		}
+		fPrevIndex = selIndex;
+		if (selIndex >= 0 && selIndex < processorTypes.length)
+		{
+			selectedProcessorType = processorTypes[selIndex];
+		}
+		fLibraryBlock.initializeFrom(standinProcessor, selectedProcessorType);
+		updateStatusLine();
+	}
+
+	@Override
+	public void create()
+	{
+		super.create();
+		processorNameField.setFocus();
+	}
+
+	private void initializeFields()
+	{
+		processorTypeField.setInput(processorTypes);
+		if (adding)
+		{
+			processorNameField.setText(""); //$NON-NLS-1$
+			processorTypeField.setSelection(new StructuredSelection(processorTypes[0]));
+			fLibraryBlock.initializeFrom(standinProcessor, selectedProcessorType);
+		}
+		else
+		{
+			processorTypeField.getCombo().setEnabled(false);
+			processorTypeField.setSelection(new StructuredSelection(standinProcessor.getProcessorType()));
+			processorNameField.setText(standinProcessor.getName());
+
+			fLibraryBlock.initializeFrom(standinProcessor, selectedProcessorType);
+		}
+		setProcessorNameStatus(validateProcessorName());
+		updateStatusLine();
+	}
+
+	private IStatus validateProcessorName()
+	{
+		IStatus status = Status.OK_STATUS;
+		String name = processorNameField.getText();
+		if (name == null || name.trim().length() == 0)
+		{
+			status = new Status(IStatus.INFO, XSLDebugUIPlugin.PLUGIN_ID, IStatus.OK, ProcessorMessages.AddProcessorDialog_enterName, null);
+		}
+		else
+		{
+			if (block.isDuplicateName(name) && (standinProcessor == null || !name.equals(standinProcessor.getName())))
+			{
+				status = new Status(IStatus.ERROR, XSLDebugUIPlugin.PLUGIN_ID, IStatus.OK, ProcessorMessages.AddProcessorDialog_duplicateName, null);
+			}
+			else
+			{
+				// IStatus s = ResourcesPlugin.getWorkspace().validateName(name,
+				// IResource.FILE);
+				// if (!s.isOK())
+				// {
+				// status.setError(MessageFormat.format(ProcessorMessages.AddProcessorDialog_Processor_name_must_be_a_valid_file_name,
+				// new String[]
+				// { s.getMessage() }));
+				// }
+			}
+		}
+		return status;
+	}
+
+	protected IStatus validateVersionStatus()
+	{
+		IStatus status = Status.OK_STATUS;
+		return status;
+	}
+
+	protected void updateStatusLine()
+	{
+		IStatus max = null;
+		for (IStatus curr : fStati)
+		{
+			if (curr.matches(IStatus.ERROR))
+			{
+				updateStatus(curr);
+				return;
+			}
+			if (max == null || curr.getSeverity() > max.getSeverity())
+			{
+				max = curr;
+			}
+		}
+		updateStatus(max);
+	}
+
+	@Override
+	protected void okPressed()
+	{
+		doOkPressed();
+		super.okPressed();
+	}
+
+	private void doOkPressed()
+	{
+		if (adding)
+		{
+			setFieldValuesToProcessor(standinProcessor);
+			block.processorAdded(standinProcessor);
+		}
+//		else
+//			setFieldValuesToProcessor((ProcessorInstall)editedProcessor);
+	}
+
+	protected void setFieldValuesToProcessor(InstallStandin processor)
+	{
+		processor.setName(processorNameField.getText());
+		processor.setProcessorTypeId(selectedProcessorType.getId());
+
+		IDebugger[] debuggers = JAXPRuntime.getDebuggers();
+		for (IDebugger element : debuggers)
+		{
+			if (element.getProcessorType().equals(selectedProcessorType))
+				processor.setDebuggerId(element.getId());
+		}
+
+		fLibraryBlock.performApply(processor);
+	}
+
+	protected File getAbsoluteFileOrEmpty(String path)
+	{
+		if (path == null || path.length() == 0)
+		{
+			return new File(""); //$NON-NLS-1$
+		}
+		return new File(path).getAbsoluteFile();
+	}
+
+	private void setProcessorNameStatus(IStatus status)
+	{
+		fStati[0] = status;
+	}
+
+	protected IStatus getSystemLibraryStatus()
+	{
+		return fStati[3];
+	}
+
+	protected void setSystemLibraryStatus(IStatus status)
+	{
+		fStati[3] = status;
+	}
+
+	protected void setVersionStatus(IStatus status)
+	{
+		fStati[2] = status;
+	}
+
+	@Override
+	protected void updateButtonsEnableState(IStatus status)
+	{
+		Button ok = getButton(IDialogConstants.OK_ID);
+		if (ok != null && !ok.isDisposed())
+			ok.setEnabled(status.getSeverity() == IStatus.OK);
+	}
+
+	@Override
+	protected void setButtonLayoutData(Button button)
+	{
+		super.setButtonLayoutData(button);
+	}
+
+	protected String getDialogSettingsSectionName()
+	{
+		return "ADD_PROCESSOR_DIALOG_SECTION"; //$NON-NLS-1$
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings()
+	{
+//		IDialogSettings settings = XSLDebugUIPlugin.getDefault().getDialogSettings();
+//		IDialogSettings section = settings.getSection(getDialogSettingsSectionName());
+//		if (section == null)
+//		{
+//			section = settings.addNewSection(getDialogSettingsSectionName());
+//		}
+//		return section;
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/BasePreferencePage.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/BasePreferencePage.java
new file mode 100644
index 0000000..73db6bf
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/BasePreferencePage.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class BasePreferencePage extends PreferencePage implements IWorkbenchPreferencePage
+{
+	@Override
+	protected Control createContents(Composite parent)
+	{
+		return null;
+	}
+
+	public void init(IWorkbench workbench)
+	{
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/InstalledProcessorsBlock.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/InstalledProcessorsBlock.java
new file mode 100644
index 0000000..833df3a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/InstalledProcessorsBlock.java
@@ -0,0 +1,647 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.wst.xsl.internal.debug.ui.AbstractTableBlock;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIConstants;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.InstallStandin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.ProcessorMessages;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class InstalledProcessorsBlock extends AbstractTableBlock implements ISelectionProvider
+{
+	private Composite fControl;
+	private final List<IProcessorInstall> processors = new ArrayList<IProcessorInstall>();
+	private CheckboxTableViewer tableViewer;
+	private Button fAddButton;
+	private Button fRemoveButton;
+	private Button fEditButton;
+	private final ListenerList fSelectionListeners = new ListenerList();
+	private ISelection fPrevSelection = new StructuredSelection();
+
+	public void addSelectionChangedListener(ISelectionChangedListener listener)
+	{
+		fSelectionListeners.add(listener);
+	}
+
+	public void removeSelectionChangedListener(ISelectionChangedListener listener)
+	{
+		fSelectionListeners.remove(listener);
+	}
+
+	public ISelection getSelection()
+	{
+		return new StructuredSelection(tableViewer.getCheckedElements());
+	}
+
+	public void setSelection(ISelection selection)
+	{
+		if (selection instanceof IStructuredSelection)
+		{
+			if (!selection.equals(fPrevSelection))
+			{
+				fPrevSelection = selection;
+				Object jre = ((IStructuredSelection) selection).getFirstElement();
+				if (jre == null)
+				{
+					tableViewer.setCheckedElements(new Object[0]);
+				}
+				else
+				{
+					tableViewer.setCheckedElements(new Object[]
+					{ jre });
+					tableViewer.reveal(jre);
+				}
+				fireSelectionChanged();
+			}
+		}
+	}
+
+	public void createControl(Composite ancestor)
+	{
+
+		Composite parent = new Composite(ancestor, SWT.NULL);
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		parent.setLayout(layout);
+		Font font = ancestor.getFont();
+		parent.setFont(font);
+		fControl = parent;
+
+		GridData data;
+
+		Label tableLabel = new Label(parent, SWT.NONE);
+		tableLabel.setText(ProcessorMessages.InstalledProcessorsBlock_0);
+		data = new GridData();
+		data.horizontalSpan = 2;
+		tableLabel.setLayoutData(data);
+		tableLabel.setFont(font);
+
+		Table fTable = new Table(parent, SWT.CHECK | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
+
+		data = new GridData(GridData.FILL_BOTH);
+		data.widthHint = 450;
+		fTable.setLayoutData(data);
+		fTable.setFont(font);
+
+		fTable.setHeaderVisible(true);
+		fTable.setLinesVisible(true);
+
+		TableColumn column1 = new TableColumn(fTable, SWT.NONE);
+		column1.setWidth(180);
+		column1.setResizable(true);
+		column1.setText(ProcessorMessages.InstalledProcessorsBlock_1);
+		column1.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				sortByName();
+			}
+		});
+
+		TableColumn column2 = new TableColumn(fTable, SWT.NONE);
+		column2.setWidth(90);
+		column2.setResizable(true);
+		column2.setText(ProcessorMessages.InstalledProcessorsBlock_2);
+		column2.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				sortByType();
+			}
+		});
+
+		TableColumn column4 = new TableColumn(fTable, SWT.NONE);
+		column4.setWidth(180);
+		column4.setResizable(true);
+		column4.setText(ProcessorMessages.InstalledProcessorsBlock_4);
+		column4.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				sortByVersion();
+			}
+		});
+
+		tableViewer = new CheckboxTableViewer(fTable);
+		tableViewer.setLabelProvider(new VMLabelProvider());
+		tableViewer.setContentProvider(new ProcessorsContentProvider());
+
+		tableViewer.addSelectionChangedListener(new ISelectionChangedListener()
+		{
+			public void selectionChanged(SelectionChangedEvent evt)
+			{
+				enableButtons();
+			}
+		});
+
+		tableViewer.addCheckStateListener(new ICheckStateListener()
+		{
+			public void checkStateChanged(CheckStateChangedEvent event)
+			{
+				if (event.getChecked())
+				{
+					setCheckedInstall((IProcessorInstall) event.getElement());
+				}
+				else
+				{
+					setCheckedInstall(null);
+				}
+			}
+		});
+
+		tableViewer.addDoubleClickListener(new IDoubleClickListener()
+		{
+			public void doubleClick(DoubleClickEvent e)
+			{
+				if (!tableViewer.getSelection().isEmpty())
+				{
+					editProcessor();
+				}
+			}
+		});
+		fTable.addKeyListener(new KeyAdapter()
+		{
+			@Override
+			public void keyPressed(KeyEvent event)
+			{
+				if (event.character == SWT.DEL && event.stateMask == 0)
+				{
+					removeProcessors();
+				}
+			}
+		});
+
+		Composite buttons = new Composite(parent, SWT.NULL);
+		buttons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		buttons.setLayout(layout);
+		buttons.setFont(font);
+
+		fAddButton = createPushButton(buttons, ProcessorMessages.InstalledProcessorsBlock_5);
+		fAddButton.addListener(SWT.Selection, new Listener()
+		{
+			public void handleEvent(Event evt)
+			{
+				addProcessor();
+			}
+		});
+
+		fEditButton = createPushButton(buttons, ProcessorMessages.InstalledProcessorsBlock_6);
+		fEditButton.addListener(SWT.Selection, new Listener()
+		{
+			public void handleEvent(Event evt)
+			{
+				editProcessor();
+			}
+		});
+
+		fRemoveButton = createPushButton(buttons, ProcessorMessages.InstalledProcessorsBlock_7);
+		fRemoveButton.addListener(SWT.Selection, new Listener()
+		{
+			public void handleEvent(Event evt)
+			{
+				removeProcessors();
+			}
+		});
+
+		// copied from ListDialogField.CreateSeparator()
+		Label separator = new Label(buttons, SWT.NONE);
+		separator.setVisible(false);
+		GridData gd = new GridData();
+		gd.horizontalAlignment = GridData.FILL;
+		gd.verticalAlignment = GridData.BEGINNING;
+		gd.heightHint = 4;
+		separator.setLayoutData(gd);
+
+		fillWithWorkspaceProcessors();
+		enableButtons();
+
+		restoreColumnSettings();
+	}
+
+	protected void fillWithWorkspaceProcessors()
+	{
+		List<InstallStandin> standins = new ArrayList<InstallStandin>();
+		IProcessorType[] types = JAXPRuntime.getProcessorTypes();
+		for (IProcessorType type : types)
+		{
+			IProcessorInstall[] installs = JAXPRuntime.getProcessors(type.getId());
+			for (IProcessorInstall install : installs)
+			{
+				standins.add(new InstallStandin(install));
+			}
+		}
+		setProcessors((IProcessorInstall[]) standins.toArray(new IProcessorInstall[standins.size()]));
+	}
+
+	private void fireSelectionChanged()
+	{
+		SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
+		Object[] listeners = fSelectionListeners.getListeners();
+		for (Object element : listeners)
+		{
+			ISelectionChangedListener listener = (ISelectionChangedListener) element;
+			listener.selectionChanged(event);
+		}
+	}
+
+	/**
+	 * Sorts by type, and name within type.
+	 */
+	private void sortByType()
+	{
+		tableViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				IProcessorInstall left = (IProcessorInstall) e1;
+				IProcessorInstall right = (IProcessorInstall) e2;
+				return left.getProcessorType().getLabel().compareToIgnoreCase(right.getProcessorType().getLabel());
+			}
+
+			@Override
+			public boolean isSorterProperty(Object element, String property)
+			{
+				return true;
+			}
+		});
+	}
+
+	private void sortByVersion()
+	{
+		tableViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				IProcessorInstall left = (IProcessorInstall) e1;
+				IProcessorInstall right = (IProcessorInstall) e2;
+				return left.getSupports().compareToIgnoreCase(right.getSupports());
+			}
+
+			@Override
+			public boolean isSorterProperty(Object element, String property)
+			{
+				return true;
+			}
+		});
+	}
+
+	/**
+	 * Sorts by name.
+	 */
+	private void sortByName()
+	{
+		tableViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				if ((e1 instanceof IProcessorInstall) && (e2 instanceof IProcessorInstall))
+				{
+					IProcessorInstall left = (IProcessorInstall) e1;
+					IProcessorInstall right = (IProcessorInstall) e2;
+					return left.getName().compareToIgnoreCase(right.getName());
+				}
+				return super.compare(viewer, e1, e2);
+			}
+
+			@Override
+			public boolean isSorterProperty(Object element, String property)
+			{
+				return true;
+			}
+		});
+	}
+
+	private void enableButtons()
+	{
+		IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
+		int selectionCount = selection.size();
+		fEditButton.setEnabled(selectionCount == 1 && !((IProcessorInstall)selection.getFirstElement()).isContributed());
+		if (selectionCount > 0 && selectionCount < tableViewer.getTable().getItemCount())
+		{
+			Iterator<?> iterator = selection.iterator();
+			while (iterator.hasNext())
+			{
+				IProcessorInstall install = (IProcessorInstall) iterator.next();
+				if (install.isContributed())
+				{
+					fRemoveButton.setEnabled(false);
+					return;
+				}
+			}
+			fRemoveButton.setEnabled(true);
+		}
+		else
+		{
+			fRemoveButton.setEnabled(false);
+		}
+	}
+
+	protected Button createPushButton(Composite parent, String label)
+	{
+		Button button = new Button(parent, SWT.PUSH);
+		button.setText(label);
+		button.setLayoutData(GridDataFactory.fillDefaults().create());
+		return button;
+	}
+
+	@Override
+	public Control getControl()
+	{
+		return fControl;
+	}
+
+	protected void setProcessors(IProcessorInstall[] vms)
+	{
+		processors.clear();
+		for (IProcessorInstall element : vms)
+		{
+			processors.add(element);
+		}
+		tableViewer.setInput(processors);
+		// tableViewer.refresh();
+	}
+
+	public IProcessorInstall[] getProcessors()
+	{
+		return (IProcessorInstall[]) processors.toArray(new IProcessorInstall[processors.size()]);
+	}
+
+	private void addProcessor()
+	{
+		AddProcessorDialog dialog = new AddProcessorDialog(this, getShell(), JAXPRuntime.getProcessorTypesExclJREDefault(), null);
+		dialog.setTitle(ProcessorMessages.AddProcessorDialog_Add_Title);
+		if (dialog.open() != Window.OK)
+		{
+			return;
+		}
+	}
+
+	public void processorAdded(IProcessorInstall install)
+	{
+		processors.add(install);
+		tableViewer.add(install);
+		tableViewer.setSelection(new StructuredSelection(install), true);
+	}
+
+	public boolean isDuplicateName(String name)
+	{
+		for (int i = 0; i < processors.size(); i++)
+		{
+			IProcessorInstall install = (IProcessorInstall) processors.get(i);
+			if (install.getName().equals(name))
+			{
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private void editProcessor()
+	{
+		IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
+		IProcessorInstall install = (IProcessorInstall) selection.getFirstElement();
+		if (install == null)
+		{
+			return;
+		}
+		if (!install.isContributed())
+		{
+//			ProcessorDetailsDialog dialog = new ProcessorDetailsDialog(getShell(), install);
+//			dialog.open();
+//		}
+//		else
+//		{
+			AddProcessorDialog dialog = new AddProcessorDialog(this, getShell(), JAXPRuntime.getProcessorTypesExclJREDefault(), install);
+			dialog.setTitle(ProcessorMessages.AddProcessorDialog_Edit_Title);
+			if (dialog.open() != Window.OK)
+			{
+				return;
+			}
+			// fillWithWorkspaceProcessors();
+			tableViewer.refresh();
+		}
+	}
+
+	private void removeProcessors()
+	{
+		IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
+		IProcessorInstall[] vms = new IProcessorInstall[selection.size()];
+		Iterator<?> iter = selection.iterator();
+		int i = 0;
+		while (iter.hasNext())
+		{
+			vms[i] = (IProcessorInstall) iter.next();
+			i++;
+		}
+		removeProcessors(vms);
+	}
+
+	public void removeProcessors(IProcessorInstall[] theInstalls)
+	{
+		IStructuredSelection prev = (IStructuredSelection) getSelection();
+		for (IProcessorInstall element : theInstalls)
+		{
+			processors.remove(element);
+		}
+		tableViewer.refresh();
+		IStructuredSelection curr = (IStructuredSelection) getSelection();
+		if (!curr.equals(prev))
+		{
+			IProcessorInstall[] installs = getProcessors();
+			if (curr.size() == 0 && installs.length == 1)
+			{
+				// pick a default install automatically
+				setSelection(new StructuredSelection(installs[0]));
+			}
+			else
+			{
+				fireSelectionChanged();
+			}
+		}
+	}
+
+	public void setCheckedInstall(IProcessorInstall install)
+	{
+		if (install == null)
+		{
+			setSelection(new StructuredSelection());
+		}
+		else
+		{
+			setSelection(new StructuredSelection(install));
+		}
+	}
+
+	public IProcessorInstall getCheckedInstall()
+	{
+		Object[] objects = tableViewer.getCheckedElements();
+		if (objects.length == 0)
+		{
+			return null;
+		}
+		return (IProcessorInstall) objects[0];
+	}
+
+	@Override
+	protected void setSortColumn(int column)
+	{
+		switch (column)
+		{
+			case 1:
+				sortByName();
+				break;
+			case 2:
+				sortByType();
+				break;
+		}
+		super.setSortColumn(column);
+	}
+
+	@Override
+	protected Table getTable()
+	{
+		return tableViewer.getTable();
+	}
+
+	@Override
+	protected IDialogSettings getDialogSettings()
+	{
+		return XSLDebugUIPlugin.getDefault().getDialogSettings();
+	}
+
+	@Override
+	protected String getQualifier()
+	{
+		return XSLDebugUIConstants.PROCESSOR_DETAILS_DIALOG;
+	}
+
+	public String getName()
+	{
+		return null;
+	}
+
+	public void initializeFrom(ILaunchConfiguration configuration)
+	{
+	}
+
+	public void performApply(ILaunchConfigurationWorkingCopy configuration)
+	{
+	}
+
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
+	{
+	}
+
+	private class ProcessorsContentProvider implements IStructuredContentProvider
+	{
+		public Object[] getElements(Object input)
+		{
+			return processors.toArray();
+		}
+
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+		{
+		}
+
+		public void dispose()
+		{
+		}
+	}
+
+	private class VMLabelProvider extends LabelProvider implements ITableLabelProvider
+	{
+		public String getColumnText(Object element, int columnIndex)
+		{
+			if (element instanceof IProcessorInstall)
+			{
+				IProcessorInstall install = (IProcessorInstall) element;
+				switch (columnIndex)
+				{
+					case 0:
+						return install.getName();
+					case 1:
+						return install.getProcessorType().getLabel();
+					case 2:
+						if (install.getDebugger() != null)
+						{
+							return install.getDebugger().getName();
+						}
+						return ProcessorMessages.InstalledProcessorsBlock_8;
+				}
+			}
+			return element.toString();
+		}
+
+		public Image getColumnImage(Object element, int columnIndex)
+		{
+			return null;
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/Messages.java
new file mode 100644
index 0000000..e0e0c15
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/Messages.java
@@ -0,0 +1,22 @@
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private Messages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorLibraryBlock.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorLibraryBlock.java
new file mode 100644
index 0000000..2233a3d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorLibraryBlock.java
@@ -0,0 +1,345 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceComparator;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.InstallStandin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.JarContentProvider;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.JarLabelProvider;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.ProcessorMessages;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class ProcessorLibraryBlock implements SelectionListener, ISelectionChangedListener
+{
+	protected static final String LAST_PATH_SETTING = "LAST_PATH_SETTING"; //$NON-NLS-1$
+	protected static final String LAST_WORKSPACE_PATH_SETTING = "LAST_WORKSPACE_PATH_SETTING"; //$NON-NLS-1$
+	protected static final String DIALOG_SETTINGS_PREFIX = "ProcessorLibraryBlock"; //$NON-NLS-1$
+	protected InstallStandin install;
+	protected IProcessorType installType;
+	protected AddProcessorDialog addDialog = null;
+	protected TableViewer tableViewer;
+	private Button removeButton;
+	private Button addButton;
+	private Button addWorkspaceButton;
+
+	private final ISelectionStatusValidator validator = new ISelectionStatusValidator()
+	{
+		public IStatus validate(Object[] selection)
+		{
+			if (selection.length == 0)
+			{
+				return new Status(IStatus.ERROR, XSLDebugUIPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
+			}
+			for (Object element : selection)
+			{
+				if (element instanceof IFolder)
+					return new Status(IStatus.ERROR, XSLDebugUIPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
+				else if (element instanceof IFile)
+				{
+					// IFile file = (IFile) selection[i];
+					// TODO check that the file is not already on the classpath
+				}
+			}
+			return new Status(IStatus.OK, XSLDebugUIPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
+		}
+	};
+
+	public ProcessorLibraryBlock(AddProcessorDialog dialog)
+	{
+		addDialog = dialog;
+	}
+
+	public Control createControl(Composite parent)
+	{
+		Font font = parent.getFont();
+
+		Composite comp = new Composite(parent, SWT.NONE);
+		GridLayout topLayout = new GridLayout();
+		topLayout.numColumns = 2;
+		topLayout.marginHeight = 0;
+		topLayout.marginWidth = 0;
+		comp.setLayout(topLayout);
+		GridData gd = new GridData(GridData.FILL_BOTH);
+		comp.setLayoutData(gd);
+
+		tableViewer = new TableViewer(comp);
+		gd = new GridData(GridData.FILL_BOTH);
+		gd.heightHint = 6;
+		tableViewer.getControl().setLayoutData(gd);
+		JarContentProvider fLibraryContentProvider = new JarContentProvider();
+		tableViewer.setContentProvider(fLibraryContentProvider);
+		tableViewer.setLabelProvider(new JarLabelProvider());
+		tableViewer.addSelectionChangedListener(this);
+
+		Composite pathButtonComp = new Composite(comp, SWT.NONE);
+		GridLayout pathButtonLayout = new GridLayout();
+		pathButtonLayout.marginHeight = 0;
+		pathButtonLayout.marginWidth = 0;
+		pathButtonComp.setLayout(pathButtonLayout);
+		gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL);
+		pathButtonComp.setLayoutData(gd);
+		pathButtonComp.setFont(font);
+
+		addWorkspaceButton = createPushButton(pathButtonComp, ProcessorMessages.ProcessorLibraryBlock_AddWorkspaceButton);
+		addWorkspaceButton.addSelectionListener(this);
+
+		addButton = createPushButton(pathButtonComp, ProcessorMessages.ProcessorLibraryBlock_AddButton);
+		addButton.addSelectionListener(this);
+
+		removeButton = createPushButton(pathButtonComp, ProcessorMessages.ProcessorLibraryBlock_RemoveButton);
+		removeButton.addSelectionListener(this);
+
+		return comp;
+	}
+
+	protected Button createPushButton(Composite parent, String label)
+	{
+		Button button = new Button(parent, SWT.PUSH);
+		button.setFont(parent.getFont());
+		button.setText(label);
+		addDialog.setButtonLayoutData(button);
+		return button;
+	}
+
+	protected void createVerticalSpacer(Composite comp, int colSpan)
+	{
+		Label label = new Label(comp, SWT.NONE);
+		GridData gd = new GridData();
+		gd.horizontalSpan = colSpan;
+		label.setLayoutData(gd);
+	}
+
+	public void initializeFrom(InstallStandin standin, IProcessorType type)
+	{
+		install = standin;
+		installType = type;
+		if (install != null)
+			tableViewer.setInput(install);
+		update();
+	}
+
+	/**
+	 * Updates buttons and status based on current libraries
+	 */
+	public void update()
+	{
+		updateButtons();
+		IStatus status = Status.OK_STATUS;
+		if (install != null && install.getProcessorJars().length == 0)
+		{
+			status = new Status(IStatus.INFO, XSLDebugUIPlugin.PLUGIN_ID, 0, ProcessorMessages.ProcessorLibraryBlock_6, null);
+		}
+		addDialog.setSystemLibraryStatus(status);
+		addDialog.updateStatusLine();
+	}
+
+	public void performApply(InstallStandin standin)
+	{
+		standin.setProcessorJars(install.getProcessorJars());
+	}
+
+	protected IProcessorInstall getVMInstall()
+	{
+		return install;
+	}
+
+	protected IProcessorType getVMInstallType()
+	{
+		return installType;
+	}
+
+	public void widgetSelected(SelectionEvent e)
+	{
+		Object source = e.getSource();
+		if (source == removeButton)
+		{
+			remove((IStructuredSelection) tableViewer.getSelection());
+		}
+		else if (source == addButton)
+		{
+			addExternal((IStructuredSelection) tableViewer.getSelection());
+		}
+		else if (source == addWorkspaceButton)
+		{
+			addWorkspace((IStructuredSelection) tableViewer.getSelection());
+		}
+		update();
+	}
+
+	public void widgetDefaultSelected(SelectionEvent e)
+	{
+	}
+
+	private void addExternal(IStructuredSelection selection)
+	{
+		IDialogSettings dialogSettings = XSLDebugUIPlugin.getDefault().getDialogSettings();
+		String lastUsedPath = dialogSettings.get(LAST_PATH_SETTING);
+		if (lastUsedPath == null)
+		{
+			lastUsedPath = ""; //$NON-NLS-1$
+		}
+		FileDialog dialog = new FileDialog(tableViewer.getControl().getShell(), SWT.MULTI);
+		dialog.setText(ProcessorMessages.ProcessorLibraryBlock_FileDialog_Title);
+		dialog.setFilterExtensions(new String[]
+		{ "*.jar;*.zip" }); //$NON-NLS-1$
+		dialog.setFilterPath(lastUsedPath);
+		String res = dialog.open();
+		if (res == null)
+		{
+			return;
+		}
+		String[] fileNames = dialog.getFileNames();
+		int nChosen = fileNames.length;
+
+		IPath filterPath = new Path(dialog.getFilterPath());
+		IProcessorJar[] libs = new IProcessorJar[nChosen];
+		for (int i = 0; i < nChosen; i++)
+		{
+			libs[i] = JAXPRuntime.createProcessorJar(filterPath.append(fileNames[i]).makeAbsolute());
+		}
+		dialogSettings.put(LAST_PATH_SETTING, filterPath.toOSString());
+
+		IProcessorJar[] currentJars = install.getProcessorJars();
+		IProcessorJar[] newJars = new IProcessorJar[currentJars.length + libs.length];
+		System.arraycopy(currentJars, 0, newJars, 0, currentJars.length);
+		System.arraycopy(libs, 0, newJars, currentJars.length, libs.length);
+		install.setProcessorJars(newJars);
+
+		tableViewer.add(libs);
+	}
+
+	private void addWorkspace(IStructuredSelection selection)
+	{
+		IDialogSettings dialogSettings = XSLDebugUIPlugin.getDefault().getDialogSettings();
+		String lastUsedPath = dialogSettings.get(LAST_WORKSPACE_PATH_SETTING);
+		IPath lastPath = null;
+		if (lastUsedPath != null)
+		{
+			lastPath = Path.fromPortableString(lastUsedPath);
+		}
+
+		// IResource currentResource = getResource();
+		ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(tableViewer.getControl().getShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider());
+		dialog.setTitle(ProcessorMessages.ProcessorLibraryBlock_WorkspaceFileDialog_Title);
+		dialog.setMessage(ProcessorMessages.ProcessorLibraryBlock_WorkspaceFileDialog_Message);
+		dialog.setValidator(validator);
+		dialog.addFilter(new ViewerFilter()
+		{
+			@Override
+			public boolean select(Viewer viewer, Object parentElement, Object element)
+			{
+				if (element instanceof IContainer)
+					return true;
+				else if (element instanceof IFile)
+				{
+					IFile file = (IFile) element;
+					String extension = file.getFileExtension();
+					if (extension == null)
+						return false;
+					return extension.equals("jar"); //$NON-NLS-1$
+				}
+				return false;
+			}
+		});
+		dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
+		if (lastPath != null)
+			dialog.setInitialSelection(lastPath);
+		dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
+		dialog.setAllowMultiple(true);
+
+		if (dialog.open() == Window.OK)
+		{
+			Object[] elements = dialog.getResult();
+			if (elements.length > 0)
+			{
+				IProcessorJar[] libs = new IProcessorJar[elements.length];
+				for (int i = 0; i < elements.length; i++)
+				{
+					IFile jar = (IFile) elements[i];
+					libs[i] = JAXPRuntime.createProcessorJar(jar.getFullPath());
+				}
+				IProcessorJar[] currentJars = install.getProcessorJars();
+				IProcessorJar[] newJars = new IProcessorJar[currentJars.length + libs.length];
+				System.arraycopy(currentJars, 0, newJars, 0, currentJars.length);
+				System.arraycopy(libs, 0, newJars, currentJars.length, libs.length);
+				install.setProcessorJars(newJars);
+
+				tableViewer.add(libs);
+
+				lastPath = libs[0].getPath();
+				lastPath = lastPath.uptoSegment(lastPath.segmentCount());
+				dialogSettings.put(LAST_WORKSPACE_PATH_SETTING, lastPath.toPortableString());
+			}
+		}
+	}
+
+	private void remove(IStructuredSelection selection)
+	{
+		List<IProcessorJar> currentJars = new ArrayList<IProcessorJar>(Arrays.asList(install.getProcessorJars()));
+		for (Iterator<?> iter = selection.iterator(); iter.hasNext();)
+		{
+			currentJars.remove(iter.next());
+		}
+		install.setProcessorJars((IProcessorJar[]) currentJars.toArray(new IProcessorJar[0]));
+		tableViewer.remove(selection.toArray());
+	}
+
+	public void selectionChanged(SelectionChangedEvent event)
+	{
+		updateButtons();
+	}
+
+	private void updateButtons()
+	{
+		IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
+		removeButton.setEnabled(!selection.isEmpty());
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorsPreferencePage.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorsPreferencePage.java
new file mode 100644
index 0000000..bb83fac
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/ProcessorsPreferencePage.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class ProcessorsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage
+{
+	private InstalledProcessorsBlock processorsBlock;
+
+	public ProcessorsPreferencePage()
+	{
+		super();
+		// only used when page is shown programatically
+		setTitle(Messages.getString("ProcessorsPreferencePage.0")); //$NON-NLS-1$
+		setDescription(Messages.getString("ProcessorsPreferencePage.1")); //$NON-NLS-1$
+	}
+
+	public void init(IWorkbench workbench)
+	{
+	}
+
+	@Override
+	protected Control createContents(Composite ancestor)
+	{
+		initializeDialogUnits(ancestor);
+
+		noDefaultAndApplyButton();
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 1;
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		ancestor.setLayout(layout);
+
+		processorsBlock = new InstalledProcessorsBlock();
+		processorsBlock.createControl(ancestor);
+		Control control = processorsBlock.getControl();
+		GridData data = new GridData(GridData.FILL_BOTH);
+		data.horizontalSpan = 1;
+		control.setLayoutData(data);
+
+		// TODO PlatformUI.getWorkbench().getHelpSystem().setHelp...
+
+		initDefaultInstall();
+		processorsBlock.addSelectionChangedListener(new ISelectionChangedListener()
+		{
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				IProcessorInstall install = getCurrentDefaultProcessor();
+				if (install == null)
+				{
+					setValid(false);
+					setErrorMessage(Messages.getString("ProcessorsPreferencePage.2")); //$NON-NLS-1$
+				}
+				else
+				{
+					setValid(true);
+					setErrorMessage(null);
+				}
+			}
+		});
+		applyDialogFont(ancestor);
+		return ancestor;
+	}
+
+	@Override
+	public boolean performOk()
+	{
+		processorsBlock.saveColumnSettings();
+		final boolean[] ok = new boolean[1];
+		try
+		{
+			final IProcessorInstall[] installs = processorsBlock.getProcessors();
+			final IProcessorInstall defaultProcessor = getCurrentDefaultProcessor();
+			IRunnableWithProgress runnable = new IRunnableWithProgress()
+			{
+				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
+				{
+					try
+					{
+						JAXPRuntime.saveProcessorPreferences(installs,defaultProcessor,monitor);
+					}
+					catch (CoreException e)
+					{
+						XSLDebugUIPlugin.log(e);
+					}
+					ok[0] = !monitor.isCanceled();
+				}
+			};
+			XSLDebugUIPlugin.getDefault().getWorkbench().getProgressService().busyCursorWhile(runnable);
+		}
+		catch (InvocationTargetException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		catch (InterruptedException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		return ok[0];
+	}
+
+	private void initDefaultInstall()
+	{
+		IProcessorInstall realDefault = JAXPRuntime.getDefaultProcessor();
+		if (realDefault != null)
+		{
+			IProcessorInstall[] installs = processorsBlock.getProcessors();
+			for (IProcessorInstall fakeInstall : installs)
+			{
+				if (fakeInstall.getId().equals(realDefault.getId()))
+				{
+					verifyDefaultVM(fakeInstall);
+					break;
+				}
+			}
+		}
+	}
+
+	private void verifyDefaultVM(IProcessorInstall install)
+	{
+		if (install != null)
+		{
+			processorsBlock.setCheckedInstall(install);
+		}
+		else
+		{
+			processorsBlock.setCheckedInstall(null);
+		}
+	}
+
+	private IProcessorInstall getCurrentDefaultProcessor()
+	{
+		return processorsBlock.getCheckedInstall();
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/messages.properties
new file mode 100644
index 0000000..0dbe494
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/preferences/messages.properties
@@ -0,0 +1,3 @@
+ProcessorsPreferencePage.0=Java XSLT Processors
+ProcessorsPreferencePage.1=Add, remove or edit XSLT processor definitions.\nBy default, the checked Processor is used for all transformations.
+ProcessorsPreferencePage.2=Select a default XSLT Processor
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributeDialog.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributeDialog.java
new file mode 100644
index 0000000..885ec53
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributeDialog.java
@@ -0,0 +1,161 @@
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wst.xsl.jaxp.launching.IAttribute;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchAttributes;
+import org.eclipse.wst.xsl.launching.config.LaunchAttribute;
+
+public class AttributeDialog extends StatusDialog
+{
+	private Table table;
+	private TableViewer tViewer;
+	private Text text;
+	private List<IAttribute> attributes = new ArrayList<IAttribute>();
+	private List<IAttribute> selectedAttributes = new ArrayList<IAttribute>();
+
+	public AttributeDialog(Shell parent, LaunchAttributes launchAttributes)
+	{
+		super(parent);
+		setTitle("Select Processor Attributes");
+		
+		Set<String> attributeSet = new HashSet<String>();
+		for (LaunchAttribute att : launchAttributes.getAttributes())
+		{
+			attributeSet.add(att.uri);
+		}
+		for (IProcessorType type : JAXPRuntime.getProcessorTypes())
+		{
+			for (IAttribute attribute : type.getAttributes())
+			{
+				if (!attributeSet.contains(attribute.getURI()))
+				{
+					attributeSet.add(attribute.getURI());
+					attributes.add(attribute);
+				}
+			}
+		}
+	}
+	
+	@Override
+	protected Control createDialogArea(Composite parent)
+	{
+		Composite comp = new Composite(parent,SWT.NONE);
+		GridData gd = new GridData(SWT.FILL,SWT.FILL,true,true);
+		gd.widthHint = 400;
+		comp.setLayoutData(gd);
+		comp.setLayout(new GridLayout());
+		
+		Label label = new Label(comp,SWT.NONE);
+		label.setText("Select one or more attributes to set on the XSLT processor.");
+		
+		
+		table = new Table(comp,SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI);
+		table.setHeaderVisible(false);
+		gd = new GridData(SWT.FILL,SWT.FILL,true,true);
+		gd.verticalIndent = 10;
+		gd.heightHint = 200;
+		table.setLayoutData(gd);
+		
+		tViewer = new TableViewer(table);
+		tViewer.setContentProvider(new IStructuredContentProvider()
+		{
+			public Object[] getElements(Object inputElement)
+			{
+				return attributes.toArray(new IAttribute[0]);
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+			}
+		});
+		tViewer.setLabelProvider(new LabelProvider(){
+			@Override
+			public String getText(Object element)
+			{
+				IAttribute attribute = (IAttribute)element;
+				return attribute.getURI();
+			}
+		});
+		tViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				IAttribute a1 = (IAttribute) e1;
+				IAttribute a2 = (IAttribute) e2;
+				return a1.getURI().compareTo(a2.getURI());
+			}
+		});
+		tViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				IStructuredSelection sel = (IStructuredSelection)event.getSelection();
+				selectedAttributes = sel.toList();
+				if (sel.isEmpty())
+					text.setText("");
+				else
+				{
+					IAttribute attribute = (IAttribute)sel.getFirstElement(); 
+					text.setText(attribute.getDescription());
+				}
+			}
+		});
+		tViewer.addDoubleClickListener(new IDoubleClickListener(){
+			public void doubleClick(DoubleClickEvent event)
+			{
+				buttonPressed(IDialogConstants.OK_ID);
+			}
+		});
+		tViewer.setInput(attributes);
+		
+		text = new Text(comp,SWT.BORDER | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL);
+		text.setEditable(false);
+		gd = new GridData(SWT.FILL,SWT.FILL,true,false);
+		gd.heightHint = 80;
+		text.setLayoutData(gd);
+		
+		if (attributes.size() > 0)
+		{
+			tViewer.setSelection(new StructuredSelection(tViewer.getElementAt(0)), true);
+		}
+		
+		return comp;
+	}
+	
+	public List<IAttribute> getAttributes()
+	{
+		return selectedAttributes;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributesBlock.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributesBlock.java
new file mode 100644
index 0000000..76885a2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/AttributesBlock.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.wst.xsl.internal.debug.ui.AbstractTableBlock;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIConstants;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.JAXPDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.IAttribute;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchAttributes;
+import org.eclipse.wst.xsl.launching.config.LaunchAttribute;
+
+public class AttributesBlock extends AbstractTableBlock
+{
+	private Table table;
+	private TableViewer tViewer;
+	private LaunchAttributes attributes;
+	private Button removeButton;
+	private Map<String,IAttribute> attributeUris = new HashMap<String,IAttribute>();
+	
+	public AttributesBlock()
+	{
+		for (IProcessorType type : JAXPRuntime.getProcessorTypes())
+		{
+			for (IAttribute attribute : type.getAttributes())
+			{
+				attributeUris.put(attribute.getURI(), attribute);
+			}
+		}
+	}
+
+	@Override
+	protected IDialogSettings getDialogSettings()
+	{
+		return XSLDebugUIPlugin.getDefault().getDialogSettings();
+	}
+
+	@Override
+	protected String getQualifier()
+	{
+		return JAXPDebugUIPlugin.PLUGIN_ID+"."+getClass().getCanonicalName();
+	}
+
+	@Override
+	protected Table getTable()
+	{
+		return table;
+	}
+
+	public void createControl(Composite parent)
+	{
+		TabItem item = new TabItem((TabFolder)parent,SWT.NONE);
+		item.setText("Attributes");
+		
+		Composite composite = new Composite(parent,SWT.NONE);
+		GridLayout layout = new GridLayout(2,false);
+		layout.marginBottom = 0;
+		layout.marginWidth = 0;
+		composite.setLayout(layout);
+		item.setControl(composite);
+		
+		table = new Table(composite,SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI);
+		table.setHeaderVisible(true);
+		table.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true));
+		table.addKeyListener(new KeyAdapter() {
+			public void keyPressed(KeyEvent event) {
+				if (event.character == SWT.DEL && event.stateMask == 0) {
+					performRemove();
+				}
+			}
+		});
+		
+		TableColumn tc1 = new TableColumn(table,SWT.NONE);
+		tc1.setText("Name");
+		tc1.setWidth(350);
+		tc1.setResizable(true);
+		
+		TableColumn tc2 = new TableColumn(table,SWT.NONE);
+		tc2.setText("Value");
+		tc2.setWidth(50);
+		tc2.setResizable(true);
+		
+		Composite buttonComp = new Composite(composite,SWT.FILL);
+		buttonComp.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		GridLayout gl = new GridLayout();
+		gl.marginWidth = 0;
+		buttonComp.setLayout(gl);
+		
+		Button addButton = new Button(buttonComp,SWT.PUSH);
+		addButton.setText("Add");
+		addButton.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		addButton.addSelectionListener(new SelectionListener(){
+			public void widgetDefaultSelected(SelectionEvent e)
+			{
+			}
+			public void widgetSelected(SelectionEvent e)
+			{
+				AttributeDialog dialog = new AttributeDialog(getShell(),attributes);
+				if (dialog.open() == AttributeDialog.OK)
+				{
+					List<IAttribute> newAttributes = dialog.getAttributes();
+					LaunchAttribute first = null;
+					for (IAttribute attribute : newAttributes)
+					{
+						LaunchAttribute att = new LaunchAttribute(attribute.getURI(),"string",null);
+						if (first == null)
+							first = att;
+						attributes.addAttribute(att);
+					}
+					if (newAttributes.size() > 0)
+					{
+						tViewer.refresh();
+						tViewer.setSelection(new StructuredSelection(first), true);
+						tViewer.editElement(first, 1);
+						updateLaunchConfigurationDialog();
+					}
+				}
+			}
+		});
+		
+		removeButton = new Button(buttonComp,SWT.PUSH);
+		removeButton.setText("Remove");
+		removeButton.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		removeButton.addSelectionListener(new SelectionListener(){
+			public void widgetDefaultSelected(SelectionEvent e)
+			{
+			}
+			public void widgetSelected(SelectionEvent e)
+			{
+				performRemove();
+			}
+		});
+		
+		setControl(table);
+		
+		tViewer = new TableViewer(table);
+		tViewer.setContentProvider(new IStructuredContentProvider()
+		{
+			public Object[] getElements(Object inputElement)
+			{
+				return attributes.getAttributes().toArray(new LaunchAttribute[0]);
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+				attributes = (LaunchAttributes) newInput;
+			}
+		});
+		tViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				LaunchAttribute a1 = (LaunchAttribute) e1;
+				LaunchAttribute a2 = (LaunchAttribute) e2;
+				return a1.uri.compareTo(a2.uri);
+			}
+		});
+		tViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				updateRemoveButton();
+			}
+		});
+		
+		TableViewerColumn tvc1 = new TableViewerColumn(tViewer,tc1);
+		tvc1.setLabelProvider(new CellLabelProvider(){
+			@Override
+			public void update(ViewerCell cell)
+			{
+				LaunchAttribute tv = (LaunchAttribute) cell.getElement();
+				cell.setText(tv.uri);
+			}
+			
+			@Override
+			public int getToolTipTimeDisplayed(Object object)
+			{
+				return 5000;
+			}
+			
+			@Override
+			public String getToolTipText(Object element)
+			{
+				LaunchAttribute tv = (LaunchAttribute) element;
+				return attributeUris.get(tv.uri).getDescription();
+			}
+			
+		});
+		
+//		ColumnViewerToolTipSupport.enableFor(tViewer);
+		
+		TableViewerColumn tvc2 = new TableViewerColumn(tViewer,tc2);
+		tvc2.setLabelProvider(new CellLabelProvider(){
+			@Override
+			public void update(ViewerCell cell)
+			{
+				LaunchAttribute tv = (LaunchAttribute) cell.getElement();
+				cell.setText(tv.value);
+			}
+		});
+		
+		tvc2.setEditingSupport(new EditingSupport(tViewer){
+
+			@Override
+			protected boolean canEdit(Object element)
+			{
+				return true;
+			}
+
+			@Override
+			protected CellEditor getCellEditor(Object element)
+			{
+				return new TextCellEditor(table);
+			}
+
+			@Override
+			protected Object getValue(Object element)
+			{
+				LaunchAttribute tv = (LaunchAttribute)element;
+				return tv.value == null ? "" : tv.value;
+			}
+
+			@Override
+			protected void setValue(Object element, Object value)
+			{
+				LaunchAttribute tv = (LaunchAttribute)element;
+				tv.setValue((String)value);
+				updateLaunchConfigurationDialog();
+				tViewer.update(tv, null);
+			}
+			
+		});
+		
+		restoreColumnSettings();
+	}
+
+	protected void updateRemoveButton()
+	{
+		removeButton.setEnabled(!tViewer.getSelection().isEmpty());
+	}
+
+	public String getName()
+	{
+		return Messages.getString("AttributesBlock.16"); //$NON-NLS-1$
+	}
+
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
+	{
+	}
+
+	private void initializeAttributesFromStorage(ILaunchConfiguration configuration) throws CoreException
+	{
+		String s = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_ATTRIBUTES, (String) null);
+		if (s != null && s.length() > 0)
+		{
+			attributes = LaunchAttributes.fromXML(new ByteArrayInputStream(s.getBytes()));
+		}
+		else
+		{
+			attributes = new LaunchAttributes();
+		}
+		tViewer.setInput(attributes);
+		updateRemoveButton();
+	}
+
+	public void initializeFrom(ILaunchConfiguration configuration)
+	{
+		try
+		{
+			initializeAttributesFromStorage(configuration);
+		}
+		catch (CoreException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+	}
+
+	public void performApply(ILaunchConfigurationWorkingCopy configuration)
+	{
+		try
+		{
+			String xml = attributes.toXML();
+			configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_ATTRIBUTES, xml);
+		}
+		catch (ParserConfigurationException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		catch (IOException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		catch (TransformerException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+	}
+
+	private void performRemove()
+	{
+		IStructuredSelection sel = (IStructuredSelection)tViewer.getSelection();
+		for (Iterator iterator = sel.iterator(); iterator.hasNext();)
+		{
+			LaunchAttribute att = (LaunchAttribute) iterator.next();
+			attributes.removeAtribute(att.uri);
+		}
+		tViewer.refresh();
+		updateLaunchConfigurationDialog();
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/InstallStandin.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/InstallStandin.java
new file mode 100644
index 0000000..35b3927
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/InstallStandin.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.ProcessorInstall;
+
+public class InstallStandin extends ProcessorInstall
+{
+	public InstallStandin(IProcessorInstall install)
+	{
+		super(install.getId(), install.getName(), install.getProcessorType().getId(), install.getProcessorJars(), install.getDebugger() != null ? install.getDebugger().getId() : null, install
+				.getSupports(), install.isContributed());
+	}
+
+	public InstallStandin(String id, String name, String typeId, String debuggerId, IProcessorJar[] jars)
+	{
+		super(id, name, typeId, jars, debuggerId, "", false); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarContentProvider.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarContentProvider.java
new file mode 100644
index 0000000..f37a0de
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarContentProvider.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+
+public class JarContentProvider implements IStructuredContentProvider
+{
+	private IProcessorInstall install;
+
+	public Object[] getElements(Object inputElement)
+	{
+		return install.getProcessorJars();
+	}
+
+	public void dispose()
+	{
+	}
+
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+	{
+		install = (IProcessorInstall) newInput;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarLabelProvider.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarLabelProvider.java
new file mode 100644
index 0000000..5ded313
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/JarLabelProvider.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+
+public class JarLabelProvider extends LabelProvider
+{
+	@Override
+	public String getText(Object element)
+	{
+		IProcessorJar jar = (IProcessorJar) element;
+		IPath path = jar.getPath();
+		return path.lastSegment() + " - " + path.removeLastSegments(1).toOSString() + ""; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/Messages.java
new file mode 100644
index 0000000..9c12c93
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/Messages.java
@@ -0,0 +1,22 @@
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private Messages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertiesBlock.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertiesBlock.java
new file mode 100644
index 0000000..94989c5
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertiesBlock.java
@@ -0,0 +1,376 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.wst.xsl.internal.debug.ui.AbstractTableBlock;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.JAXPDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.IOutputProperty;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchProperties;
+
+public class OutputPropertiesBlock extends AbstractTableBlock
+{
+	private Table table;
+	private TableViewer tViewer;
+	private LaunchProperties properties;
+	private Button removeButton;
+	private Map<String,IOutputProperty> propertyUris = new HashMap<String,IOutputProperty>();
+	
+	public OutputPropertiesBlock()
+	{
+		for (IProcessorType type : JAXPRuntime.getProcessorTypes())
+		{
+			for (IOutputProperty property : type.getOutputProperties())
+			{
+				propertyUris.put(property.getURI(), property);
+			}
+		}
+	}
+
+	@Override
+	protected IDialogSettings getDialogSettings()
+	{
+		return XSLDebugUIPlugin.getDefault().getDialogSettings();
+	}
+
+	@Override
+	protected String getQualifier()
+	{
+		return JAXPDebugUIPlugin.PLUGIN_ID+"."+getClass().getCanonicalName();
+	}
+
+	@Override
+	protected Table getTable()
+	{
+		return table;
+	}
+
+	public void createControl(Composite parent)
+	{
+		TabItem item = new TabItem((TabFolder)parent,SWT.NONE);
+		item.setText("Output Properties");
+		
+		Composite composite = new Composite(parent,SWT.NONE);
+		GridLayout layout = new GridLayout(2,false);
+		layout.marginBottom = 0;
+		layout.marginWidth = 0;
+		composite.setLayout(layout);
+		item.setControl(composite);
+		
+		table = new Table(composite,SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI);
+		table.setHeaderVisible(true);
+		table.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true));
+		table.addKeyListener(new KeyAdapter() {
+			public void keyPressed(KeyEvent event) {
+				if (event.character == SWT.DEL && event.stateMask == 0) {
+					performRemove();
+				}
+			}
+		});
+
+		
+		TableColumn tc1 = new TableColumn(table,SWT.NONE);
+		tc1.setText("Name");
+		tc1.setWidth(350);
+		tc1.setResizable(true);
+		
+		TableColumn tc2 = new TableColumn(table,SWT.NONE);
+		tc2.setText("Value");
+		tc2.setWidth(50);
+		tc2.setResizable(true);
+		
+		Composite buttonComp = new Composite(composite,SWT.FILL);
+		buttonComp.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		GridLayout gl = new GridLayout();
+		gl.marginWidth = 0;
+		buttonComp.setLayout(gl);
+		
+		Button addButton = new Button(buttonComp,SWT.PUSH);
+		addButton.setText("Add");
+		addButton.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		addButton.addSelectionListener(new SelectionListener(){
+			public void widgetDefaultSelected(SelectionEvent e)
+			{
+			}
+			public void widgetSelected(SelectionEvent e)
+			{
+				OutputPropertyDialog dialog = new OutputPropertyDialog(getShell(),properties);
+				if (dialog.open() == AttributeDialog.OK)
+				{
+					List<IOutputProperty> newProperties = dialog.getOutpuProperties();
+					String first = null;
+					for (IOutputProperty property : newProperties)
+					{
+						String att = property.getURI();
+						if (first == null)
+							first = att;
+						properties.setProperty(property.getURI(), null);
+					}
+					if (newProperties.size() > 0)
+					{
+						tViewer.refresh();
+						tViewer.setSelection(new StructuredSelection(first), true);
+						tViewer.editElement(first, 1);
+						updateLaunchConfigurationDialog();
+					}
+				}
+			}
+		});
+		
+		removeButton = new Button(buttonComp,SWT.PUSH);
+		removeButton.setText("Remove");
+		removeButton.setLayoutData(new GridData(SWT.FILL,SWT.TOP,false,false));
+		removeButton.addSelectionListener(new SelectionListener(){
+			public void widgetDefaultSelected(SelectionEvent e)
+			{
+			}
+			public void widgetSelected(SelectionEvent e)
+			{
+				performRemove();
+			}
+		});
+		
+		setControl(table);
+		
+		tViewer = new TableViewer(table);
+		tViewer.setContentProvider(new IStructuredContentProvider()
+		{
+			public Object[] getElements(Object inputElement)
+			{
+				return properties.getProperties().keySet().toArray(new String[0]);
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+			}
+		});
+		tViewer.setSorter(new ViewerSorter());
+		tViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				updateRemoveButton();
+			}
+		});
+		
+		TableViewerColumn tvc1 = new TableViewerColumn(tViewer,tc1);
+		tvc1.setLabelProvider(new CellLabelProvider(){
+			@Override
+			public void update(ViewerCell cell)
+			{
+				String tv = (String) cell.getElement();
+				cell.setText(tv);
+			}
+			
+			@Override
+			public int getToolTipTimeDisplayed(Object object)
+			{
+				return 5000;
+			}
+			
+			@Override
+			public String getToolTipText(Object element)
+			{
+				String tv = (String) element;
+				return propertyUris.get(tv).getDescription();
+			}
+			
+		});
+		
+//		ColumnViewerToolTipSupport.enableFor(tViewer);
+		
+		TableViewerColumn tvc2 = new TableViewerColumn(tViewer,tc2);
+		tvc2.setLabelProvider(new CellLabelProvider(){
+			@Override
+			public void update(ViewerCell cell)
+			{
+				String tv = (String) cell.getElement();
+				String val = properties.getProperty(tv);
+				cell.setText(val == null ? "" : val);
+			}
+		});
+		
+		tvc2.setEditingSupport(new EditingSupport(tViewer){
+
+			@Override
+			protected boolean canEdit(Object element)
+			{
+				return true;
+			}
+
+			@Override
+			protected CellEditor getCellEditor(Object element)
+			{
+				return new TextCellEditor(table);
+			}
+
+			@Override
+			protected Object getValue(Object element)
+			{
+				String tv = (String)element;
+				String val = properties.getProperty(tv);
+				return val == null ? "" : val;
+			}
+
+			@Override
+			protected void setValue(Object element, Object value)
+			{
+				String tv = (String)element;
+				properties.setProperty(tv, (String)value);
+				updateLaunchConfigurationDialog();
+				tViewer.update(tv, null);
+			}
+			
+		});
+		
+		restoreColumnSettings();
+	}
+
+	protected void updateRemoveButton()
+	{
+		removeButton.setEnabled(!tViewer.getSelection().isEmpty());
+	}
+
+	public String getName()
+	{
+		return Messages.getString("AttributesBlock.16"); //$NON-NLS-1$
+	}
+
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
+	{
+//		LaunchProperties p = new LaunchProperties();
+//		p.setProperty("indent", "yes");
+//		try
+//		{
+//			String xml = p.toXML();
+//			configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_OUTPUT_PROPERTIES, xml);
+//		}
+//		catch (ParserConfigurationException e)
+//		{
+//			XSLDebugUIPlugin.log(e);
+//		}
+//		catch (IOException e)
+//		{
+//			XSLDebugUIPlugin.log(e);
+//		}
+//		catch (TransformerException e)
+//		{
+//			XSLDebugUIPlugin.log(e);
+//		}
+	}
+
+	private void initializePropertiesFromStorage(ILaunchConfiguration configuration) throws CoreException
+	{
+		String s = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_OUTPUT_PROPERTIES, (String) null);
+		if (s != null && s.length() > 0)
+		{
+			properties = LaunchProperties.fromXML(new ByteArrayInputStream(s.getBytes()));
+		}
+		else
+		{
+			properties = new LaunchProperties();
+		}
+		tViewer.setInput(properties);
+		updateRemoveButton();
+	}
+
+	public void initializeFrom(ILaunchConfiguration configuration)
+	{
+		try
+		{
+			initializePropertiesFromStorage(configuration);
+		}
+		catch (CoreException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+	}
+
+	public void performApply(ILaunchConfigurationWorkingCopy configuration)
+	{
+		try
+		{
+			String xml = properties.toXML();
+			configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_OUTPUT_PROPERTIES, xml);
+		}
+		catch (ParserConfigurationException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		catch (IOException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+		catch (TransformerException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+	}
+
+	private void performRemove()
+	{
+		IStructuredSelection sel = (IStructuredSelection)tViewer.getSelection();
+		for (Iterator iterator = sel.iterator(); iterator.hasNext();)
+		{
+			String att = (String) iterator.next();
+			properties.removeProperty(att);
+		}
+		tViewer.refresh();
+		updateLaunchConfigurationDialog();
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertyDialog.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertyDialog.java
new file mode 100644
index 0000000..2fc7b7c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/OutputPropertyDialog.java
@@ -0,0 +1,160 @@
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wst.xsl.jaxp.launching.IOutputProperty;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchProperties;
+
+public class OutputPropertyDialog extends StatusDialog
+{
+	private Table table;
+	private TableViewer tViewer;
+	private Text text;
+	private List<IOutputProperty> properties = new ArrayList<IOutputProperty>();
+	private List<IOutputProperty> selectedProperties = new ArrayList<IOutputProperty>();
+
+	public OutputPropertyDialog(Shell parent, LaunchProperties launchProperties)
+	{
+		super(parent);
+		setTitle("Select Output Properties");
+		
+		Set<String> propertySet = new HashSet<String>();
+		for (String att : launchProperties.getProperties().keySet())
+		{
+			propertySet.add(att);
+		}
+		for (IProcessorType type : JAXPRuntime.getProcessorTypes())
+		{
+			for (IOutputProperty property : type.getOutputProperties())
+			{
+				if (!propertySet.contains(property.getURI()))
+				{
+					propertySet.add(property.getURI());
+					properties.add(property);
+				}
+			}
+		}
+	}
+	
+	@Override
+	protected Control createDialogArea(Composite parent)
+	{
+		Composite comp = new Composite(parent,SWT.NONE);
+		GridData gd = new GridData(SWT.FILL,SWT.FILL,true,true);
+		gd.widthHint = 400;
+		comp.setLayoutData(gd);
+		comp.setLayout(new GridLayout());
+		
+		Label label = new Label(comp,SWT.NONE);
+		label.setText("Select one or more output properties for the transformation.");
+		
+		
+		table = new Table(comp,SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI);
+		table.setHeaderVisible(false);
+		gd = new GridData(SWT.FILL,SWT.FILL,true,true);
+		gd.verticalIndent = 10;
+		gd.heightHint = 200;
+		table.setLayoutData(gd);
+		
+		tViewer = new TableViewer(table);
+		tViewer.setContentProvider(new IStructuredContentProvider()
+		{
+			public Object[] getElements(Object inputElement)
+			{
+				return properties.toArray(new IOutputProperty[0]);
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+			}
+		});
+		tViewer.setLabelProvider(new LabelProvider(){
+			@Override
+			public String getText(Object element)
+			{
+				IOutputProperty property = (IOutputProperty)element;
+				return property.getURI();
+			}
+		});
+		tViewer.setSorter(new ViewerSorter()
+		{
+			@Override
+			public int compare(Viewer viewer, Object e1, Object e2)
+			{
+				IOutputProperty a1 = (IOutputProperty) e1;
+				IOutputProperty a2 = (IOutputProperty) e2;
+				return a1.getURI().compareTo(a2.getURI());
+			}
+		});
+		tViewer.addSelectionChangedListener(new ISelectionChangedListener(){
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				IStructuredSelection sel = (IStructuredSelection)event.getSelection();
+				selectedProperties = sel.toList();
+				if (sel.isEmpty())
+					text.setText("");
+				else
+				{
+					IOutputProperty property = (IOutputProperty)sel.getFirstElement(); 
+					text.setText(property.getDescription());
+				}
+			}
+		});
+		tViewer.addDoubleClickListener(new IDoubleClickListener(){
+			public void doubleClick(DoubleClickEvent event)
+			{
+				buttonPressed(IDialogConstants.OK_ID);
+			}
+		});
+		tViewer.setInput(properties);
+		
+		text = new Text(comp,SWT.BORDER | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL);
+		text.setEditable(false);
+		gd = new GridData(SWT.FILL,SWT.FILL,true,false);
+		gd.heightHint = 80;
+		text.setLayoutData(gd);
+		
+		if (properties.size() > 0)
+		{
+			tViewer.setSelection(new StructuredSelection(tViewer.getElementAt(0)), true);
+		}
+		
+		return comp;
+	}
+	
+	public List<IOutputProperty> getOutpuProperties()
+	{
+		return selectedProperties;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorBlock.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorBlock.java
new file mode 100644
index 0000000..2353884
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorBlock.java
@@ -0,0 +1,376 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.preferences.ProcessorsPreferencePage;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class ProcessorBlock extends AbstractLaunchConfigurationTab
+{
+	private Button usePreferencesRadio;
+	private Button alterPreferencesButton;
+	private Button overridePreferencesRadio;
+	private Combo runCombo;
+	private Button installedProcessorsButton;
+	private ComboViewer runComboViewer;
+	private ComboViewer factoryComboViewer;
+	private ITransformerFactory currentFactory;
+
+	public ProcessorBlock()
+	{
+	}
+
+	public void createControl(Composite parent)
+	{
+		Font font = parent.getFont();
+
+		Composite group = new Composite(parent, SWT.NULL);
+		setControl(group);
+		group.setLayout(new GridLayout(2, false));
+		group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		group.setFont(font);
+//		group.setText(ProcessorMessages.ProcessorBlock_0);
+
+		usePreferencesRadio = new Button(group, SWT.RADIO);
+		usePreferencesRadio.setText(ProcessorMessages.ProcessorBlock_1);
+		usePreferencesRadio.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				preferencesSelected();
+				updateLaunchConfigurationDialog();
+			}
+		});
+
+		alterPreferencesButton = new Button(group, SWT.PUSH);
+		alterPreferencesButton.setText(ProcessorMessages.ProcessorBlock_2);
+		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+		gd.widthHint = 150;
+		alterPreferencesButton.setLayoutData(gd);
+		alterPreferencesButton.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				IPreferencePage page = new ProcessorsPreferencePage();
+				showPrefPage("org.eclipse.wst.xslt.launching.ui.preferences.ProcessorPreferencePage", page); //$NON-NLS-1$
+			}
+		});
+
+		overridePreferencesRadio = new Button(group, SWT.RADIO);
+		overridePreferencesRadio.setText(ProcessorMessages.ProcessorBlock_4);
+		overridePreferencesRadio.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				overrideSelected();
+				updateLaunchConfigurationDialog();
+			}
+		});
+
+		installedProcessorsButton = new Button(group, SWT.PUSH);
+		installedProcessorsButton.setText(ProcessorMessages.ProcessorsComboBlock_1);
+		gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+		gd.widthHint = 150;
+		installedProcessorsButton.setLayoutData(gd);
+		installedProcessorsButton.addSelectionListener(new SelectionAdapter()
+		{
+			@Override
+			public void widgetSelected(SelectionEvent e)
+			{
+				IPreferencePage page = new ProcessorsPreferencePage();
+				showPrefPage("org.eclipse.wst.xslt.launching.ui.preferences.ProcessorPreferencePage", page); //$NON-NLS-1$
+			}
+		});
+
+		Composite settingsComp = new Composite(group, SWT.NONE);
+		GridLayout gl = new GridLayout(3, false);
+		gl.marginHeight = 2;
+		settingsComp.setLayout(gl);
+		gd = new GridData(GridData.FILL_HORIZONTAL);
+		gd.horizontalIndent = 15;
+		gd.horizontalSpan = 2;
+		settingsComp.setLayoutData(gd);
+		settingsComp.setFont(font);
+
+		Label label = new Label(settingsComp, SWT.NONE);
+		label.setText(ProcessorMessages.ProcessorBlock_6);
+		runCombo = new Combo(settingsComp, SWT.READ_ONLY | SWT.SINGLE);
+		runCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		runComboViewer = new ComboViewer(runCombo);
+		runComboViewer.setContentProvider(new ComboContentProvider());
+		runComboViewer.setLabelProvider(new ComboLabelProvider());
+		runComboViewer.setInput(JAXPRuntime.getProcessors());
+		runComboViewer.addSelectionChangedListener(new ISelectionChangedListener()
+		{
+
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+				if (!sel.isEmpty())
+				{
+					IProcessorInstall processor = (IProcessorInstall) sel.getFirstElement();
+					
+					if (processor.getProcessorType().getTransformerFactories().length > 1)
+						factoryComboViewer.getCombo().setVisible(true);
+					else
+						factoryComboViewer.getCombo().setVisible(false);
+
+					factoryComboViewer.setInput(processor.getProcessorType());
+					
+					boolean found = false;
+					for (ITransformerFactory tf : processor.getProcessorType().getTransformerFactories())
+					{
+						if (tf.equals(currentFactory))
+						{
+							found = true;
+							break;
+						}
+					}
+					if (!found)
+					{
+						currentFactory = processor.getProcessorType().getDefaultTransformerFactory();
+						if (currentFactory!=null)
+							factoryComboViewer.setSelection(new StructuredSelection(currentFactory));
+					}
+				}
+				updateLaunchConfigurationDialog();
+			}
+		});
+
+		Combo factoryCombo = new Combo(settingsComp, SWT.READ_ONLY | SWT.SINGLE);
+		factoryCombo.setLayoutData(new GridData(80,SWT.DEFAULT));
+		factoryComboViewer = new ComboViewer(factoryCombo);
+		factoryComboViewer.setContentProvider(new IStructuredContentProvider(){
+
+			private IProcessorType type;
+			
+			public Object[] getElements(Object inputElement)
+			{
+				return type.getTransformerFactories();
+			}
+
+			public void dispose()
+			{
+			}
+
+			public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+			{
+				this.type = (IProcessorType)newInput;
+			}
+			
+		});
+		factoryComboViewer.setLabelProvider(new LabelProvider(){
+			@Override
+			public String getText(Object element)
+			{
+				ITransformerFactory f = (ITransformerFactory)element;
+				return f.getName(); // + " - " + f.getFactoryClass();
+			}
+		});
+		factoryComboViewer.addSelectionChangedListener(new ISelectionChangedListener()
+		{
+
+			public void selectionChanged(SelectionChangedEvent event)
+			{
+				currentFactory = (ITransformerFactory)((IStructuredSelection)event.getSelection()).getFirstElement();
+				updateLaunchConfigurationDialog();
+			}
+		});
+
+//		overridePreferencesButton = new Button(group,SWT.CHECK);
+//		overridePreferencesButton.setText("Override preferences");
+//		gd = new GridData(SWT.NONE,SWT.NONE,false,false);
+//		overridePreferencesButton.setLayoutData(gd);
+//		overridePreferencesButton.addSelectionListener(new SelectionListener(){
+//			public void widgetDefaultSelected(SelectionEvent e)
+//			{}
+//			
+//			public void widgetSelected(SelectionEvent e)
+//			{
+//				firePreferenceProcessorChanged(overridePreferencesButton.getSelection());
+//			}
+//		});
+	}
+	
+
+	private void preferencesSelected()
+	{
+		alterPreferencesButton.setEnabled(true);
+		installedProcessorsButton.setEnabled(false);
+		runCombo.setEnabled(false);
+		factoryComboViewer.getCombo().setEnabled(false);
+		runComboViewer.setSelection(new StructuredSelection(getRunProcessorPreference()), true);
+	}
+
+	private void overrideSelected()
+	{
+		alterPreferencesButton.setEnabled(false);
+		installedProcessorsButton.setEnabled(true);
+		factoryComboViewer.getCombo().setEnabled(true);
+		runCombo.setEnabled(true);
+	}
+
+	private void showPrefPage(String id, IPreferencePage page)
+	{
+		XSLDebugUIPlugin.showPreferencePage(id, page);
+		// now refresh everything
+		runComboViewer.setInput(JAXPRuntime.getProcessors());
+		runComboViewer.setSelection(new StructuredSelection(getRunProcessorPreference()), true);
+		// preferencesSelected();
+	}
+
+	public String getName()
+	{
+		return ProcessorMessages.ProcessorBlock_7;
+	}
+
+	public void initializeFrom(ILaunchConfiguration configuration)
+	{
+		try
+		{
+			boolean useDefaultProcessor = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_DEFAULT_PROCESSOR, true);
+			if (useDefaultProcessor)
+			{
+				usePreferencesRadio.setSelection(true);
+				overridePreferencesRadio.setSelection(false);
+				preferencesSelected();
+			}
+			else
+			{
+				usePreferencesRadio.setSelection(false);
+				overridePreferencesRadio.setSelection(true);
+				overrideSelected();
+
+				IProcessorInstall runInstall = null;
+				String runId = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_PROCESSOR, (String) null);
+				if (runId != null)
+					runInstall = JAXPRuntime.getProcessor(runId);
+				if (runInstall == null)
+					runInstall = getRunProcessorPreference();
+				runComboViewer.setSelection(new StructuredSelection(runInstall));
+				
+
+				String factoryId = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_TRANSFORMER_FACTORY, (String) null);
+				if (factoryId == null)
+				{
+					currentFactory = runInstall.getProcessorType().getDefaultTransformerFactory();
+				}
+				else
+				{
+					for (ITransformerFactory tf : runInstall.getProcessorType().getTransformerFactories())
+					{
+						if (tf.getFactoryClass().equals(factoryId))
+						{
+							currentFactory = tf;
+							break;
+						}
+					}
+				}
+				
+				if (currentFactory == null)
+				{
+					currentFactory = runInstall.getProcessorType().getDefaultTransformerFactory();
+				}
+				if (currentFactory != null)
+				{
+					factoryComboViewer.setSelection(new StructuredSelection(currentFactory), true);
+				}
+			}
+		}
+		catch (CoreException e)
+		{
+			XSLDebugUIPlugin.log(e);
+		}
+	}
+
+	private IProcessorInstall getRunProcessorPreference()
+	{
+		return JAXPRuntime.getDefaultProcessor();
+	}
+
+	public void performApply(ILaunchConfigurationWorkingCopy configuration)
+	{
+		boolean usePreferences = usePreferencesRadio.getSelection();
+		configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_DEFAULT_PROCESSOR, usePreferences);
+		if (!usePreferences)
+		{
+			IProcessorInstall runprocessor = (IProcessorInstall) ((IStructuredSelection) runComboViewer.getSelection()).getFirstElement();
+			configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_PROCESSOR, runprocessor.getId());
+			configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_TRANSFORMER_FACTORY, currentFactory == null ? null : currentFactory.getFactoryClass());
+		}
+	}
+
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
+	{
+		configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_DEFAULT_PROCESSOR, true);
+		configuration.setAttribute(JAXPLaunchConfigurationConstants.ATTR_PROCESSOR, (String) null);
+	}
+
+	private class ComboContentProvider implements IStructuredContentProvider
+	{
+		public Object[] getElements(Object inputElement)
+		{
+			return JAXPRuntime.getProcessors();
+		}
+
+		public void dispose()
+		{
+		}
+
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+		{
+		}
+	}
+
+	private class ComboLabelProvider extends LabelProvider
+	{
+		@Override
+		public String getText(Object element)
+		{
+			IProcessorInstall install = (IProcessorInstall) element;
+			return install.getName();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDescriptor.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDescriptor.java
new file mode 100644
index 0000000..83bf92f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDescriptor.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+public abstract class ProcessorDescriptor
+{
+	public abstract String getDescription();
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDetailsDialog.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDetailsDialog.java
new file mode 100644
index 0000000..e0621f5
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorDetailsDialog.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+
+public class ProcessorDetailsDialog extends Dialog
+{
+	private final IProcessorInstall install;
+
+	public ProcessorDetailsDialog(Shell shell, IProcessorInstall install)
+	{
+		super(shell);
+		setShellStyle(getShellStyle() | SWT.RESIZE);
+		this.install = install;
+	}
+
+	@Override
+	protected void configureShell(Shell newShell)
+	{
+		super.configureShell(newShell);
+		newShell.setText(ProcessorMessages.ProcessorDetailsDialog_Title);
+		// TODO PlatformUI.getWorkbench().getHelpSystem().setHelp...
+	}
+
+	@Override
+	protected Control createDialogArea(Composite ancestor)
+	{
+		Composite parent = (Composite) super.createDialogArea(ancestor);
+		GridLayout layout = new GridLayout(2, false);
+		parent.setLayout(layout);
+
+		// type
+		createLabel(parent, ProcessorMessages.ProcessorDetailsDialog_installType);
+		createLabel(parent, install.getProcessorType().getLabel());
+
+		// name
+		createLabel(parent, ProcessorMessages.ProcessorDetailsDialog_installName);
+		createLabel(parent, install.getName());
+
+		// jars
+		Label label = createLabel(parent, ProcessorMessages.ProcessorDetailsDialog_installClasspath);
+		GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_BEGINNING);
+		label.setLayoutData(gd);
+		TableViewer libraryViewer = new TableViewer(parent);
+		gd = new GridData(GridData.FILL_BOTH);
+		gd.heightHint = 6;
+		libraryViewer.getControl().setLayoutData(gd);
+		libraryViewer.setContentProvider(new JarContentProvider());
+		libraryViewer.setLabelProvider(new JarLabelProvider());
+		libraryViewer.setInput(install);
+
+		applyDialogFont(parent);
+		return parent;
+	}
+
+	private Label createLabel(Composite parent, String text)
+	{
+		Label label = new Label(parent, SWT.NONE);
+		label.setText(text);
+		return label;
+	}
+
+	/**
+	 * Returns the name of the section that this dialog stores its settings in
+	 * 
+	 * @return String
+	 */
+	protected String getDialogSettingsSectionName()
+	{
+		return "XSL_DETAILS_DIALOG_SECTION"; //$NON-NLS-1$
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings()
+	{
+		IDialogSettings settings = XSLDebugUIPlugin.getDefault().getDialogSettings();
+		IDialogSettings section = settings.getSection(getDialogSettingsSectionName());
+		if (section == null)
+		{
+			section = settings.addNewSection(getDialogSettingsSectionName());
+		}
+		return section;
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent)
+	{
+		// create OK and Cancel buttons by default
+		createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.java
new file mode 100644
index 0000000..9c9c336
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class ProcessorMessages extends NLS
+{
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor.ProcessorMessages"; //$NON-NLS-1$
+
+	public static String ProcessorBlock_0;
+
+	public static String ProcessorBlock_1;
+
+	public static String ProcessorBlock_2;
+
+	public static String ProcessorBlock_4;
+
+	public static String ProcessorBlock_6;
+
+	public static String ProcessorBlock_7;
+
+	public static String ProcessorsComboBlock;
+	public static String ProcessorsComboBlock_0;
+	public static String ProcessorsComboBlock_1;
+	public static String SpecificProcessor;
+
+	public static String InputFileBlock_WORKSPACE_DIALOG_TITLE;
+
+	public static String InstalledProcessorsBlock_0;
+
+	public static String InstalledProcessorsBlock_1;
+
+	public static String InstalledProcessorsBlock_2;
+
+	public static String InstalledProcessorsBlock_3;
+
+	public static String InstalledProcessorsBlock_4;
+
+	public static String InstalledProcessorsBlock_5;
+
+	public static String InstalledProcessorsBlock_6;
+
+	public static String InstalledProcessorsBlock_7;
+
+	public static String InstalledProcessorsBlock_8;
+
+	public static String ProcessorDetailsDialog_Title;
+
+	public static String ProcessorDetailsDialog_installName;
+
+	public static String ProcessorDetailsDialog_installType;
+
+	public static String ProcessorDetailsDialog_installClasspath;
+
+	public static String AddProcessorDialog_1;
+
+	public static String AddProcessorDialog_7;
+
+	public static String AddProcessorDialog_Edit_Title;
+
+	public static String AddProcessorDialog_Add_Title;
+
+	public static String AddProcessorDialog_jars;
+
+	public static String AddProcessorDialog_attributes;
+
+	public static String AddProcessorDialog_processorName;
+
+	public static String AddProcessorDialog_processorType;
+
+	public static String ProcessorLibraryBlock_6;
+
+	public static String ProcessorLibraryBlock_AddButton;
+
+	public static String ProcessorLibraryBlock_RemoveButton;
+
+	public static String ProcessorLibraryBlock_AddWorkspaceButton;
+
+	public static String AddProcessorDialog_enterName;
+
+	public static String AddProcessorDialog_duplicateName;
+
+	public static String AddProcessorDialog_Processor_name_must_be_a_valid_file_name;
+
+	public static String ProcessorLibraryBlock_FileDialog_Title;
+
+	public static String ProcessorLibraryBlock_WorkspaceFileDialog_Title;
+
+	public static String ProcessorLibraryBlock_WorkspaceFileDialog_Message;
+
+	public static String ProcessorsUpdater;
+
+	public static String WorkingDirectoryBlock_1;
+
+	public static String WorkingDirectoryBlock_2;
+
+	public static String WorkingDirectoryBlock_3;
+
+	public static String WorkingDirectoryBlock_DIRECTORY_NOT_SPECIFIED;
+	public static String WorkingDirectoryBlock_DIRECTORY_DOES_NOT_EXIST;
+	public static String WorkingDirectoryBlock_DEFAULT_RADIO;
+	public static String WorkingDirectoryBlock_OTHER_RADIO;
+	public static String WorkingDirectoryBlock_DIALOG_MESSAGE;
+	public static String WorkingDirectoryBlock_WORKSPACE_DIALOG_MESSAGE;
+	public static String WorkingDirectoryBlock_VARIABLES_BUTTON;
+	public static String WorkingDirectoryBlock_FILE_SYSTEM_BUTTON;
+	public static String WorkingDirectoryBlock_WORKSPACE_BUTTON;
+	public static String WorkingDirectoryBlock_WORKSPACE_DIALOG_TITLE;
+
+	public static String URIResolverBlock_3;
+
+	public static String URIResolverBlock_5;
+
+	public static String URIResolverBlock_6;
+
+	public static String URIResolverBlock_8;
+
+	public static String URIResolverBlock_DIRECTORY_NOT_SPECIFIED;
+	public static String URIResolverBlock_DIRECTORY_DOES_NOT_EXIST;
+	public static String URIResolverBlock_DEFAULT_RADIO;
+	public static String URIResolverBlock_OTHER_RADIO;
+	public static String URIResolverBlock_DIALOG_MESSAGE;
+	public static String URIResolverBlock_WORKSPACE_DIALOG_MESSAGE;
+	public static String URIResolverBlock_VARIABLES_BUTTON;
+	public static String URIResolverBlock_FILE_SYSTEM_BUTTON;
+	public static String URIResolverBlock_WORKSPACE_BUTTON;
+	public static String URIResolverBlock_WORKSPACE_DIALOG_TITLE;
+
+	static
+	{
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, ProcessorMessages.class);
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.properties
new file mode 100644
index 0000000..d08fcc7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/ProcessorMessages.properties
@@ -0,0 +1,92 @@
+ProcessorBlock_0=XSLT Processor
+ProcessorBlock_1=Use processor from preferences
+ProcessorBlock_2=Change preferences...
+ProcessorBlock_4=Use specific processor
+ProcessorBlock_6=Processor:
+ProcessorBlock_7=Processor
+ProcessorsComboBlock=XSLT Processor
+ProcessorsComboBlock_0=No XSLT processors defined in workspace
+ProcessorsComboBlock_1=&Installed processors...
+SpecificProcessor=Alternate Processor:
+
+URIResolverBlock_DIRECTORY_NOT_SPECIFIED=URI Resolver directory not specified
+URIResolverBlock_DIRECTORY_DOES_NOT_EXIST=URI Resolver directory does not exist
+URIResolverBlock_DEFAULT_RADIO=Default (resolve URIs relative to the working directory)
+URIResolverBlock_OTHER_RADIO=Other
+URIResolverBlock_DIALOG_MESSAGE=Select an external URI resolver directory
+URIResolverBlock_WORKSPACE_DIALOG_MESSAGE=Select a URI resolver directory in the workspace
+URIResolverBlock_VARIABLES_BUTTON=Variables...
+URIResolverBlock_FILE_SYSTEM_BUTTON=File System...
+URIResolverBlock_WORKSPACE_BUTTON=Workspace...
+URIResolverBlock_WORKSPACE_DIALOG_TITLE=Folder Selection
+
+
+URIResolverBlock_0=Workspace
+URIResolverBlock_1=File System
+URIResolverBlock_17=Variables
+URIResolverBlock_7=Select a base directory for the launch configuration
+URIResolverBlock_4=Select a workspace relative base directory
+URIResolverBlock_19=Other:
+URIResolverBlock_18=Default
+URIResolverBlock_12=Base directory for resolving URIs
+URIResolverBlock_10=Base directory does not exist
+URIResolverBlock_20=Base directory not specified
+URIResolverBlock_3=URI Resolver
+URIResolverBlock_5=Relative to working directory
+URIResolverBlock_6=Relative to (1st) stylesheet
+URIResolverBlock_8=Specific Location:
+URIResolverBlock_Working_Directory_8=URI Resolver
+URIResolverBlock_WORKSPACE_DIALOG_TITLE=Folder Selection
+
+ProcessorDetailsDialog_Title=Built-in XSLT Processor
+ProcessorDetailsDialog_installName=Name:
+ProcessorDetailsDialog_installType=Type:
+ProcessorDetailsDialog_installClasspath=Libraries:
+
+AddProcessorDialog_1=Supported versions:
+AddProcessorDialog_7=Processor must support at least one XSLT version
+AddProcessorDialog_Edit_Title=Edit Processor
+AddProcessorDialog_Add_Title=Add Processor
+AddProcessorDialog_processorName=Processor Name:
+AddProcessorDialog_processorType=Processor Type:
+AddProcessorDialog_jars=Libraries:
+AddProcessorDialog_attributes=Attributes:
+AddProcessorDialog_enterName=A name must be entered for this processor
+AddProcessorDialog_duplicateName=The name has already been used
+AddProcessorDialog_Processor_name_must_be_a_valid_file_name=Processor name must be a valid file name
+InstalledProcessorsBlock_0=Installed Java XSLT Processors:
+InstalledProcessorsBlock_1=Name
+InstalledProcessorsBlock_2=Type
+InstalledProcessorsBlock_3=XSLT Versions
+InstalledProcessorsBlock_4=Debugger
+InstalledProcessorsBlock_5=Add
+InstalledProcessorsBlock_6=Edit
+InstalledProcessorsBlock_7=Remove
+InstalledProcessorsBlock_8=None
+
+ProcessorLibraryBlock_6=One or more jar files must be specified
+ProcessorLibraryBlock_AddButton=Add External JARs
+ProcessorLibraryBlock_AddWorkspaceButton=Add Workspace JARs
+ProcessorLibraryBlock_RemoveButton=Remove
+ProcessorLibraryBlock_FileDialog_Title=External JARs
+ProcessorLibraryBlock_WorkspaceFileDialog_Title=Workspace JARs
+ProcessorLibraryBlock_WorkspaceFileDialog_Message=Select the JARs that make up the XSLT processor
+
+ProcessorsUpdater=Save processor settings
+
+
+WorkingDirectoryBlock_1=Default:
+WorkingDirectoryBlock_2=Other:
+WorkingDirectoryBlock_3=Working Directory
+WorkingDirectoryBlock_DIRECTORY_NOT_SPECIFIED=Working directory not specified
+WorkingDirectoryBlock_DIRECTORY_DOES_NOT_EXIST=Working directory does not exist
+WorkingDirectoryBlock_DEFAULT_RADIO=Workspace default
+WorkingDirectoryBlock_OTHER_RADIO=Other
+WorkingDirectoryBlock_DIALOG_MESSAGE=Select an external working directory
+WorkingDirectoryBlock_WORKSPACE_DIALOG_MESSAGE=Select a working directory in the workspace
+WorkingDirectoryBlock_VARIABLES_BUTTON=Variables...
+WorkingDirectoryBlock_FILE_SYSTEM_BUTTON=File System...
+WorkingDirectoryBlock_WORKSPACE_BUTTON=Workspace...
+WorkingDirectoryBlock_WORKSPACE_DIALOG_TITLE=Folder Selection
+
+
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/XSLProcessorTab2.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/XSLProcessorTab2.java
new file mode 100644
index 0000000..2bab50e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/XSLProcessorTab2.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *     David Carver - bug 223557 - Added images contributed by Holger Voormann
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.tabs.processor;
+
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.wst.xsl.internal.debug.ui.XSLLaunchConfigurationTab;
+import org.eclipse.wst.xsl.jaxp.debug.ui.internal.JAXPDebugUIPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class XSLProcessorTab2 extends XSLLaunchConfigurationTab
+{
+	private final ProcessorBlock processorBlock;
+	private final AttributesBlock attributesBlock;
+	private final OutputPropertiesBlock outputPropertiesBlock;
+	private Image image;
+
+	public XSLProcessorTab2()
+	{
+		attributesBlock = new AttributesBlock();
+		outputPropertiesBlock = new OutputPropertiesBlock();
+		processorBlock = new ProcessorBlock();
+		
+		setBlocks(new ILaunchConfigurationTab[]
+		{ processorBlock , attributesBlock, outputPropertiesBlock });
+	}
+
+	@Override
+	public void createControl(Composite parent)
+	{
+		super.createControl(parent);
+		Composite comp = (Composite) getControl();
+
+		processorBlock.createControl(comp);
+		
+		TabFolder tabFolder = new TabFolder(comp,SWT.NONE);
+		tabFolder.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true));
+
+		outputPropertiesBlock.createControl(tabFolder);		
+		attributesBlock.createControl(tabFolder);		
+	}
+
+	@Override
+	public void performApply(ILaunchConfigurationWorkingCopy configuration)
+	{
+		super.performApply(configuration);
+		IProcessorInvoker invoker = JAXPRuntime.getProcessorInvokers()[0];
+		configuration.setAttribute(JAXPLaunchConfigurationConstants.INVOKER_DESCRIPTOR, invoker.getId());
+	}
+
+	public String getName()
+	{
+		return Messages.getString("XSLProcessorTab.0"); //$NON-NLS-1$
+	}
+	
+	@Override
+	public String getId()
+	{
+		return "org.eclipse.wst.xsl.debug.ui.jaxp.tabs.processor";
+	}
+
+	@Override
+	public Image getImage()
+	{
+		if (image == null)
+		{
+			ImageDescriptor id = JAXPDebugUIPlugin.imageDescriptorFromPlugin(JAXPDebugUIPlugin.PLUGIN_ID, "icons/xslt_processor.gif");
+			image = id.createImage();
+		}
+		return image;
+	}
+
+	@Override
+	public void dispose()
+	{
+		if (image != null)
+			image.dispose();
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/messages.properties
new file mode 100644
index 0000000..1cebef7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/tabs/processor/messages.properties
@@ -0,0 +1,11 @@
+AttributesBlock.1=Change Preferences...
+AttributesBlock.10=type
+AttributesBlock.11=value
+AttributesBlock.12=value
+AttributesBlock.16=Processor Attributes
+AttributesBlock.3=Use specific attributes
+AttributesBlock.4=Attribute
+AttributesBlock.5=Type
+AttributesBlock.6=Value
+AttributesBlock.9=name
+XSLProcessorTab.0=Processor
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/views/ResultView.java b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/views/ResultView.java
new file mode 100644
index 0000000..3927501
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug.ui/src/org/eclipse/wst/xsl/jaxp/debug/ui/internal/views/ResultView.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.ui.internal.views;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration;
+import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
+import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider;
+import org.eclipse.wst.xml.core.internal.provisional.contenttype.ContentTypeIdForXML;
+import org.eclipse.wst.xsl.launching.model.XSLDebugTarget;
+import org.eclipse.wst.xsl.ui.internal.StructuredTextViewerConfigurationXSL;
+
+/**
+ * TODO handle multiple concurrent debugging processes (and bring the current results to the top depending on which selected in Debug view)
+ * TODO handle different output methods - xml, html, text - will need a call back from the debugger to tell us this (output method defined in XSL stylesheet)
+ * 
+ * @author Doug Satchwell
+ */
+public class ResultView extends ViewPart implements IDebugEventSetListener
+{
+	private SourceViewer sv;
+
+	@Override
+	public void dispose()
+	{
+		DebugPlugin.getDefault().removeDebugEventListener(this);
+		super.dispose();
+	}
+
+	@Override
+	public void createPartControl(Composite parent)
+	{
+		this.sv = createViewer(parent);
+		
+		// handle any launches already added
+		IDebugTarget[] targets = DebugPlugin.getDefault().getLaunchManager().getDebugTargets();
+		for (IDebugTarget debugTarget : targets)
+		{
+			if (debugTarget instanceof XSLDebugTarget)
+			{
+				handleDebugTarget((XSLDebugTarget)debugTarget);
+			}			
+		}
+		// listen to further launches
+		DebugPlugin.getDefault().addDebugEventListener(this);
+	}
+
+	private SourceViewer createViewer(Composite parent)
+	{
+		SourceViewerConfiguration sourceViewerConfiguration = new StructuredTextViewerConfiguration() {
+			StructuredTextViewerConfiguration baseConfiguration = new StructuredTextViewerConfigurationXSL();
+
+			public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
+				return baseConfiguration.getConfiguredContentTypes(sourceViewer);
+			}
+
+			public LineStyleProvider[] getLineStyleProviders(ISourceViewer sourceViewer, String partitionType) {
+				return baseConfiguration.getLineStyleProviders(sourceViewer, partitionType);
+			}
+		};
+		SourceViewer viewer = new StructuredTextViewer(parent, null, null, false, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+		((StructuredTextViewer) viewer).getTextWidget().setFont(JFaceResources.getFont("org.eclipse.wst.sse.ui.textfont")); //$NON-NLS-1$
+		IStructuredModel scratchModel = StructuredModelManager.getModelManager().createUnManagedStructuredModelFor(ContentTypeIdForXML.ContentTypeID_XML);
+		
+		IDocument document = scratchModel.getStructuredDocument();
+		viewer.configure(sourceViewerConfiguration);
+		viewer.setDocument(document);
+		viewer.setEditable(false);
+		return viewer;
+	}
+
+	@Override
+	public void setFocus()
+	{}
+
+	public void handleDebugEvents(DebugEvent[] events)
+	{
+		for (DebugEvent debugEvent : events)
+		{
+			if (debugEvent.getKind() == DebugEvent.CREATE && debugEvent.getSource() instanceof XSLDebugTarget)
+			{
+				handleDebugTarget((XSLDebugTarget)debugEvent.getSource());
+			}
+		}
+	}
+	
+	private void handleDebugTarget(XSLDebugTarget xdt)
+	{
+		// first, clear the viewer
+		sv.getDocument().set("");
+		
+		final Reader reader = xdt.getGenerateReader();
+		IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService)getSite().getService(IWorkbenchSiteProgressService.class);
+		service.schedule(new Job("Result view job"){
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				IStatus status = Status.OK_STATUS;
+				try
+				{
+					char[] c = new char[8192]; // this is the default BufferedWriter size, so we will usually get chunks of this size
+					int size;
+					while((size = reader.read(c)) != -1)
+					{
+						writeString(new String(c,0,size));
+					}
+				}
+				catch (IOException e)
+				{
+					// ignore
+				}
+				finally
+				{
+					monitor.done();
+				}
+				return status;
+			}
+			
+			private void writeString(final String s)
+			{
+				getSite().getShell().getDisplay().syncExec(new Runnable(){
+
+					public void run()
+					{
+						sv.getDocument().set(sv.getDocument().get()+s);
+					}
+				});
+			}
+		});
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/.classpath b/bundles/org.eclipse.wst.xsl.jaxp.debug/.classpath
new file mode 100644
index 0000000..2fbb7a2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/.project b/bundles/org.eclipse.wst.xsl.jaxp.debug/.project
new file mode 100644
index 0000000..96358c2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.wst.xsl.jaxp.debug</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+	</natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.wst.xsl.jaxp.debug/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..04cdef3
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Mon Aug 04 15:54:18 BST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.xsl.jaxp.debug/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..47e43a4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: XSL JAXP Debugger (Incubating)
+Bundle-SymbolicName: org.eclipse.wst.xsl.jaxp.debug
+Bundle-Version: 0.5.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Require-Bundle: org.apache.commons.logging;bundle-version="1.0.4";visibility:=reexport
+Export-Package: org.eclipse.wst.xsl.jaxp.debug.debugger,
+ org.eclipse.wst.xsl.jaxp.debug.invoker
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/about.html b/bundles/org.eclipse.wst.xsl.jaxp.debug/about.html
new file mode 100644
index 0000000..ed30003
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/about.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+
+<BODY lang="EN-US">
+
+<H3>About This Content</H3>
+
+<P>August, 2008</P>
+
+<H3>License</H3>
+
+<P>The Eclipse Foundation makes available all content in this plug-in 
+("Content"). Unless otherwise indicated below, the Content is provided to you 
+under the terms and conditions of the Eclipse Public License Version 1.0 
+("EPL"). A copy of the EPL is available at
+<A href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/org/documents/epl-v10.php</A>. 
+For purposes of the EPL, "Program" will mean the Content.</P>
+
+<P>If you did not receive this Content directly from the Eclipse Foundation, the 
+Content is being redistributed by another party ("Redistributor") and different 
+terms and conditions may apply to your use of any object code in the Content. 
+Check the Redistributor’s license that was provided with the Content. If no such 
+license exists, contact the Redistributor. Unless otherwise indicated below, the 
+terms and conditions of the EPL still apply to any source code in the Content 
+and such source code may be obtained at
+<A href="http://www.eclipse.org/">http://www.eclipse.org/</A>.</P>
+
+</BODY>
+</HTML>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/build.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug/build.properties
new file mode 100644
index 0000000..17daa5b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               about.html
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/log4j.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/log4j.properties
new file mode 100644
index 0000000..09bb551
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/log4j.properties
@@ -0,0 +1,10 @@
+# Set root logger level to DEBUG and its appenders are A1 and A2
+log4j.rootLogger=DEBUG, A2
+
+# A2 is set to be a ConsoleAppender
+log4j.appender.A2=org.apache.log4j.ConsoleAppender
+
+# A2 uses PatternLayout.
+log4j.appender.A2.layout=org.apache.log4j.PatternLayout
+log4j.appender.A2.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%t] %c{1} %x - %m%n
+
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/AbstractDebugger.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/AbstractDebugger.java
new file mode 100644
index 0000000..c099904
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/AbstractDebugger.java
@@ -0,0 +1,406 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Stack;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.TransformationException;
+
+/**
+ * An implementation of <code>IXSLDebugger</code>.
+ * 
+ * This class can be subclassed in order to provide debugging for a particular XSLT processor.
+ * 
+ * @author Doug Satchwell
+ */
+public abstract class AbstractDebugger implements IXSLDebugger
+{
+	private static final Log log = LogFactory.getLog(AbstractDebugger.class);
+
+	private static final int ACTION_DO_NOTHING = 0;
+	private static final int ACTION_STOP = 1;
+	private static final int ACTION_QUIT = 2;
+	private static final int ACTION_SUSPEND = 3;
+	private static final int ACTION_RESUME = 4;
+	private static final int ACTION_STEP_INTO = 5;
+	private static final int ACTION_STEP_OVER = 6;
+	private static final int ACTION_STEP_RETURN = 7;
+
+	private static final String EVENT_STARTED = "started"; //$NON-NLS-1$
+	private static final String EVENT_STOPPED = "stopped"; //$NON-NLS-1$
+	private static final String EVENT_SUSPENDED = "suspended client"; //$NON-NLS-1$
+	private static final String EVENT_SUSPENDED_STEP = "suspended step"; //$NON-NLS-1$
+	private static final String EVENT_RESUMED = "resumed client"; //$NON-NLS-1$
+	private static final String EVENT_RESUMED_STEP = "resumed step"; //$NON-NLS-1$
+
+	private IProcessorInvoker invoker;
+	private int action;
+	private Writer eventWriter;
+	private Writer generatedWriter;
+	private final Set breakpoints = Collections.synchronizedSet(new HashSet());
+	private final Stack stack = new Stack();
+	private StyleFrame stepOverFrame;
+	private BreakPoint breakpoint;
+	private URL sourceURL;
+	private Result result;
+
+	private int stepOverStackSize;
+
+	public void setInvoker(IProcessorInvoker invoker)
+	{
+		this.invoker = invoker;
+	}
+
+	public void setEventWriter(Writer writer)
+	{
+		eventWriter = writer;
+	}
+
+	public void setGeneratedWriter(Writer writer)
+	{
+		this.generatedWriter = writer;
+	}
+
+	public void setSource(URL sourceURL)
+	{
+		this.sourceURL = sourceURL;
+	}
+
+	public void setTarget(final Writer writer)
+	{
+		result = new StreamResult(new Writer(){
+			public void write(char[] cbuf, int off, int len) throws IOException
+			{
+				writer.write(cbuf, off, len);
+				generatedWriter.write(cbuf,off,len);
+			}
+
+			public void close() throws IOException
+			{
+				writer.close();
+				generatedWriter.close();
+			}
+
+			public void flush() throws IOException
+			{
+				writer.flush();
+				generatedWriter.flush();
+			}
+		});
+	}
+
+	public void run()
+	{
+		if (action != ACTION_QUIT)
+		{
+			debuggerStarted();
+			try
+			{
+				invoker.transform(sourceURL, result);
+			}
+			catch (TransformationException e)
+			{
+				log.error("Transform failed", e); //$NON-NLS-1$
+			}
+			debuggerStopped();
+		}
+	}
+
+	public synchronized void suspend()
+	{
+		action = ACTION_SUSPEND;
+		notify();
+	}
+
+	public synchronized void resume()
+	{
+		action = ACTION_RESUME;
+		notify();
+	}
+
+	public synchronized void stepInto()
+	{
+		action = ACTION_STEP_INTO;
+		notify();
+	}
+
+	public synchronized void stepOver()
+	{
+		action = ACTION_STEP_OVER;
+		stepOverFrame = peekStyleFrame();
+		stepOverStackSize = stack.size();
+		notify();
+	}
+
+	public synchronized void stepReturn()
+	{
+		action = ACTION_STEP_RETURN;
+		stepOverStackSize = stack.size();
+		notify();
+	}
+
+	public synchronized void quit()
+	{
+		action = ACTION_QUIT;
+	}
+
+	public String stack()
+	{
+		StringBuffer sb = new StringBuffer();
+		synchronized (stack)
+		{
+			for (Iterator iter = stack.iterator(); iter.hasNext();)
+			{
+				StyleFrame frame = (StyleFrame) iter.next();
+				sb.append(frame.toString());
+				for (Iterator iter2 = frame.getVariableStack().iterator(); iter2.hasNext();)
+				{
+					sb.append("|"); //$NON-NLS-1$
+					Variable v = (Variable) iter2.next();
+					sb.append(v.getId());
+				}
+				if (iter.hasNext())
+					sb.append("$$$"); //$NON-NLS-1$
+			}
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * Check whether the debugger has been stopped and perform the appropriate action if so.
+	 */
+	public synchronized void checkStopped()
+	{
+		if (action == ACTION_QUIT)
+			debuggerQuit();
+		else if (action == ACTION_STOP)
+			debuggerStopped();
+	}
+
+	/**
+	 * Check whether the debugger is currently suspended or stepping at the given breakpoint and style frame, 
+	 * and perform the appropriate action if so.
+	 * 
+	 * @param styleFrame the styleframe to check
+	 * @param breakpoint the current location
+	 */
+	public synchronized void checkSuspended(StyleFrame styleFrame, BreakPoint breakpoint)
+	{
+		// do not suspend unless the line actually changed
+		if (breakpoint.equals(this.breakpoint))
+			return;
+		int stackSize;
+		synchronized (stack)
+		{
+			stackSize = stack.size();
+		}
+		// do not suspend if there is nothing in the stack
+		if (stackSize == 0)
+			return;
+		switch (action)
+		{
+			case ACTION_SUSPEND:
+				debuggerSuspendedClient(breakpoint);
+				break;
+			case ACTION_STEP_OVER:
+				// suspend if we are in the same template or we are moving up the stack
+				if (styleFrame.equals(stepOverFrame) || stackSize < stepOverStackSize)
+					debuggerSuspendedStep(breakpoint);
+				break;
+			case ACTION_STEP_INTO:
+				debuggerSuspendedStep(breakpoint);
+				break;
+			case ACTION_STEP_RETURN:
+				// suspend if we moved up the stack
+				if (stackSize < stepOverStackSize)
+					debuggerSuspendedStep(breakpoint);
+				break;
+			default:
+				checkBreakpoint(breakpoint);
+		}
+	}
+
+	private synchronized void checkBreakpoint(BreakPoint breakpoint)
+	{
+		if (isBreakpoint(breakpoint))
+			debuggerSuspendedBreakpoint(breakpoint);
+	}
+
+	/**
+	 * Called when the next transform in the pipeline has begun.
+	 */
+	public synchronized void debuggerTransformStarted()
+	{
+		stack.clear();
+	}
+
+	protected synchronized void debuggerStarted()
+	{
+		action = ACTION_DO_NOTHING;
+		sendEvent(EVENT_STARTED);
+	}
+
+	protected synchronized void debuggerStopped()
+	{
+		action = ACTION_DO_NOTHING;
+		sendEvent(EVENT_STOPPED);
+	}
+
+	private synchronized void debuggerQuit()
+	{
+		// just wait here indefinitely until the JVM exists, just to make sure
+		// we don't send any further events
+		try
+		{
+			wait();
+		}
+		catch (InterruptedException e)
+		{
+		}
+	}
+
+	private synchronized void debuggerSuspendedBreakpoint(BreakPoint breakpoint)
+	{
+		sendEvent("suspended breakpoint " + breakpoint); //$NON-NLS-1$
+		debuggerSuspended(breakpoint);
+	}
+
+	private synchronized void debuggerSuspendedStep(BreakPoint breakpoint)
+	{
+		sendEvent(EVENT_SUSPENDED_STEP);
+		debuggerSuspended(breakpoint);
+	}
+
+	private synchronized void debuggerSuspendedClient(BreakPoint breakpoint)
+	{
+		sendEvent(EVENT_SUSPENDED);
+		debuggerSuspended(breakpoint);
+	}
+
+	public synchronized void debuggerSuspended(BreakPoint breakpoint)
+	{
+		this.breakpoint = breakpoint;
+		do
+		{
+			try
+			{
+				wait();
+			}
+			catch (InterruptedException e)
+			{
+			}
+		}
+		while (action != ACTION_RESUME && action != ACTION_STEP_INTO && action != ACTION_STEP_OVER && action != ACTION_STEP_RETURN && action != ACTION_STOP);
+		debuggerResumed();
+	}
+
+	private synchronized void debuggerResumed()
+	{
+		if (action == ACTION_STEP_INTO || action == ACTION_STEP_OVER || action == ACTION_STEP_RETURN)
+			sendEvent(EVENT_RESUMED_STEP);
+		else
+			sendEvent(EVENT_RESUMED);
+	}
+
+	private synchronized void sendEvent(String event)
+	{
+		try
+		{
+			log.info("Sending event: " + event+" eventWriter="+eventWriter);  //$NON-NLS-1$//$NON-NLS-2$
+			eventWriter.write(event + "\n"); //$NON-NLS-1$
+			eventWriter.flush();
+		}
+		catch (IOException e)
+		{
+			log.error("Error sending event", e); //$NON-NLS-1$
+		}
+	}
+
+	public void addBreakpoint(BreakPoint breakpoint)
+	{
+		log.info("Adding breakpoint: " + breakpoint); //$NON-NLS-1$
+		breakpoints.add(breakpoint);
+	}
+
+	public void removeBreakpoint(BreakPoint breakpoint)
+	{
+		log.info("Removing breakpoint: " + breakpoint); //$NON-NLS-1$
+		breakpoints.remove(breakpoint);
+	}
+
+	private boolean isBreakpoint(BreakPoint breakpoint)
+	{
+		// do not check for breakpoint unless the line or filename actually changed
+		if (breakpoint.equals(this.breakpoint))
+			return false;
+		this.breakpoint = null;
+		return breakpoints.contains(breakpoint);
+	}
+	
+	/**
+	 * Pop a style frame from the stack.
+	 * 
+	 * @return the popped style frame
+	 */
+	public StyleFrame popStyleFrame()
+	{
+		synchronized (stack)
+		{
+			StyleFrame styleFrame = (StyleFrame) stack.pop();
+			if (styleFrame.getParent() != null)
+				styleFrame.getParent().removeChild(styleFrame);
+			log.trace("Popped frame: " + styleFrame + " (size after pop=" + stack.size() + ")");   //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+			return styleFrame;
+		}
+	}
+
+	/**
+	 * Push a style frame onto the stack.
+	 * 
+	 * @param styleFrame
+	 */
+	public void pushStyleFrame(StyleFrame styleFrame)
+	{
+		synchronized (stack)
+		{
+			stack.push(styleFrame);
+			log.trace("Pushed frame: " + styleFrame + " (size after push=" + stack.size() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+	}
+
+	/**
+	 * Peek a style frame from the stack.
+	 * 
+	 * @return the peeked style frame
+	 */
+	public StyleFrame peekStyleFrame()
+	{
+		synchronized (stack)
+		{
+			if (stack.size() > 0)
+				return (StyleFrame) stack.peek();
+			return null;
+		}
+	}	
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/BreakPoint.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/BreakPoint.java
new file mode 100644
index 0000000..0b6000d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/BreakPoint.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+/**
+ * A line number in a file.
+ * 
+ * @author Doug Satchwell
+ */
+public class BreakPoint
+{
+	private String file;
+	private final int line;
+
+	/**
+	 * Construct a new instance of this for the given file and line number.
+	 * 
+	 * @param file the file path
+	 * @param line the line number
+	 */
+	public BreakPoint(String file, int line)
+	{
+		this.file = file;
+		this.line = line;
+	}
+
+	/**
+	 * Get the file location.
+	 * 
+	 * @return the file
+	 */
+	public String getFile()
+	{
+		return file;
+	}
+
+	/**
+	 * Get the line number
+	 * 
+	 * @return the line number
+	 */
+	public int getLine()
+	{
+		return line;
+	}
+
+	public int hashCode()
+	{
+		int hash = 3 * file.hashCode() + 5 * line;
+		return hash;
+	}
+
+	public boolean equals(Object obj)
+	{
+		if (obj == this)
+			return true;
+		if (obj instanceof BreakPoint)
+		{
+			BreakPoint b = (BreakPoint) obj;
+			return b.file.equals(file) && b.line == line;
+		}
+		return false;
+	}
+
+	public String toString()
+	{
+		return file + " " + line; //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugConstants.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugConstants.java
new file mode 100644
index 0000000..2383a29
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugConstants.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+/**
+ * Constants used by the debugger.
+ * 
+ * <p>
+ * Note that class is loaded both on the Eclipse classpath and the 
+ * launched transformation process, such that they can use exactly the same constants
+ * for communication.
+ * </p>
+ * 
+ * @author Doug Satchwell
+ */
+public class DebugConstants
+{
+	/**
+	 * The constant used to notify the debugger to start.
+	 */
+	public static final String REQUEST_START = "start"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify addition of a breakpoint.
+	 */
+	public static final String REQUEST_ADD_BREAKPOINT = "add"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify removal of a breakpoint.
+	 */
+	public static final String REQUEST_REMOVE_BREAKPOINT = "remove"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify step into.
+	 */
+	public static final String REQUEST_STEP_INTO = "step into"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify step over.
+	 */
+	public static final String REQUEST_STEP_OVER = "step over"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify suspension.
+	 */
+	public static final String REQUEST_SUSPEND = "suspend"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify resume.
+	 */
+	public static final String REQUEST_RESUME = "resume"; //$NON-NLS-1$
+	/**
+	 * The constant used to request the stack.
+	 */
+	public static final String REQUEST_STACK = "stack"; //$NON-NLS-1$
+	/**
+	 * The constant used to request a variable.
+	 */
+	public static final String REQUEST_VARIABLE = "var"; //$NON-NLS-1$
+	/**
+	 * The constant used to request a variable value.
+	 */
+	public static final String REQUEST_VALUE = "value"; //$NON-NLS-1$
+	/**
+	 * The constant used to signify step return.
+	 */
+	public static final String REQUEST_STEP_RETURN = "step return"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugRunner.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugRunner.java
new file mode 100644
index 0000000..1be1ce2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/DebugRunner.java
@@ -0,0 +1,400 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.PipelineDefinition;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.TransformationException;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.JAXPSAXProcessorInvoker;
+import org.xml.sax.InputSource;
+
+/**
+ * The entry point to the debug process which is responsible for configuring a debugger 
+ * and then communicating with the Eclipse process via sockets using a common set of commands.
+ * 
+ * <ul>
+ * <li>instantiates an implementation of <code>IXSLDebugger</code>
+ * <li>configures the debugger with the transformation pipeline
+ * <li>starts the debugger in a separate thread
+ * <li>the main thread is then used to listen to incoming requests and call the appropriate debugger methods
+ * </ul>
+ * 
+ * @author Doug Satchwell
+ */
+public class DebugRunner
+{
+	private static final Log log = LogFactory.getLog(DebugRunner.class);
+
+	private final BufferedReader requestIn;
+	private final Writer requestOut;
+	private final Writer eventOut;
+	private final Writer generatedStream;
+	private Socket eventSocket;
+	private Socket requestSocket;
+	private Socket generateSocket;
+
+	/**
+	 * Create a new instance of this using the supplied readers and writers.
+	 * 
+	 * @param requestIn the reader for reading incoming requests
+	 * @param requestOut the writer for acknowledging requests
+	 * @param eventOut the writer for publishing debug events
+	 */
+	public DebugRunner(BufferedReader requestIn, PrintWriter requestOut, PrintWriter eventOut, PrintWriter generatedStream)
+	{
+		this.requestOut = requestOut;
+		this.requestIn = requestIn;
+		this.eventOut = eventOut;
+		this.generatedStream = generatedStream;
+	}
+
+	/**
+	 * Create a new instance of this given a request port and an event port.
+	 * 
+	 * @param requestPort the port to listen to requests and send acknowledgements
+	 * @param eventPort the port for publishing debug events
+	 * @throws IOException if there was a problem opening a socket
+	 */
+	public DebugRunner(int requestPort, int eventPort, int generatePort) throws IOException
+	{
+		requestSocket = getSocket(requestPort);
+		eventSocket = getSocket(eventPort);
+		generateSocket = getSocket(generatePort);
+		requestIn = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));
+		requestOut = new PrintWriter(requestSocket.getOutputStream(), true);
+		eventOut = new PrintWriter(eventSocket.getOutputStream(), true);
+		generatedStream = new BufferedWriter(new PrintWriter(generateSocket.getOutputStream(), true));
+	}
+
+	/**
+	 * This method starts the given debugger in its own thread, and blocks while waiting 
+	 * for incoming requests from the request port, until there are no more requests.
+	 * 
+	 * @param debugger the debugger to start in a thread
+	 * @throws TransformationException if a problem occurred while transforming
+	 * @throws IOException 
+	 */
+	public void loop(IXSLDebugger debugger) throws TransformationException, IOException
+	{
+		debugger.setEventWriter(eventOut);
+		debugger.setGeneratedWriter(generatedStream);
+		String inputLine, response;
+		// signal we are ready to receive requests
+		eventOut.write("ready\n"); //$NON-NLS-1$
+		eventOut.flush();
+		log.debug("entering loop"); //$NON-NLS-1$
+		try
+		{
+			while ((inputLine = requestIn.readLine()) != null)
+			{
+				response = inputLine;
+				log.debug("REQUEST:" + inputLine); //$NON-NLS-1$
+				Thread debuggerThread = null;
+				if (DebugConstants.REQUEST_START.equals(inputLine))
+				{
+					debuggerThread = new Thread(debugger, "debugger"); //$NON-NLS-1$
+					debuggerThread.start();
+				}
+				/*
+				 * else if (REQUEST_QUIT.equals(inputLine)) { }
+				 */
+				else if (DebugConstants.REQUEST_STEP_INTO.equals(inputLine))
+				{
+					debugger.stepInto();
+				}
+				else if (DebugConstants.REQUEST_STEP_OVER.equals(inputLine))
+				{
+					debugger.stepOver();
+				}
+				else if (DebugConstants.REQUEST_STEP_RETURN.equals(inputLine))
+				{
+					debugger.stepReturn();
+				}
+				else if (DebugConstants.REQUEST_SUSPEND.equals(inputLine))
+				{
+					debugger.suspend();
+				}
+				else if (DebugConstants.REQUEST_RESUME.equals(inputLine))
+				{
+					debugger.resume();
+				}
+				else if (DebugConstants.REQUEST_STACK.equals(inputLine))
+				{
+					response = debugger.stack();
+				}
+				else if (inputLine.startsWith(DebugConstants.REQUEST_VARIABLE))
+				{
+					String data = inputLine.substring(DebugConstants.REQUEST_VARIABLE.length() + 1);
+					int id = Integer.parseInt(data);
+					Variable var = debugger.getVariable(id);
+					log.debug("var "+id+" = "+var); //$NON-NLS-1$ //$NON-NLS-2$
+					response = var.getScope() + "&" + var.getName(); //$NON-NLS-1$
+				}
+				else if (inputLine.startsWith(DebugConstants.REQUEST_VALUE))
+				{
+					String data = inputLine.substring(DebugConstants.REQUEST_VALUE.length() + 1);
+					int id = Integer.parseInt(data);
+					Variable var = debugger.getVariable(id);
+					response =  var.getType() + "&" + var.getValueFirstLine(); //$NON-NLS-1$
+				}
+				else if (inputLine.startsWith(DebugConstants.REQUEST_ADD_BREAKPOINT))
+				{
+					int index = inputLine.lastIndexOf(' ');
+					String file = inputLine.substring(DebugConstants.REQUEST_ADD_BREAKPOINT.length() + 1, index);
+					String line = inputLine.substring(index + 1);
+					BreakPoint breakpoint = new BreakPoint(file, Integer.parseInt(line));
+					debugger.addBreakpoint(breakpoint);
+				}
+				else if (inputLine.startsWith(DebugConstants.REQUEST_REMOVE_BREAKPOINT))
+				{
+					int index = inputLine.lastIndexOf(' ');
+					String file = inputLine.substring(DebugConstants.REQUEST_REMOVE_BREAKPOINT.length() + 1, index);
+					String line = inputLine.substring(index + 1);
+					BreakPoint breakpoint = new BreakPoint(file, Integer.parseInt(line));
+					debugger.removeBreakpoint(breakpoint);
+				}
+				else
+				{
+					response = "What?"; //$NON-NLS-1$
+				}
+				// confirm request
+				log.debug("RESPONSE:" + response); //$NON-NLS-1$
+				requestOut.write(response + "\n"); //$NON-NLS-1$
+				requestOut.flush();
+
+				/*
+				 * if (REQUEST_QUIT.equals(inputLine)) { waitForFinish(debuggerThread); break; }
+				 */
+			}
+		}
+		catch (Exception e)
+		{
+			throw new TransformationException(e.getMessage(), e);
+		}
+		log.debug("exited loop"); //$NON-NLS-1$
+		eventOut.write("terminated\n"); //$NON-NLS-1$
+		eventOut.flush();
+	}
+
+	/**
+	 * Dispose of this - close all open sockets.
+	 * @throws IOException 
+	 */
+	public void dispose() throws IOException
+	{
+		if (requestIn != null)
+		{
+			try
+			{
+				requestIn.close();
+			}
+			catch (IOException e)
+			{
+				log.error("Could not close request input stream", e); //$NON-NLS-1$
+			}
+		}
+		if (requestOut != null)
+		{
+			requestOut.close();
+		}
+		if (eventOut != null)
+		{
+			eventOut.close();
+		}
+		if (requestSocket != null)
+		{
+			try
+			{
+				requestSocket.close();
+			}
+			catch (IOException e)
+			{
+				log.error("Could not close request socket", e); //$NON-NLS-1$
+			}
+		}
+		if (eventSocket != null)
+		{
+			try
+			{
+				eventSocket.close();
+			}
+			catch (IOException e)
+			{
+				log.error("Could not close event socket", e); //$NON-NLS-1$
+			}
+		}
+	}
+
+	private static Socket getSocket(int port) throws IOException
+	{
+		InetAddress localhost = InetAddress.getByName("localhost"); //$NON-NLS-1$
+		ServerSocket serverSocket = new ServerSocket(port, 5, localhost);
+		Socket clientSocket = serverSocket.accept();
+		serverSocket.close();
+		return clientSocket;
+	}
+
+	/**
+	 * Expected arguments:
+	 * 
+	 * <ol>
+	 * <li>the class name of the invoker
+	 * <li>the file name of the XML launch configuration file
+	 * <li>the URL of the source document
+	 * <li>the file of the output document
+	 * <li>not used (anything)
+	 * <li>the class name of the <code>IXSLDebugger</code> instance
+	 * <li>the port used for requests
+	 * <li>the port used for debug events
+	 * <li>the port used for generate events
+	 * </ol>
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args)
+	{
+		log.info("javax.xml.transform.TransformerFactory=" + System.getProperty("javax.xml.transform.TransformerFactory"));  //$NON-NLS-1$//$NON-NLS-2$
+		log.info("java.endorsed.dirs=" + System.getProperty("java.endorsed.dirs"));  //$NON-NLS-1$//$NON-NLS-2$
+
+		String invokerClassName = args[0];
+		File launchFile = new File(args[1]);
+		String src = args[2];
+		String target = args[3];
+		String debuggerClassName = args[5];
+
+		log.info("src: " + src); //$NON-NLS-1$
+		log.info("target: " + target); //$NON-NLS-1$
+		log.info("launchFile: " + launchFile); //$NON-NLS-1$
+		log.info("debugger: " + debuggerClassName); //$NON-NLS-1$
+
+		DebugRunner debugRunner = null;
+		try
+		{
+			final IXSLDebugger debugger = createDebugger(debuggerClassName);
+			// create the invoker
+			IProcessorInvoker invoker = new JAXPSAXProcessorInvoker()
+			{
+
+				protected TransformerFactory createTransformerFactory()
+				{
+					TransformerFactory tFactory = super.createTransformerFactory();
+					debugger.setTransformerFactory(tFactory);
+					return tFactory;
+				}
+
+				public void addStylesheet(URL stylesheet, Map parameters, Properties outputProperties, URIResolver resolver) throws TransformerConfigurationException
+				{
+					InputSource inputsource = new InputSource(stylesheet.toString());
+					// if required in future, parse the document with line numbers (to get the end line numbers)
+//					XMLReaderWrapper reader = new XMLReaderWrapper(createReader());
+//					SAXSource source = new SAXSource(reader,inputsource);
+					addStylesheet(new SAXSource(inputsource), resolver, parameters, outputProperties);
+				}
+				
+				protected Transformer addStylesheet(Source source, URIResolver resolver, Map parameters, Properties outputProperties) throws TransformerConfigurationException
+				{
+					Transformer transformer = super.addStylesheet(source, resolver, parameters, outputProperties);
+					debugger.addTransformer(transformer);
+					return transformer;
+				}
+			};
+
+			if (args.length == 9)
+			{
+				int requestPort = Integer.parseInt(args[6]);
+				int eventPort = Integer.parseInt(args[7]);
+				int generatePort = Integer.parseInt(args[8]);
+
+				log.debug("requestPort: " + requestPort); //$NON-NLS-1$
+				log.debug("eventPort: " + eventPort); //$NON-NLS-1$
+				log.debug("generatePort: " + generatePort); //$NON-NLS-1$
+
+				try
+				{
+					debugRunner = new DebugRunner(requestPort, eventPort, generatePort);
+				}
+				catch (Exception e)
+				{
+					handleFatalError("Could not instantiate invoker: " + invokerClassName, e); //$NON-NLS-1$
+				}
+			}
+			else
+			{
+				BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+				debugRunner = new DebugRunner(br, new PrintWriter(System.out), new PrintWriter(System.err), null);
+				System.out.println("xsl>"); //$NON-NLS-1$
+			}
+
+			PipelineDefinition pipeline = new PipelineDefinition(launchFile);
+			pipeline.configure(invoker);
+
+			debugger.setInvoker(invoker);
+			debugger.setSource(new URL(src));
+			debugger.setTarget(new FileWriter(new File(target)));
+
+			debugRunner.loop(debugger);
+		}
+		catch (Exception e)
+		{
+			handleFatalError(e.getMessage(), e);
+		}
+		finally
+		{
+			if (debugRunner != null)
+			{
+				try
+				{
+					debugRunner.dispose();
+				}
+				catch (IOException e)
+				{
+					handleFatalError(e.getMessage(), e);
+				}
+			}
+		}
+	}
+
+	private static IXSLDebugger createDebugger(String classname) throws ClassNotFoundException, InstantiationException, IllegalAccessException
+	{
+		Class clazz = Class.forName(classname);
+		return (IXSLDebugger) clazz.newInstance();
+	}
+
+	private static void handleFatalError(String msg, Throwable t)
+	{
+		log.fatal(msg, t);
+		System.exit(1);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/IXSLDebugger.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/IXSLDebugger.java
new file mode 100644
index 0000000..26b7f69
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/IXSLDebugger.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+import java.io.FileWriter;
+import java.io.Writer;
+import java.net.URL;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+
+import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
+
+/**
+ * An interface to XSL debugger instances.
+ * 
+ * @author Doug Satchwell
+ */
+public interface IXSLDebugger extends Runnable
+{
+	/**
+	 * Set the invoker to use.
+	 * 
+	 * @param invoker the invoker to set
+	 */
+	void setInvoker(IProcessorInvoker invoker);
+
+	/**
+	 * Set the transformer factory to use.
+	 * 
+	 * @param factory the factory to use
+	 */
+	void setTransformerFactory(TransformerFactory factory);
+
+	/**
+	 * Add a transformer to this.
+	 * 
+	 * @param transformer
+	 */
+	void addTransformer(Transformer transformer);
+
+	/**
+	 * Set the Writer for this to write events to.
+	 * 
+	 * @param writer the writer to write events to
+	 */
+	void setEventWriter(Writer writer);
+
+	/**
+	 * Set the ObjectOutputStream for this to write generated events to.
+	 * 
+	 * @param writer the stream to write generate events to
+	 */
+	void setGeneratedWriter(Writer writer);
+
+	/**
+	 * Set the URL of the transformation source file.
+	 * 
+	 * @param sourceURL the source URL
+	 */
+	void setSource(URL sourceURL);
+
+	/**
+	 * Set the transformation Result.
+	 * 
+	 * @param writer the result
+	 */
+	void setTarget(Writer writer);
+
+	/**
+	 * Add a breakpoint to this.
+	 * 
+	 * @param breakpoint
+	 */
+	void addBreakpoint(BreakPoint breakpoint);
+
+	/**
+	 * Remove a breakpoint from this.
+	 * 
+	 * @param breakpoint
+	 */
+	void removeBreakpoint(BreakPoint breakpoint);
+
+	/**
+	 * Perform a 'step into' operation.
+	 */
+	void stepInto();
+
+	/**
+	 * Perform a 'step over' operation.
+	 */
+	void stepOver();
+
+	/**
+	 * Perform a 'step return' operation.
+	 */
+	void stepReturn();
+
+	/**
+	 * Perform a 'suspend' operation.
+	 */
+	void suspend();
+
+	/**
+	 * Perform a 'resume' operation.
+	 */
+	void resume();
+
+	/**
+	 * Quit debugging.
+	 */
+	void quit();
+
+	/**
+	 * Generate a string that represents the current call stack of frames and their variables.
+	 * <p>
+	 * Frames are generated with the following format: <i>file</i>|<i>frameId</i>|<i>lineNumber</i>|<i>name</i>
+	 * This is immediately followed with the id's of the frame's variables (each variable id being unique for the whole process).
+	 * </p>
+	 * <p>
+	 * The separator for frames is $$$. Within a frame, the separator for variable id's is |.
+	 * </p>
+	 * <p>
+	 * e.g. file:/tran1.xsl|1|12|xsl:template name="temp1"|1|2|3$$$file:/tran2.xsl|2|34|xsl:template name="temp2"|4|5|6
+	 * 
+	 * This defines 2 frames with id's 1 and 2, which are occur in files tran1.xsl and tran2.xsl respectively.
+	 * Frame 1 is currently at line 12, in a template with name temp1, and it defines 3 variables with id's 1, 2 and 3. 
+	 * </p>
+	 * 
+	 * @return the generated string
+	 */
+	String stack();
+
+	/**
+	 * Get the variable with the given id.
+	 * 
+	 * @param id the id of the variable
+	 * @return the variable
+	 */
+	Variable getVariable(int id);
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/StyleFrame.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/StyleFrame.java
new file mode 100644
index 0000000..f77ef9a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/StyleFrame.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An <code>xsl:template</code> that forms part of the call stack.
+ * 
+ * @author Doug Satchwell
+ */
+public abstract class StyleFrame
+{
+	private static int nextId;
+	private final StyleFrame parent;
+	private final List children = new ArrayList();
+	private final int id;
+
+	/**
+	 * Create a new instance of this using the given frame as its parent (may be null if this is the root frame).
+	 * 
+	 * @param parent the parent frame
+	 */
+	public StyleFrame(StyleFrame parent)
+	{
+		this.id = nextId++;
+		this.parent = parent;
+		if (parent != null)
+			parent.addChild(this);
+	}
+	
+	/**
+	 * A unique id for this frame
+	 * 
+	 * @return a unique id for this frame
+	 */
+	public int getId()
+	{
+		return id;
+	}
+
+	/**
+	 * Get the name of this frame.
+	 * 
+	 * @return the name of this
+	 */
+	public abstract String getName();
+
+	/**
+	 * Get the file in which this frame is found.
+	 * 
+	 * @return the filename for this
+	 */
+	public abstract String getFilename();
+
+	/**
+	 * Get the line number at which the frame is currently located.
+	 * 
+	 * @return the line number at which this is held
+	 */
+	public abstract int getCurrentLine();
+
+	/**
+	 * Get a list of <code>Variables</code>'s
+	 * 
+	 * @return the list of variables for this frame
+	 */
+	public abstract List getVariableStack();
+
+	/**
+	 * Get the parent of this.
+	 * 
+	 * @return the parent frame
+	 */
+	public StyleFrame getParent()
+	{
+		return parent;
+	}
+
+	/**
+	 * Add a child frame to this.
+	 * 
+	 * @param child the frame to add
+	 */
+	public void addChild(StyleFrame child)
+	{
+		children.add(child);
+	}
+
+	/**
+	 * Remove a child frame from this.
+	 * 
+	 * @param child the frame to remove
+	 */
+	public void removeChild(StyleFrame child)
+	{
+		children.remove(child);
+	}
+
+	/**
+	 * Get the children of this
+	 * 
+	 * @return a list of <code>StyleFrame</code>'s
+	 */
+	public List getChildren()
+	{
+		return children;
+	}
+
+	/**
+	 * Creates a string in the format <i>file</i>|<i>frameId</i>|<i>lineNumber</i>|<i>name</i>.
+	 * Since pipe is used as a separator, the name has any pipe (|) characters replaced with the literal '%@_PIPE_@%'
+	 */
+	public String toString()
+	{
+		String safename = getName().replaceAll("\\|", "%@_PIPE_@%");  //$NON-NLS-1$//$NON-NLS-2$
+		return getFilename() + "|" + getId() + "|" + getCurrentLine() + "|" + safename;  //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/Variable.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/Variable.java
new file mode 100644
index 0000000..8c7fc29
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/debugger/Variable.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.debugger;
+
+/**
+ * An abstract class that XSL processor implementations can subclass for their variables.
+ * 
+ * @author Doug Satchwell
+ */
+public abstract class Variable
+{
+	private static int idSequence = 0;
+
+	/**
+	 * The constant denoting a local scope variable.
+	 */
+	public static final String LOCAL_SCOPE = "L"; //$NON-NLS-1$
+	/**
+	 * The constant denoting a tunnel scope variable.
+	 */
+	public static final String TUNNEL_SCOPE = "T"; //$NON-NLS-1$
+	/**
+	 * The constant denoting a global scope variable.
+	 */
+	public static final String GLOBAL_SCOPE = "G"; //$NON-NLS-1$
+
+	protected final static int MAXIMUM_VALUE_SIZE = 100;
+
+	protected static final String UNRESOLVED = "unresolved"; //$NON-NLS-1$
+	protected static final String BOOLEAN = "boolean"; //$NON-NLS-1$
+	protected static final String NUMBER = "number"; //$NON-NLS-1$
+	protected static final String STRING = "string"; //$NON-NLS-1$
+	protected static final String NODESET = "nodeset"; //$NON-NLS-1$
+	protected static final String OBJECT = "object"; //$NON-NLS-1$
+	protected static final String UNKNOWN = "unknown"; //$NON-NLS-1$
+
+	protected final String name;
+	protected final String scope;
+	protected final int slotNumber;
+
+	private int id;
+
+	/**
+	 * Create a new instance of this with the given name, scope and slot number.
+	 * 
+	 * @param name the name of this
+	 * @param scope the scope of this
+	 * @param slotNumber the slot number of this
+	 */
+	public Variable(String name, String scope, int slotNumber)
+	{
+		this.name = name;
+		this.scope = scope;
+		this.slotNumber = slotNumber;
+		this.id = idSequence++;
+	}
+
+	/**
+	 * Get the id used for this.
+	 * 
+	 * @return the variable id
+	 */
+	public int getId()
+	{
+		return id;
+	}
+	
+	/**
+	 * Get the variable name.
+	 * 
+	 * @return the variable name
+	 */
+	public String getName()
+	{
+		return name;
+	}
+
+	/**
+	 * Get the type of this variable e.g. string, or node
+	 * 
+	 * @return the variable type
+	 */
+	public abstract String getType();
+
+	/**
+	 * Get the scope of this variable - one of <code>LOCAL_SCOPE</code>, <code>TUNNEL_SCOPE</code> or <code>GLOBAL_SCOPE</code>.
+	 * 
+	 * @return the variable scope
+	 */
+	public String getScope()
+	{
+		return scope;
+	}
+
+	/**
+	 * Get the current value of this variable as a String.
+	 * 
+	 * @return the value of this
+	 */
+	public abstract String getValue();
+
+	/**
+	 * Get the first line of the value truncating to <code>MAXIMUM_VALUE_SIZE</code> where necessary.
+	 * 
+	 * @return the first line of the value
+	 */
+	public String getValueFirstLine()
+	{
+		String value = getValue();
+		if (value != null)
+		{
+			// make sure it is not too long
+			value = value.replace('\n', '.');
+			if (value.length() > MAXIMUM_VALUE_SIZE)
+				value = value.substring(0, MAXIMUM_VALUE_SIZE);
+		}
+		else
+			value = ""; //$NON-NLS-1$
+		return value;
+	}
+
+	/**
+	 * Get the slot number for this.
+	 * 
+	 * @return the slot number
+	 */
+	public int getSlotNumber()
+	{
+		return slotNumber;
+	}
+
+	public int hashCode()
+	{
+		return 3 * scope.hashCode() + 5 * slotNumber;
+	}
+	
+	public boolean equals(Object obj)
+	{
+		if (obj == this)
+			return true;
+		if (obj instanceof Variable)
+		{
+			Variable v = (Variable) obj;
+			return v.scope.equals(scope) && slotNumber == v.slotNumber;
+		}
+		return false;
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/IProcessorInvoker.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/IProcessorInvoker.java
new file mode 100644
index 0000000..21b657b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/IProcessorInvoker.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.URIResolver;
+
+
+/**
+ * Interface used by the launched process to define the XSL transformation pipeline.
+ * The <code>setAttributes</code> and <code>addStylesheet</code> methods should be called
+ * before calling <code>transform</code> to do the actual transformation.
+ * 
+ * <p>
+ * If <code>addStylesheet</code> is not called before <code>transform</code>, then
+ * it is assumed that the source document contains and embedded stylesheet instruction.
+ * </p>
+ * 
+ * @author Doug Satchwell
+ */
+public interface IProcessorInvoker
+{
+	/**
+	 * Set the processor-specific attributes to use.
+	 * 
+	 * @param attributes a map of String v. String attributes
+	 */
+	void setAttributes(Map attributes);
+
+	/**
+	 * Add a stylesheet to the pipeline (order is important).
+	 * 
+	 * @param stylesheet the URL of the stylesheet to add
+	 * @param parameters the map of parameters for the stylesheet
+	 * @param outputProperties the output properties
+	 * @param resolver the <code>URIResolver</code> to use
+	 * @throws TransformerConfigurationException if stylesheet could not be added
+	 */
+	void addStylesheet(URL stylesheet, Map parameters, Properties outputProperties, URIResolver resolver) throws TransformerConfigurationException;
+
+	/**
+	 * Perform the actual transformation.
+	 * 
+	 * @param source the URL of the XML source document
+	 * @param res the transformation result
+	 * @throws TransformationException if the transformation failed
+	 */
+	void transform(URL source, Result res) throws TransformationException;
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/Messages.java
new file mode 100644
index 0000000..9e6942a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/Messages.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Messages for the configuration.
+ * 
+ * @author Doug Satchwell
+ */
+class Messages
+{
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.debug.invoker.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+	private Messages()
+	{
+	}
+
+	/**
+	 * Get a message for the given key.
+	 * 
+	 * @param key the message key
+	 * @return the message
+	 */
+	public static String getString(String key)
+	{
+		try
+		{
+			return RESOURCE_BUNDLE.getString(key);
+		}
+		catch (MissingResourceException e)
+		{
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/PipelineDefinition.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/PipelineDefinition.java
new file mode 100644
index 0000000..198f999
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/PipelineDefinition.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+
+import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.ConfigurationException;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.CreationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * The definition of the transformation pipeline.
+ * <p>
+ * This class is loaded on both the Eclipse classpath and the transformation process's classpath.
+ * The whole definition is serialized to an XML document by the Eclipse launcher, and is then 
+ * read by the transformation process when launched.
+ * </p>
+ * 
+ * @author Doug Satchwell
+ */
+public class PipelineDefinition
+{
+	private String sourceURL;
+	private String targetFile;
+	private final List transformDefs = new ArrayList();
+	private final Set attributes = new HashSet();
+	private boolean useEmbedded;
+
+	/**
+	 * Create a new empty instance of this.
+	 */
+	public PipelineDefinition()
+	{
+	}
+
+	/**
+	 * Create a new instance of this by reading the specified XML file.
+	 * 
+	 * @param launchFile the XSL file to load
+	 * @throws SAXException if problems occur during parsing
+	 * @throws IOException if problems occur during parsing
+	 * @throws ParserConfigurationException if problems occur during parsing
+	 */
+	public PipelineDefinition(File launchFile) throws SAXException, IOException, ParserConfigurationException
+	{
+		this(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new BufferedInputStream(new FileInputStream(launchFile))));
+	}
+
+	/**
+	 * Create a new instance of this from the specified document
+	 * 
+	 * @param doc the Document to create this from
+	 */
+	public PipelineDefinition(Document doc)
+	{
+		Element rootEl = doc.getDocumentElement();
+
+		Element attributesEl = (Element) rootEl.getElementsByTagName("Attributes").item(0); //$NON-NLS-1$
+		NodeList attributeEls = attributesEl.getElementsByTagName("Attribute"); //$NON-NLS-1$
+		for (int i = 0; i < attributeEls.getLength(); i++)
+		{
+			Element attributeEl = (Element) attributeEls.item(i);
+			String name = attributeEl.getAttribute("name"); //$NON-NLS-1$
+			String type = attributeEl.getAttribute("type"); //$NON-NLS-1$
+			String value = attributeEl.getAttribute("value"); //$NON-NLS-1$
+			addAttribute(new TypedValue(name, type, value));
+		}
+
+		Element transformsEl = (Element) rootEl.getElementsByTagName("Transforms").item(0); //$NON-NLS-1$
+		String useEmbedded = transformsEl.getAttribute("useEmbedded"); //$NON-NLS-1$
+		boolean embedded = Boolean.getBoolean(useEmbedded);
+		setUseEmbedded(embedded);
+		if (!embedded)
+		{
+			NodeList transformEls = transformsEl.getElementsByTagName("Transform"); //$NON-NLS-1$
+			for (int i = 0; i < transformEls.getLength(); i++)
+			{
+				Element transformEl = (Element) transformEls.item(i);
+				TransformDefinition tdef = TransformDefinition.fromXML(transformEl);
+				addTransformDef(tdef);
+			}
+		}
+	}
+
+	/**
+	 * Configure the invoker from this.
+	 * 
+	 * @param invoker the invoker to configure
+	 * @throws ConfigurationException if an exception occurs during configuration
+	 */
+	public void configure(IProcessorInvoker invoker) throws ConfigurationException
+	{
+		Map attVals = new HashMap();
+		for (Iterator iter = attributes.iterator(); iter.hasNext();)
+		{
+			TypedValue att = (TypedValue) iter.next();
+			Object value;
+			try
+			{
+				value = att.createValue();
+			}
+			catch (CreationException e)
+			{
+				throw new ConfigurationException(e.getMessage(), e);
+			}
+			attVals.put(att.uri, value);
+		}
+		invoker.setAttributes(attVals);
+
+		for (Iterator iter = transformDefs.iterator(); iter.hasNext();)
+		{
+			TransformDefinition tdef = (TransformDefinition) iter.next();
+			Map params = null;
+			try
+			{
+				params = tdef.getParametersAsMap();
+			}
+			catch (CreationException e)
+			{
+				throw new ConfigurationException(Messages.getString("PipelineDefinition.8"), e); //$NON-NLS-1$
+			}
+			URL url = null;
+			try
+			{
+				url = new URL(tdef.getStylesheetURL());
+			}
+			catch (MalformedURLException e)
+			{
+				throw new ConfigurationException(Messages.getString("PipelineDefinition.9") + tdef.getStylesheetURL(), e); //$NON-NLS-1$
+			}
+			Properties properties = tdef.getOutputProperties();
+			try
+			{
+				invoker.addStylesheet(url, params, properties, null);
+			}
+			catch (TransformerConfigurationException e)
+			{
+				throw new ConfigurationException(Messages.getString("PipelineDefinition.10") + tdef.getStylesheetURL(), null); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
+	 * Get the set of attributes defined.
+	 * 
+	 * @return the set of attributes
+	 */
+	public Set getAttributes()
+	{
+		return attributes;
+	}
+
+	/**
+	 * Add a attribute to this configuration
+	 * 
+	 * @param attribute the attribute to add
+	 */
+	public void addAttribute(TypedValue attribute)
+	{
+		attributes.add(attribute);
+	}
+
+	/**
+	 * Remove a attribute from the set of attributes
+	 * 
+	 * @param attribute the attribute to remove
+	 */
+	public void removeAttribute(TypedValue attribute)
+	{
+		attributes.remove(attribute);
+	}
+
+	/**
+	 * Get the list of <code>TransformDefinition</code>'s.
+	 * 
+	 * @return the list of transform definitions
+	 */
+	public List getTransformDefs()
+	{
+		return transformDefs;
+	}
+
+	/**
+	 * Add a transform definition to this.
+	 * 
+	 * @param tdef the transform definition to add
+	 */
+	public void addTransformDef(TransformDefinition tdef)
+	{
+		transformDefs.add(tdef);
+	}
+
+	/**
+	 * Remove a transform definition from this.
+	 * 
+	 * @param tdef the transform definition to remove
+	 */
+	public void removeTransformDef(TransformDefinition tdef)
+	{
+		transformDefs.remove(tdef);
+	}
+
+	/**
+	 * Set whether to use an XSL declaration embedded in the XML file 
+	 * 
+	 * @param embedded true to use embedded
+	 */
+	public void setUseEmbedded(boolean embedded)
+	{
+		useEmbedded = embedded;
+	}
+
+	/**
+	 * Get whether to use an XSL declaration embedded in the XML file 
+	 * 
+	 * @return true if embedded
+	 */
+	public boolean useEmbedded()
+	{
+		return useEmbedded;
+	}
+
+	/**
+	 * Serialize this to a DOM Document.
+	 * 
+	 * @return the serialized document
+	 * @throws ParserConfigurationException if a problem occurs during serialization
+	 */
+	public Document toXML() throws ParserConfigurationException
+	{
+		Document doc = newDocument();
+		Element rootEl = doc.createElement("Pipeline"); //$NON-NLS-1$
+		rootEl.setAttribute("source", sourceURL); //$NON-NLS-1$
+		rootEl.setAttribute("target", targetFile); //$NON-NLS-1$
+		doc.appendChild(rootEl);
+
+		Element attributesEl = doc.createElement("Attributes"); //$NON-NLS-1$
+		rootEl.appendChild(attributesEl);
+		for (Iterator iter = attributes.iterator(); iter.hasNext();)
+		{
+			TypedValue attribute = (TypedValue) iter.next();
+			Element attributeEl = doc.createElement("Attribute"); //$NON-NLS-1$
+			attributeEl.setAttribute("name", attribute.uri); //$NON-NLS-1$
+			attributeEl.setAttribute("type", attribute.type); //$NON-NLS-1$
+			attributeEl.setAttribute("value", attribute.value); //$NON-NLS-1$
+			attributesEl.appendChild(attributeEl);
+		}
+
+		rootEl.setAttribute("useEmbedded", String.valueOf(useEmbedded)); //$NON-NLS-1$
+		if (!useEmbedded)
+		{
+			Element transformsEl = doc.createElement("Transforms"); //$NON-NLS-1$
+			rootEl.appendChild(transformsEl);
+			for (Iterator iter = transformDefs.iterator(); iter.hasNext();)
+			{
+				TransformDefinition tdef = (TransformDefinition) iter.next();
+				Element tdefEl = tdef.asXML(doc);
+				transformsEl.appendChild(tdefEl);
+			}
+		}
+
+		return doc;
+	}
+
+	private static Document newDocument() throws ParserConfigurationException
+	{
+		DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
+		DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
+		Document doc = docBuilder.newDocument();
+		return doc;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformDefinition.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformDefinition.java
new file mode 100644
index 0000000..8679d90
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformDefinition.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.CreationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * A definition of a particular step in the transformation pipeline.
+ * 
+ * @author Doug Satchwell
+ */
+public class TransformDefinition
+{
+	private String stylesheetURL;
+	private String resolverClass;
+	private Properties outputProperties = new Properties();
+	private final Set parameters = new HashSet();
+
+	/**
+	 * Get the parameters as a map of name (<code>String</code>) v. value <code>TypedValue</code>.
+	 * 
+	 * @return a map of names and values
+	 * @throws CreationException if an exception occurred during object creation
+	 */
+	public Map getParametersAsMap() throws CreationException
+	{
+		Map m = new HashMap();
+		for (Iterator iter = parameters.iterator(); iter.hasNext();)
+		{
+			TypedValue tv = (TypedValue) iter.next();
+			String key = tv.uri;
+			Object value = tv.createValue();
+			m.put(key, value);
+		}
+		return m;
+	}
+
+	/**
+	 * The set of parameters
+	 * 
+	 * @return a set of <code>TypedValue</code>'s
+	 */
+	public Set getParameters()
+	{
+		return parameters;
+	}
+
+	/**
+	 * Add a parameter to the set of parameters
+	 * 
+	 * @param parameter the parameter to add
+	 */
+	public void addParameter(TypedValue parameter)
+	{
+		parameters.add(parameter);
+	}
+
+	/**
+	 * Remove a parameter.
+	 * 
+	 * @param parameter the parameter to remove
+	 */
+	public void removeParameter(TypedValue parameter)
+	{
+		parameters.remove(parameter);
+	}
+
+	/**
+	 * Get the output properties for this.
+	 * 
+	 * @return the output properties
+	 */
+	public Properties getOutputProperties()
+	{
+		return outputProperties;
+	}
+
+	/**
+	 * Set the output properties for this.
+	 * 
+	 * @param outputProperties the output properties to set
+	 */
+	public void setOutputProperties(Properties outputProperties)
+	{
+		this.outputProperties = outputProperties;
+	}
+
+	/**
+	 * Set the value of a specific output property.
+	 * 
+	 * @param name the output property
+	 * @param value the value
+	 */
+	public void setOutputProperty(String name, String value)
+	{
+		outputProperties.put(name, value);
+	}
+
+	/**
+	 * Remove an output property.
+	 * 
+	 * @param name the output property to remove
+	 */
+	public void removeOutputProperty(String name)
+	{
+		outputProperties.remove(name);
+	}
+
+	/**
+	 * Get the name of the <code>URIResolver</code> class to use.
+	 * 
+	 * @return the resolver's class name
+	 */
+	public String getResolverClass()
+	{
+		return resolverClass;
+	}
+
+	/**
+	 * Set the name of the <code>URIResolver</code> class to use.
+	 * 
+	 *  @param resolver the resolver's class name
+	 */
+	public void setResolverClass(String resolver)
+	{
+		resolverClass = resolver;
+	}
+
+	/**
+	 * Get the URL of the stylesheet.
+	 * 
+	 * @return the stylesheet URL
+	 */
+	public String getStylesheetURL()
+	{
+		return stylesheetURL;
+	}
+
+	/**
+	 * Set the URL of the stylesheet.
+	 * 
+	 * @param stylesheet the stylesheet URL
+	 */
+	public void setStylesheetURL(String stylesheet)
+	{
+		stylesheetURL = stylesheet;
+	}
+
+	/**
+	 * Serialize this to a Document fragment.
+	 * 
+	 * @param doc the document to attach to
+	 * @return the root element of the fragment
+	 */
+	public Element asXML(Document doc)
+	{
+		Element tdefEl = doc.createElement("Transform"); //$NON-NLS-1$
+		tdefEl.setAttribute(Messages.getString("TransformDefinition.1"), stylesheetURL); //$NON-NLS-1$
+		if (resolverClass != null)
+			tdefEl.setAttribute("uriResolver", resolverClass); //$NON-NLS-1$
+		Element opEl = doc.createElement("OutputProperties"); //$NON-NLS-1$
+		tdefEl.appendChild(opEl);
+		for (Iterator iter = outputProperties.entrySet().iterator(); iter.hasNext();)
+		{
+			Map.Entry entry = (Map.Entry) iter.next();
+			Element propEl = doc.createElement("Property"); //$NON-NLS-1$
+			propEl.setAttribute("name", (String) entry.getKey()); //$NON-NLS-1$
+			propEl.setAttribute("value", (String) entry.getValue()); //$NON-NLS-1$
+			opEl.appendChild(propEl);
+		}
+		Element paramsEl = doc.createElement("Parameters"); //$NON-NLS-1$
+		tdefEl.appendChild(paramsEl);
+		for (Iterator iter = parameters.iterator(); iter.hasNext();)
+		{
+			Element propEl = doc.createElement("Parameter"); //$NON-NLS-1$
+			TypedValue param = (TypedValue) iter.next();
+			propEl.setAttribute("name", param.uri); //$NON-NLS-1$
+			propEl.setAttribute("type", param.type); //$NON-NLS-1$
+			propEl.setAttribute("value", param.value); //$NON-NLS-1$
+			paramsEl.appendChild(propEl);
+		}
+		return tdefEl;
+	}
+
+	/**
+	 * Create a new instance of this from its serialized form.
+	 * 
+	 * @param transformEl the element to create this from
+	 * @return a new instance of this
+	 */
+	public static TransformDefinition fromXML(Element transformEl)
+	{
+		TransformDefinition tdef = new TransformDefinition();
+		String url = transformEl.getAttribute("url"); //$NON-NLS-1$
+		tdef.setStylesheetURL(url);
+		String uriResolver = transformEl.getAttribute("uriResolver"); //$NON-NLS-1$
+		tdef.setResolverClass(uriResolver);
+
+		Element opEl = (Element) transformEl.getElementsByTagName("OutputProperties").item(0); //$NON-NLS-1$
+		if (opEl != null)
+		{
+			NodeList propEls = opEl.getElementsByTagName("Property"); //$NON-NLS-1$
+			for (int i = 0; i < propEls.getLength(); i++)
+			{
+				Element propEl = (Element) propEls.item(i);
+				String name = propEl.getAttribute("name"); //$NON-NLS-1$
+				String value = propEl.getAttribute("value"); //$NON-NLS-1$
+				tdef.setOutputProperty(name, value);
+			}
+		}
+
+		Element paramsEl = (Element) transformEl.getElementsByTagName(Messages.getString("TransformDefinition.18")).item(0); //$NON-NLS-1$
+		if (paramsEl != null)
+		{
+			NodeList paramEls = paramsEl.getElementsByTagName(Messages.getString("TransformDefinition.19")); //$NON-NLS-1$
+			for (int i = 0; i < paramEls.getLength(); i++)
+			{
+				Element paramEl = (Element) paramEls.item(i);
+				String name = paramEl.getAttribute(Messages.getString("TransformDefinition.20")); //$NON-NLS-1$
+				String type = paramEl.getAttribute(Messages.getString("TransformDefinition.21")); //$NON-NLS-1$
+				String value = paramEl.getAttribute(Messages.getString("TransformDefinition.22")); //$NON-NLS-1$
+				tdef.addParameter(new TypedValue(name, type, value));
+			}
+		}
+
+		return tdef;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformationException.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformationException.java
new file mode 100644
index 0000000..aa0acaf
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TransformationException.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+/**
+ * Checked Exception for transformation errors.
+ * 
+ * @author Doug Satchwell
+ */
+public class TransformationException extends Exception
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Create a new instance of this with the given message.
+	 * 
+	 * @param message the message
+	 */
+	public TransformationException(String message)
+	{
+		super(message);
+	}
+
+	/**
+	 * Create a new instance of this with the given message and cause.
+	 * 
+	 * @param message the message
+	 * @param cause the cause
+	 */
+	public TransformationException(String message, Throwable cause)
+	{
+		super(message, cause);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TypedValue.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TypedValue.java
new file mode 100644
index 0000000..ad51c4d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/TypedValue.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker;
+
+import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.CreationException;
+
+/**
+ * A value that is to be instantiated from a particular type e.g. Double, Object.
+ * 
+ * @author Doug Satchwell
+ */
+public class TypedValue
+{
+	public static final String TYPE_STRING = "string"; //$NON-NLS-1$
+	private static final String TYPE_BOOLEAN = "boolean"; //$NON-NLS-1$
+	private static final String TYPE_INT = "int"; //$NON-NLS-1$
+	private static final String TYPE_DOUBLE = "double"; //$NON-NLS-1$
+	private static final String TYPE_FLOAT = "float"; //$NON-NLS-1$
+	private static final String TYPE_CLASS = "class"; //$NON-NLS-1$
+	private static final String TYPE_OBJECT = "object"; //$NON-NLS-1$
+
+	final String uri;
+	final String type;
+	final String value;
+
+	/**
+	 * Create a new instance of this from the given information. 
+	 * 
+	 * @param uri the URI
+	 * @param type the type of value
+	 * @param value the value
+	 */
+	public TypedValue(String uri, String type, String value)
+	{
+		this.uri = uri;
+		this.type = type;
+		this.value = value;
+	}
+
+	/**
+	 * Create the type of object defined by this. 
+	 * 
+	 * @return the value
+	 * @throws CreationException if a problem occurred
+	 */
+	public Object createValue() throws CreationException
+	{
+		Object o = null;
+		if (TYPE_STRING.equals(type))
+		{
+			o = value;
+		}
+		else if (TYPE_BOOLEAN.equals(type))
+		{
+			boolean b = "yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value); //$NON-NLS-1$ //$NON-NLS-2$
+			o = new Boolean(b);
+		}
+		else if (TYPE_INT.equals(type))
+		{
+			try
+			{
+				o = new Integer(value);
+			}
+			catch (NumberFormatException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.9") + value + Messages.getString("TypedValue.10"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		else if (TYPE_DOUBLE.equals(type))
+		{
+			try
+			{
+				o = new Double(value);
+			}
+			catch (NumberFormatException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.11") + value + Messages.getString("TypedValue.12"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		else if (TYPE_FLOAT.equals(type))
+		{
+			try
+			{
+				o = new Float(value);
+			}
+			catch (NumberFormatException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.13") + value + Messages.getString("TypedValue.14"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		else if (TYPE_CLASS.equals(type))
+		{
+			try
+			{
+				o = Class.forName(value);
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.15") + value + Messages.getString("TypedValue.16"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		else if (TYPE_OBJECT.equals(type))
+		{
+			try
+			{
+				Class c = Class.forName(value);
+				o = c.newInstance();
+			}
+			catch (ClassNotFoundException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.17") + value + Messages.getString("TypedValue.18"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			catch (InstantiationException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.19") + value + Messages.getString("TypedValue.20"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			catch (IllegalAccessException e)
+			{
+				throw new CreationException(Messages.getString("TypedValue.21") + value + Messages.getString("TypedValue.22"), e); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		else
+		{
+			throw new CreationException(Messages.getString("TypedValue.23") + type + Messages.getString("TypedValue.24")); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		return o;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/ConfigurationException.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/ConfigurationException.java
new file mode 100644
index 0000000..7526c73
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/ConfigurationException.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker.internal;
+
+/**
+ * An exception thrown when configuration of an XSL transform pipeline fails.
+ * 
+ * @author Doug Satchwell
+ */
+public class ConfigurationException extends Exception
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Create the exception.
+	 * 
+	 * @param msg the exception message
+	 * @param t the underlying cause
+	 */
+	public ConfigurationException(String msg, Throwable t)
+	{
+		super(msg, t);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/CreationException.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/CreationException.java
new file mode 100644
index 0000000..bba07bf
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/CreationException.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker.internal;
+
+/**
+ * Checked Exception for object creation errors.
+ * 
+ * @author Doug Satchwell
+ */
+public class CreationException extends Exception
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Create a new instance of this with the given message.
+	 * 
+	 * @param message the message
+	 */
+	public CreationException(String message)
+	{
+		super(message);
+	}
+
+	/**
+	 * Create a new instance of this with the given message and cause.
+	 * 
+	 * @param message the message
+	 * @param cause the cause
+	 */
+	public CreationException(String message, Throwable cause)
+	{
+		super(message, cause);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/JAXPSAXProcessorInvoker.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/JAXPSAXProcessorInvoker.java
new file mode 100644
index 0000000..3241ac5
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/JAXPSAXProcessorInvoker.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker.internal;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.TransformationException;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * An implementation of <code>IProcessorInvoker</code> that uses JAXP as the underlying
+ * transformation mechanism.
+ * 
+ * @author Doug Satchwell
+ */
+public class JAXPSAXProcessorInvoker implements IProcessorInvoker
+{
+	private static final Log log = LogFactory.getLog(JAXPSAXProcessorInvoker.class);
+
+	private XMLReader reader;
+	private SAXTransformerFactory tFactory;
+	private TransformerHandler th;
+
+	/**
+	 * Create a new instance of this.
+	 * 
+	 * @throws SAXException if errors occur while creating an <code>XMLReader</code>
+	 * @throws ParserConfigurationException if errors occur while creating an <code>XMLReader</code>
+	 */
+	public JAXPSAXProcessorInvoker() throws SAXException, ParserConfigurationException
+	{
+		reader = createReader();
+	}
+
+	protected XMLReader createReader() throws SAXException, ParserConfigurationException
+	{
+		SAXParserFactory spf = SAXParserFactory.newInstance();
+		spf.setNamespaceAware(true);
+		return spf.newSAXParser().getXMLReader();
+	}
+
+	public void setAttributes(Map attributes) throws TransformerFactoryConfigurationError
+	{
+		createTransformerFactory();
+		for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();)
+		{
+			Map.Entry entry = (Map.Entry) iter.next();
+			String uri = (String) entry.getKey();
+			Object value = entry.getValue();
+			log.info(Messages.getString("JAXPSAXProcessorInvoker.0") + uri + Messages.getString("JAXPSAXProcessorInvoker.1") + value); //$NON-NLS-1$ //$NON-NLS-2$
+			tFactory.setAttribute(uri, value);
+		}
+	}
+
+	protected TransformerFactory createTransformerFactory()
+	{
+		tFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
+		tFactory.setErrorListener(new ErrorListener()
+		{
+
+			public void error(TransformerException exception) throws TransformerException
+			{
+				log.error(exception.getMessageAndLocation());
+			}
+
+			public void fatalError(TransformerException exception) throws TransformerException
+			{
+				log.error(exception.getMessageAndLocation(), exception);
+				throw exception;
+			}
+
+			public void warning(TransformerException exception) throws TransformerException
+			{
+				log.warn(exception.getMessageAndLocation());
+			}
+
+		});
+		return tFactory;
+	}
+
+	public void addStylesheet(URL stylesheet, Map parameters, Properties outputProperties, URIResolver resolver) throws TransformerConfigurationException
+	{
+		InputSource inputsource = new InputSource(stylesheet.toString());
+
+		// TODO parse document with linenumbers
+
+		// XMLReader reader = createReader();
+		// LineReadingContentHandler ch = new LineReadingContentHandler();
+		// reader.setContentHandler(ch);
+		SAXSource source = new SAXSource(inputsource);
+
+		addStylesheet(source, resolver, parameters, outputProperties);
+
+	}
+
+	protected Transformer addStylesheet(Source source, URIResolver resolver, Map parameters, Properties outputProperties) throws TransformerConfigurationException
+	{
+		if (tFactory == null)
+			createTransformerFactory();
+
+		TransformerHandler newTh = tFactory.newTransformerHandler(source);
+		Transformer transformer = newTh.getTransformer();
+
+		if (resolver != null)
+			transformer.setURIResolver(resolver);
+
+		if (parameters != null)
+		{
+			for (Iterator iter = parameters.entrySet().iterator(); iter.hasNext();)
+			{
+				Map.Entry entry = (Map.Entry) iter.next();
+				String name = (String) entry.getKey();
+				Object value = entry.getValue();
+				log.info(Messages.getString("JAXPSAXProcessorInvoker.2") + name + Messages.getString("JAXPSAXProcessorInvoker.3") + value); //$NON-NLS-1$ //$NON-NLS-2$
+				transformer.setParameter(name, value);
+			}
+		}
+		if (outputProperties != null)
+		{
+			StringBuffer sb = new StringBuffer();
+			for (Iterator iter = outputProperties.entrySet().iterator(); iter.hasNext();)
+			{
+				Map.Entry entry = (Map.Entry) iter.next();
+				sb.append(entry.getKey()).append("=").append(entry.getValue()).append(" "); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			if (outputProperties.size() > 0)
+			{
+				log.info(Messages.getString("JAXPSAXProcessorInvoker.6") + sb.toString()); //$NON-NLS-1$
+				transformer.setOutputProperties(outputProperties);
+			}
+		}
+
+		if (th != null)
+			th.setResult(new SAXResult(newTh));
+		else
+			reader.setContentHandler(newTh);
+		th = newTh;
+		return th.getTransformer();
+	}
+
+	public void transform(URL sourceURL, Result res) throws TransformationException
+	{
+		transform(new InputSource(sourceURL.toExternalForm()), res);
+	}
+
+	/**
+	 * Transform using an InputSource rather than a URL
+	 * 
+	 * @param inputsource the InputSource to use
+	 * @param res the Result
+	 * @throws TransformationException if an error occurred during transformation
+	 */
+	public void transform(InputSource inputsource, Result res) throws TransformationException
+	{
+		try
+		{
+			if (th == null)
+			{// no stylesheets have been added, so try to use embedded...
+				SAXSource saxSource = new SAXSource(inputsource);
+				Source src = saxSource;
+				String media = null, title = null, charset = null;
+				while (true)
+				{
+					src = tFactory.getAssociatedStylesheet(src, media, title, charset);
+					if (src != null)
+					{
+						addStylesheet(saxSource, null, Collections.EMPTY_MAP, new Properties());
+					}
+					else
+					{
+						throw new TransformationException(Messages.getString("JAXPSAXProcessorInvoker.7") + inputsource.getSystemId()); //$NON-NLS-1$
+					}
+				}
+			}
+			th.setResult(res);
+			log.info(Messages.getString("JAXPSAXProcessorInvoker.8")); //$NON-NLS-1$
+			reader.parse(inputsource);
+			log.info(Messages.getString("JAXPSAXProcessorInvoker.9")); //$NON-NLS-1$
+		}
+		catch (Exception e)
+		{
+			throw new TransformationException(e.getMessage(), e);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Main.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Main.java
new file mode 100644
index 0000000..1ccdce8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Main.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.net.URL;
+
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.PipelineDefinition;
+
+/**
+ * The class whose <code>main</code> method is called when launching the transformation process from
+ * Eclipse.
+ * 
+ * @author Doug Satchwell
+ */
+public class Main
+{
+	private static final Log log = LogFactory.getLog(Main.class);
+
+	/**
+	 * The <code>main</code> method called when launching the transformation process.
+	 * There are 4 required arguments:
+	 * <ol>
+	 * <li>The class name of the <code>IProcessorInvoker</code> to use
+	 * <li>The launch file (serialized <code>PipelineDefinition</code>)
+	 * <li>The URL of the source XML document
+	 * <li>The file where output will be written
+	 * </ol>
+	 * 
+	 * @param args the 4 required arguments
+	 */
+	public static void main(String[] args)
+	{
+		log.info("javax.xml.transform.TransformerFactory=" + System.getProperty("javax.xml.transform.TransformerFactory")); //$NON-NLS-1$ //$NON-NLS-2$
+		log.info("java.endorsed.dirs=" + System.getProperty("java.endorsed.dirs")); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		String invokerClassName = args[0];
+		File launchFile = new File(args[1]);
+		String src = args[2];
+		String target = args[3];
+
+		log.info(Messages.getString("Main.4") + launchFile); //$NON-NLS-1$
+
+		// create the invoker
+		IProcessorInvoker invoker = null;
+		try
+		{
+			Class clazz = Class.forName(invokerClassName);
+			invoker = (IProcessorInvoker) clazz.newInstance();
+		}
+		catch (Exception e)
+		{
+			handleFatalError(Messages.getString("Main.5") + invokerClassName, e); //$NON-NLS-1$
+		}
+		try
+		{
+			PipelineDefinition pipeline = new PipelineDefinition(launchFile);
+			pipeline.configure(invoker);
+			invoker.transform(new URL(src), new StreamResult(new FileOutputStream(new File(target))));
+		}
+		catch (Exception e)
+		{
+			handleFatalError(e.getMessage(), e);
+		}
+	}
+
+	private static void handleFatalError(String msg, Throwable t)
+	{
+		log.fatal(msg, t);
+		System.exit(1);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Messages.java
new file mode 100644
index 0000000..7ee3995
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/Messages.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.debug.invoker.internal;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Messages for the transformation.
+ * 
+ * @author Doug Satchwell
+ */
+public class Messages
+{
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.debug.invoker.internal.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+	private Messages()
+	{
+	}
+
+	/**
+	 * Get a message for the given key.
+	 * 
+	 * @param key the message key
+	 * @return the message
+	 */
+	public static String getString(String key)
+	{
+		try
+		{
+			return RESOURCE_BUNDLE.getString(key);
+		}
+		catch (MissingResourceException e)
+		{
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/messages.properties
new file mode 100644
index 0000000..ff8f9a1
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/internal/messages.properties
@@ -0,0 +1,10 @@
+JAXPSAXProcessorInvoker.0=Setting attribute '
+JAXPSAXProcessorInvoker.1=' to value 
+JAXPSAXProcessorInvoker.2=Setting parameter '
+JAXPSAXProcessorInvoker.3=' to value 
+JAXPSAXProcessorInvoker.6=Setting properties: 
+JAXPSAXProcessorInvoker.7=No embedded stylesheet instruction for file: 
+JAXPSAXProcessorInvoker.8=Transforming...
+JAXPSAXProcessorInvoker.9=Done.
+Main.4=launchFile: 
+Main.5=Could not instantiate invoker: 
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/messages.properties
new file mode 100644
index 0000000..fea9b3c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.debug/src/org/eclipse/wst/xsl/jaxp/debug/invoker/messages.properties
@@ -0,0 +1,25 @@
+PipelineDefinition.10=Error with stylesheet: 
+PipelineDefinition.8=Could not instantiate parameter
+PipelineDefinition.9=Invalid stylesheet URL: 
+TransformDefinition.1=url
+TransformDefinition.18=Parameters
+TransformDefinition.19=Parameter
+TransformDefinition.20=name
+TransformDefinition.21=type
+TransformDefinition.22=value
+TypedValue.10=' to an Integer
+TypedValue.11=Could not convert value '
+TypedValue.12=' to a Double
+TypedValue.13=Could not convert value '
+TypedValue.14=' to a Float
+TypedValue.15=Class '
+TypedValue.16=' could not be located (check the classpath)
+TypedValue.17=Class '
+TypedValue.18=' could not be located (check the classpath)
+TypedValue.19=Object '
+TypedValue.20=' could not be instantiated
+TypedValue.21=Object '
+TypedValue.22=\ could not be instantiated
+TypedValue.23=Attribute type '
+TypedValue.24=' is not recognised
+TypedValue.9=Could not convert value '
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/.classpath b/bundles/org.eclipse.wst.xsl.jaxp.launching/.classpath
new file mode 100644
index 0000000..64c5e31
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/.project b/bundles/org.eclipse.wst.xsl.jaxp.launching/.project
new file mode 100644
index 0000000..8dea7ec
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.wst.xsl.jaxp.launching</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+	</natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.wst.xsl.jaxp.launching/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..b8d9369
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Wed Jul 30 16:38:51 BST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultAttributes.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultAttributes.properties
new file mode 100644
index 0000000..9c244d2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultAttributes.properties
@@ -0,0 +1,10 @@
+###############################################################################
+# Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+# 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
+#
+# Contributors:
+#    Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+###############################################################################
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultOutputProperties.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultOutputProperties.properties
new file mode 100644
index 0000000..ad23e9d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/JREDefaultOutputProperties.properties
@@ -0,0 +1,40 @@
+###############################################################################
+# Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+# 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
+#
+# Contributors:
+#    Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+###############################################################################
+
+method=method
+method.DESC="xml" | "html" | "text" | qname-but-not-ncname 
+
+version=version
+version.DESC=specifies the version of the output method
+
+indent=indent
+indent.DESC=specifies whether the XSLT processor may add additional whitespace when outputting the result tree; the value must be yes or no
+
+encoding=encoding
+encoding.DESC=specifies the preferred character encoding that the XSLT processor should use to encode sequences of characters as sequences of bytes; the value of the attribute should be treated case-insensitively; the value must contain only characters in the range #x21 to #x7E (i.e. printable ASCII characters); the value should either be a charset registered with the Internet Assigned Numbers Authority [IANA], [RFC2278] or start with X-
+
+media-type=media-type
+media-type.DESC=specifies the media type (MIME content type) of the data that results from outputting the result tree; the charset parameter should not be specified explicitly; instead, when the top-level media type is text, a charset parameter should be added according to the character encoding actually used by the output method
+
+doctype-system=doctype-system
+doctype-system.DESC=specifies the system identifier to be used in the document type declaration
+
+doctype-public=doctype-public
+doctype-public.DESC=specifies the public identifier to be used in the document type declaration
+
+omit-xml-declaration=omit-xml-declaration
+omit-xml-declaration.DESC=specifies whether the XSLT processor should output an XML declaration; the value must be yes or no
+
+standalone=standalone
+standalone.DESC=specifies whether the XSLT processor should output a standalone document declaration; the value must be yes or no
+
+cdata-section-elements=cdata-section-elements
+cdata-section-elements.DESC=specifies a list of the names of elements whose text node children should be output using CDATA sections
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.xsl.jaxp.launching/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..d8d35d3
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name.0
+Bundle-SymbolicName: org.eclipse.wst.xsl.jaxp.launching;singleton:=true
+Bundle-Version: 0.5.0.qualifier
+Bundle-Activator: org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.core.variables;bundle-version="3.2.100",
+ org.eclipse.debug.core;bundle-version="3.4.0",
+ org.eclipse.jdt.launching;bundle-version="3.4.0",
+ org.eclipse.wst.xsl.launching;bundle-version="0.5.0",
+ org.eclipse.wst.xsl.jaxp.debug;bundle-version="0.5.0",
+ org.eclipse.jface;bundle-version="3.4.0",
+ org.eclipse.ui;bundle-version="3.4.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-Vendor: %Bundle-Vendor.0
+Export-Package: org.eclipse.wst.xsl.jaxp.launching
+Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/about.html b/bundles/org.eclipse.wst.xsl.jaxp.launching/about.html
new file mode 100644
index 0000000..ed30003
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/about.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<HTML>
+
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+
+<BODY lang="EN-US">
+
+<H3>About This Content</H3>
+
+<P>August, 2008</P>
+
+<H3>License</H3>
+
+<P>The Eclipse Foundation makes available all content in this plug-in 
+("Content"). Unless otherwise indicated below, the Content is provided to you 
+under the terms and conditions of the Eclipse Public License Version 1.0 
+("EPL"). A copy of the EPL is available at
+<A href="http://www.eclipse.org/org/documents/epl-v10.php">http://www.eclipse.org/org/documents/epl-v10.php</A>. 
+For purposes of the EPL, "Program" will mean the Content.</P>
+
+<P>If you did not receive this Content directly from the Eclipse Foundation, the 
+Content is being redistributed by another party ("Redistributor") and different 
+terms and conditions may apply to your use of any object code in the Content. 
+Check the Redistributor’s license that was provided with the Content. If no such 
+license exists, contact the Redistributor. Unless otherwise indicated below, the 
+terms and conditions of the EPL still apply to any source code in the Content 
+and such source code may be obtained at
+<A href="http://www.eclipse.org/">http://www.eclipse.org/</A>.</P>
+
+</BODY>
+</HTML>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/build.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/build.properties
new file mode 100644
index 0000000..dcb663a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/build.properties
@@ -0,0 +1,11 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               about.html,\
+               schema/,\
+               JREDefaultAttributes.properties,\
+               JREDefaultOutputProperties.properties,\
+               plugin.properties,\
+               log4j.debug.properties
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/log4j.debug.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/log4j.debug.properties
new file mode 100644
index 0000000..62dfb61
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/log4j.debug.properties
@@ -0,0 +1,10 @@
+# Set root logger level to DEBUG and its appenders are A1 and A2
+log4j.rootLogger=ERROR, A2
+
+# A2 is set to be a ConsoleAppender
+log4j.appender.A2=org.apache.log4j.ConsoleAppender
+
+# A2 uses PatternLayout.
+log4j.appender.A2.layout=org.apache.log4j.PatternLayout
+log4j.appender.A2.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%t] %c{1} %x - %m%n
+
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.properties
new file mode 100644
index 0000000..0a819e0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.properties
@@ -0,0 +1,5 @@
+Bundle-Vendor.0 = Eclipse.org
+Bundle-Name.0 = XSL JAXP Launching (Incubating)
+launchDelegate.name.0 = JAXP
+processorType.label.1 = JRE Default
+processor.label.1 = JRE Instance Default
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.xml b/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.xml
new file mode 100644
index 0000000..91e2643
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/plugin.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="debugger" name="debugger" schema="schema/debugger.exsd"/>
+   <extension-point id="invoke" name="invoke" schema="schema/invoke.exsd"/>
+   <extension-point id="processor" name="processor" schema="schema/processor.exsd"/>
+   <extension-point id="processorType" name="processorType" schema="schema/processorType.exsd"/>
+ <extension
+       point="org.eclipse.debug.core.launchDelegates">
+    <launchDelegate
+          delegate="org.eclipse.wst.xsl.jaxp.launching.internal.JAXPJavaLaunchConfigurationDelegate"
+          delegateDescription="The XSLT Launcher for JAXP supports running and debugging transformations using JAXP-compliant XSLT processors"
+          id="org.eclipse.wst.xsl.launching.internal.jaxp.JAXPLaunchConfigurationDelegate"
+          modes="run, debug"
+          name="%launchDelegate.name.0"
+          type="org.eclipse.wst.xsl.launching.launchConfigurationType">
+    </launchDelegate>    
+ </extension>
+     	
+	<extension point="org.eclipse.core.runtime.preferences">
+		<initializer
+			class="org.eclipse.wst.xsl.jaxp.launching.internal.PreferenceInitializer">
+		</initializer>
+	</extension>
+ 
+	<extension point="org.eclipse.wst.xsl.jaxp.launching.invoke">
+		<invoker id="org.eclipse.wst.xsl.launching.jaxp.invoke"
+			class="org.eclipse.wst.xsl.jaxp.debug.invoker.internal.JAXPSAXProcessorInvoker"
+			classpath="${eclipse_orbit:org.eclipse.wst.xsl.jaxp.debug};${eclipse_orbit:org.apache.commons.logging};${eclipse_orbit:org.apache.log4j}" />
+	</extension>
+
+  	<extension
+	       point="org.eclipse.wst.xsl.jaxp.launching.processorType">
+     <processorType
+            attributeProperties="JREDefaultAttributes.properties"
+            id="org.eclipse.wst.xsl.launching.processorType.jreDefault"
+            label="%processorType.label.1"
+            outputProperties="JREDefaultOutputProperties.properties" />
+	 </extension>
+
+	<extension
+	         point="org.eclipse.wst.xsl.jaxp.launching.processor">
+        <processor
+              classpath=""
+              id="org.eclipse.wst.xsl.launching.jre.default"
+              label="%processor.label.1"
+              processorTypeId="org.eclipse.wst.xsl.launching.processorType.jreDefault"
+              supports="1.0"/>
+	 </extension>
+ 
+</plugin>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/debugger.exsd b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/debugger.exsd
new file mode 100644
index 0000000..672af9e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/debugger.exsd
@@ -0,0 +1,125 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.wst.xsl.launching.jaxp" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.wst.xsl.launching.jaxp" id="debugger" name="XSLT Debugger"/>
+      </appinfo>
+      <documentation>
+         &lt;b&gt;This extension point is internal and should not be used by any other plugins.&lt;/b&gt;
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="debugger" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="debugger">
+      <complexType>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="classpath" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="processorTypeId" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="className" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="transformerFactoryClass" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn="javax.xml.transform.TransformerFactory:"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         &lt;b&gt;This extension point is internal and should not be used by any other plugins.&lt;/b&gt;
+      </documentation>
+   </annotation>
+
+
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2007 Chase Technology Ltd - &lt;a href=&quot;http://www.chasetechnology.co.uk&quot;&gt;http://www.chasetechnology.co.uk&lt;/a&gt;.&lt;br&gt;
+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 &lt;a
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/invoke.exsd b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/invoke.exsd
new file mode 100644
index 0000000..2707e22
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/invoke.exsd
@@ -0,0 +1,101 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.wst.xsl.launching.jaxp" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.wst.xsl.launching.jaxp" id="invoke" name="XSLT Processor Invoker"/>
+      </appinfo>
+      <documentation>
+         &lt;b&gt;This extension point is internal and should not be used by any other plugins.&lt;/b&gt;
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="invoker"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="invoker">
+      <complexType>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Unique id for this invoker
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A class that implements the IProcessorInvoker interface
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="classpath" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A semi-colon separated list of jars relative to the root of the contributing plugin. One of the jars must contain the Invoker class named in the class attribute.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         &lt;b&gt;This extension point is internal and should not be used by any other plugins.&lt;/b&gt;
+      </documentation>
+   </annotation>
+
+
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2007 Chase Technology Ltd - &lt;a href=&quot;http://www.chasetechnology.co.uk&quot;&gt;http://www.chasetechnology.co.uk&lt;/a&gt;.&lt;br&gt;
+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 &lt;a
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processor.exsd b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processor.exsd
new file mode 100644
index 0000000..e0c1e2e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processor.exsd
@@ -0,0 +1,142 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.wst.xsl.launching.jaxp" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.wst.xsl.launching.jaxp" id="processor" name="XSLT Processor"/>
+      </appinfo>
+      <documentation>
+         Contribute a Java XSLT processor instance (e.g. Xalan 2.7.0). The extension point primarily defines the classpath to be used when launching an XSLT transformation.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="processor" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="processor">
+      <annotation>
+         <appinfo>
+            <meta.element labelAttribute="label"/>
+         </appinfo>
+      </annotation>
+      <complexType>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="label" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="processorTypeId" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="classpath" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="debuggerId" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="supports" type="string" use="required">
+            <annotation>
+               <documentation>
+                  A comma-separated list of supported XSLT versions e.g. 1.0,2.0
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         &lt;pre&gt;
+   &lt;extension
+         point=&quot;org.eclipse.wst.xsl.launching.processor&quot;&gt;
+      &lt;processor
+            classpath=&quot;xalan2.7.0.jar;serializer2.7.0.jar&quot;
+            id=&quot;org.eclipse.wst.xsl.launching.xalan.2_7_0&quot;
+            label=&quot;Xalan 2.7.0&quot;
+            processorTypeId=&quot;org.eclipse.wst.xsl.xalan.processorType&quot;
+            debuggerId=&quot;org.eclipse.wst.xsl.xalan.debugger&quot;
+            supports=&quot;1.0&quot;&gt;
+      &lt;/processor&gt;
+   &lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2007 Chase Technology Ltd - &lt;a href=&quot;http://www.chasetechnology.co.uk&quot;&gt;http://www.chasetechnology.co.uk&lt;/a&gt;.&lt;br&gt;
+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 &lt;a
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processorType.exsd b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processorType.exsd
new file mode 100644
index 0000000..b48eb2d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/schema/processorType.exsd
@@ -0,0 +1,160 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.wst.xsl.launching.jaxp" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.wst.xsl.launching.jaxp" id="processorType" name="XSLT Processor Type"/>
+      </appinfo>
+      <documentation>
+         Contribute a Java XSLT processor type (e.g. Xalan, Saxon). The processor type defines which JAXP attributes and output properies are supported.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="processorType" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="processorType">
+      <annotation>
+         <appinfo>
+            <meta.element labelAttribute="label"/>
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="transformerFactory" minOccurs="0" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Unique id for the processor type
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="label" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Name for display in the UI
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="outputProperties" type="string">
+            <annotation>
+               <documentation>
+                  Location of a properties file containing the list of the processors output properties. Must be a path relative to the root of the bundle.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="attributeProperties" type="string">
+            <annotation>
+               <documentation>
+                  Location of a properties file containing the list of the attributes supported by this processor. Must be a path relative to the root of the bundle.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="transformerFactory">
+      <annotation>
+         <documentation>
+            A TransformerFactory for this type
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="factoryClass" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The fully-qualified transformer factory class
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn="javax.xml.transform.TransformerFactory:"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         &lt;pre&gt;
+   &lt;extension
+         point=&quot;org.eclipse.wst.xsl.launching.processorType&quot;&gt;
+      &lt;processorType
+            attributeProperties=&quot;XalanAttributes.properties&quot;
+            id=&quot;org.eclipse.wst.xsl.xalan.processorType&quot;
+            label=&quot;Xalan&quot;
+            outputProperties=&quot;XalanOutputProperties.properties&quot;
+            transformerFactory=&quot;org.apache.xalan.processor.TransformerFactoryImpl&quot;&gt;
+      &lt;/processorType&gt;
+   &lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2007 Chase Technology Ltd - &lt;a href=&quot;http://www.chasetechnology.co.uk&quot;&gt;http://www.chasetechnology.co.uk&lt;/a&gt;.&lt;br&gt;
+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 &lt;a
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IAttribute.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IAttribute.java
new file mode 100644
index 0000000..467914b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IAttribute.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * A attribute supported by an XSLT processor. 
+ * 
+ * @author Doug Satchwell
+ */
+public interface IAttribute
+{
+	/**
+	 * Constant for attributes of type <code>string</code>
+	 * @see #getType()
+	 */
+	String TYPE_STRING = "string"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>boolean</code>
+	 * @see #getType()
+	 */
+	String TYPE_BOOLEAN = "boolean"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>int</code>
+	 * @see #getType()
+	 */
+	String TYPE_INT = "int"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>double</code>
+	 * @see #getType()
+	 */
+	String TYPE_DOUBLE = "double"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>float</code>
+	 * @see #getType()
+	 */
+	String TYPE_FLOAT = "float"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>class</code>
+	 * @see #getType()
+	 */
+	String TYPE_CLASS = "class"; //$NON-NLS-1$
+	
+	/**
+	 * Constant for attributes of type <code>object</code>
+	 * @see #getType()
+	 */
+	String TYPE_OBJECT = "object"; //$NON-NLS-1$
+
+	/**
+	 * Get the URI for this attribute
+	 * @return the attribute URI
+	 */
+	String getURI();
+
+	/**
+	 * Get a description for this attribute
+	 * @return the attribute description
+	 */
+	String getDescription();
+
+	/**
+	 * Get the type of this attribute. Will match one of the TYPE constants in this interface.
+	 * @return the attribute type: one of <code>TYPE_STRING</code>, <code>TYPE_BOOLEAN</code>, 
+	 * <code>TYPE_INT</code>, <code>TYPE_DOUBLE</code>, <code>TYPE_FLOAT</code>, <code>TYPE_CLASS</code>, 
+	 * or <code>TYPE_OBJECT</code>
+	 */
+	String getType();
+
+	/**
+	 * Determine whether the given value is a valid one for this attribute.
+	 * @return an <code>IStatus</code> with severity <code>OK</code> if valid, or <code>ERROR</code> if invalid.
+	 */
+	IStatus validateValue(String value);
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IDebugger.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IDebugger.java
new file mode 100644
index 0000000..5502f95
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IDebugger.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+/**
+ * An XSLT debugger. Typically this will have been 
+ * contributed via the <code>org.eclipse.wst.xsl.launching.debugger</code> extension point.
+ * 
+ * @author Doug Satchwell
+ */
+public interface IDebugger
+{
+	/**
+	 * Get the unique id for this debugger.
+	 * @return debugger id
+	 */
+	String getId();
+
+	/**
+	 * Get the set of bundle-relative jar files to add to the classpath. 
+	 * @return array of bundle-relative jars
+	 */
+	String[] getClassPath();
+
+	/**
+	 * Get a unique name for this debugger
+	 * @return the name for the debugger
+	 */
+	String getName();
+
+	/**
+	 * Get the processor type that this debugger is associated with
+	 * @return the processor type
+	 */
+	IProcessorType getProcessorType();
+
+	/**
+	 * Get the class name for this debugger
+	 * @return the class name
+	 */
+	String getClassName();
+	
+	/**
+	 * Get the transformer factory this debugger is associated with
+	 * @return the transformer factory
+	 */
+	String getTransformerFactory();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IOutputProperty.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IOutputProperty.java
new file mode 100644
index 0000000..9bd2c76
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IOutputProperty.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+/**
+ * An output property supported by an XSLT processor. 
+ * 
+ * @author Doug Satchwell
+ */
+public interface IOutputProperty
+{
+	/**
+	 * Get the URI of this output property. 
+	 * @return a unique URI
+	 */
+	String getURI();
+
+	/**
+	 * Get a description for this output property. 
+	 * @return a description
+	 */
+	String getDescription();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInstall.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInstall.java
new file mode 100644
index 0000000..4cab27b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInstall.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+/**
+ * An instance of an XSLT processor (e.g. Xalan 2.7.0).
+ * 
+ * @see IProcessorInstall
+ * @author Doug Satchwell
+ */
+public interface IProcessorInstall
+{
+	/**
+	 * Get the unqiue id of this install
+	 * @return the unique id
+	 */
+	String getId();
+
+	/**
+	 * Get the name of this install
+	 * @return the name of this install
+	 */
+	String getName();
+
+	/**
+	 * Get the the processor type associated with this install
+	 * @return the processor type id
+	 */
+	IProcessorType getProcessorType();
+
+	/**
+	 * Get the jar files for this processor
+	 * @return a set of jar files
+	 */
+	IProcessorJar[] getProcessorJars();
+
+	/**
+	 * Get whether this install has been contributed via the <code>org.eclipse.wst.xsl.launching.processor</code> extension point.
+	 * @return <code>true</code> if contributed via the extension point, otherwise <code>false</code>.
+	 */
+	boolean isContributed();
+
+	/**
+	 * Get the list of supported XSLT versions
+	 * @return <code>true</code> if this install has a debugger, otherwise <code>false</code>.
+	 */
+	// TODO deprecate and use boolean supports instaed
+	String getSupports();
+
+	/**
+	 * Get whether this install supports the specified xslt version.
+	 * @return <code>true</code> if this install supports the version, otherwise <code>false</code>.
+	 */
+	boolean supports(String xsltVersion);
+
+	/**
+	 * Get the debugger associated with this install
+	 * @return the debugger, or null if no debugger has been set
+	 */
+	IDebugger getDebugger();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInvoker.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInvoker.java
new file mode 100644
index 0000000..540101a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorInvoker.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+public interface IProcessorInvoker
+{
+	String getId();
+
+	String getInvokerClassName();
+
+	String[] getClasspathEntries();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorJar.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorJar.java
new file mode 100644
index 0000000..53052bb
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorJar.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * A jar file for an XSLT processor
+ * 
+ * @see IProcessorInstall
+ * @author Doug Satchwell
+ */
+public interface IProcessorJar
+{
+	/**
+	 * The path may be relative or absolute; in the workspace or external.
+	 * @return the path to this jar
+	 */
+	IPath getPath();
+
+	/**
+	 * The URL will always be absolute and can be opened.
+	 * @return a URL to the jar
+	 */
+	URL asURL();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorType.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorType.java
new file mode 100644
index 0000000..d13e700
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/IProcessorType.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.util.Map;
+
+/**
+ * A particular type of XSLT Processor (e.g. Xalan) for which there may be any number of installs.
+ * 
+ * @see IProcessorInstall
+ * @author Doug Satchwell
+ */
+public interface IProcessorType
+{
+	String getId();
+
+	String getLabel();
+
+	boolean isJREDefault();
+
+	ITransformerFactory[] getTransformerFactories();
+
+	IAttribute[] getAttributes();
+
+	Map<String, String> getAttributeValues();
+
+	IOutputProperty[] getOutputProperties();
+
+	Map<String, String> getOutputPropertyValues();
+
+	ITransformerFactory getDefaultTransformerFactory();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ITransformerFactory.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ITransformerFactory.java
new file mode 100644
index 0000000..64716ab
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ITransformerFactory.java
@@ -0,0 +1,7 @@
+package org.eclipse.wst.xsl.jaxp.launching;
+
+public interface ITransformerFactory
+{
+	String getName();
+	String getFactoryClass();
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPLaunchConfigurationConstants.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPLaunchConfigurationConstants.java
new file mode 100644
index 0000000..a1cf82d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPLaunchConfigurationConstants.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+
+public class JAXPLaunchConfigurationConstants
+{
+	public static final String INVOKER_DESCRIPTOR = JAXPLaunchingPlugin.PLUGIN_ID + ".INVOKER_DESCRIPTOR"; //$NON-NLS-1$
+	public static final String ATTR_PROCESSOR = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_PROCESSOR"; //$NON-NLS-1$	
+	public static final String ATTR_OUTPUT_PROPERTIES = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_OUTPUT_PROPERTIES"; //$NON-NLS-1$
+	public static final String ATTR_ATTRIBUTES = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_ATTRIBUTES"; //$NON-NLS-1$
+	public static final String ATTR_DEFAULT_DEBUGGING_INSTALL_ID = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_DEFAULT_DEBUGGING_INSTALL_ID"; //$NON-NLS-1$
+	public static final String ATTR_USE_DEFAULT_PROCESSOR = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_USE_DEFAULT_PROCESSOR"; //$NON-NLS-1$
+	public static final String ATTR_TRANSFORMER_FACTORY = JAXPLaunchingPlugin.PLUGIN_ID + ".ATTR_TRANSFORMER_FACTORY";
+
+	public static final String XALAN_TYPE_ID = "org.eclipse.wst.xsl.xalan.processorType"; //$NON-NLS-1$
+	public static final String SAXON_TYPE_ID = "org.eclipse.wst.xsl.saxon.processorType"; //$NON-NLS-1$
+	public static final String SAXON_1_0_TYPE_ID = "org.eclipse.wst.xsl.saxon_1_0.processorType"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPRuntime.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPRuntime.java
new file mode 100644
index 0000000..ba1dd11
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/JAXPRuntime.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.wst.xsl.jaxp.launching.internal.FeaturePreferences;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.internal.OutputPropertyPreferences;
+import org.eclipse.wst.xsl.jaxp.launching.internal.ProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.internal.ProcessorPreferences;
+import org.eclipse.wst.xsl.jaxp.launching.internal.registry.DebuggerRegistry;
+import org.eclipse.wst.xsl.jaxp.launching.internal.registry.InvokerRegistry;
+import org.eclipse.wst.xsl.jaxp.launching.internal.registry.ProcessorRegistry;
+import org.eclipse.wst.xsl.jaxp.launching.internal.registry.ProcessorTypeRegistry;
+
+public class JAXPRuntime
+{
+	public static final String PREF_PROCESSOR_XML = "PREF_PROCESSOR_XML"; //$NON-NLS-1$
+	public static final String PREF_FEATURE_XML = "PREF_FEATURE_XML"; //$NON-NLS-1$
+	public static final String PREF_OUTPUT_PROPERTIES_XML = "PREF_OUTPUT_PROPERTIES_XML"; //$NON-NLS-1$
+	public static final String JRE_DEFAULT_PROCESSOR_ID = "org.eclipse.wst.xsl.launching.jre.default"; //$NON-NLS-1$
+	public static final String JRE_DEFAULT_PROCESSOR_TYPE_ID = "org.eclipse.wst.xsl.launching.processorType.jreDefault"; //$NON-NLS-1$
+
+	private static byte[] NEXT_ID_LOCK = new byte[0];
+	private static byte[] REGISTRY_LOCK = new byte[0];
+
+	private static int lastStandinID;
+	private static ProcessorTypeRegistry processorTypeRegistry;
+	private static ProcessorRegistry processorRegistry;
+	private static InvokerRegistry invokerRegistry;
+	private static DebuggerRegistry debuggerRegistry;
+
+	private static ProcessorTypeRegistry getProcessorTypeRegistry()
+	{
+		synchronized (REGISTRY_LOCK)
+		{
+			if (processorTypeRegistry == null)
+				processorTypeRegistry = new ProcessorTypeRegistry();
+		}
+		return processorTypeRegistry;
+	}
+
+	public static ProcessorRegistry getProcessorRegistry()
+	{
+		synchronized (REGISTRY_LOCK)
+		{
+			if (processorRegistry == null)
+				processorRegistry = new ProcessorRegistry();
+		}
+		return processorRegistry;
+	}
+
+	private static InvokerRegistry getInvokerRegistry()
+	{
+		synchronized (REGISTRY_LOCK)
+		{
+			if (invokerRegistry == null)
+				invokerRegistry = new InvokerRegistry();
+		}
+		return invokerRegistry;
+	}
+
+	private static DebuggerRegistry getDebuggerRegistry()
+	{
+		synchronized (REGISTRY_LOCK)
+		{
+			if (debuggerRegistry == null)
+				debuggerRegistry = new DebuggerRegistry();
+		}
+		return debuggerRegistry;
+	}
+	
+	private static void savePreferences()
+	{
+		JAXPLaunchingPlugin.getDefault().savePluginPreferences();
+		synchronized (REGISTRY_LOCK)
+		{
+			// force the registries to be re-initialised next time it is required
+			processorRegistry = null;
+			processorTypeRegistry = null;
+		}
+	}
+
+	/**
+	 * Find a unique processor install id. Check existing 'real' processors, as
+	 * well as the last id used for a standin.
+	 */
+	public static String createUniqueProcessorId(IProcessorType type)
+	{
+		IProcessorInstall[] installs = JAXPRuntime.getProcessors(type.getId());
+		String id = null;
+		synchronized (NEXT_ID_LOCK)
+		{
+			do
+			{
+				id = String.valueOf(++lastStandinID);
+			}
+			while (isTaken(id, installs));
+		}
+		return id;
+	}
+
+	public static IProcessorJar createProcessorJar(IPath path)
+	{
+		return new ProcessorJar(path);
+	}
+
+	private static boolean isTaken(String id, IProcessorInstall[] installs)
+	{
+		for (IProcessorInstall install : installs)
+		{
+			if (install.getId().equals(id))
+				return true;
+		}
+		return false;
+	}
+
+	public static IDebugger[] getDebuggers()
+	{
+		return getDebuggerRegistry().getDebuggers();
+	}
+
+	public static IDebugger getDebugger(String id)
+	{
+		return getDebuggerRegistry().getDebugger(id);
+	}
+
+	public static IProcessorInstall[] getProcessors()
+	{
+		return getProcessorRegistry().getProcessors();
+	}
+
+	public static IProcessorInstall[] getProcessors(String typeId)
+	{
+		return getProcessorRegistry().getProcessors(typeId);
+	}
+
+	public static IProcessorInstall getProcessor(String processorId)
+	{
+		IProcessorInstall[] processors = getProcessors();
+		for (IProcessorInstall install : processors)
+		{
+			if (install.getId().equals(processorId))
+				return install;
+		}
+		return null;
+	}
+
+	public static IProcessorInstall getDefaultProcessor()
+	{
+		return getProcessorRegistry().getDefaultProcessor();
+	}
+
+	public static IProcessorInstall getJREDefaultProcessor()
+	{
+		return getProcessorRegistry().getJREDefaultProcessor();
+	}
+
+	public static IProcessorType[] getProcessorTypes()
+	{
+		return getProcessorTypeRegistry().getProcessorTypes();
+	}
+
+	public static IProcessorType[] getProcessorTypesExclJREDefault()
+	{
+		return getProcessorTypeRegistry().getProcessorTypesExclJREDefault();
+	}
+
+	public static IProcessorType getProcessorType(String id)
+	{
+		return getProcessorTypeRegistry().getProcessorType(id);
+	}
+
+	public static IProcessorInvoker getProcessorInvoker(String invokerId)
+	{
+		return getInvokerRegistry().getProcessorInvoker(invokerId);
+	}
+
+	public static IProcessorInvoker[] getProcessorInvokers()
+	{
+		return getInvokerRegistry().getProcessorInvokers();
+	}
+
+	private static Preferences getPreferences()
+	{
+		return JAXPLaunchingPlugin.getDefault().getPluginPreferences();
+	}
+
+	public static void saveFeaturePreferences(Map<IProcessorType, Map<String, String>> typeFeatures, IProgressMonitor monitor) throws CoreException
+	{
+		if (monitor.isCanceled())
+			return;
+		try
+		{
+			monitor.beginTask(Messages.getString("XSLTRuntime.5"), 100); //$NON-NLS-1$
+			FeaturePreferences prefs = new FeaturePreferences();
+			Map<String,Map<String,String>> typeIdFeatures = new HashMap<String,Map<String,String>>(typeFeatures.size());
+			for (IProcessorType type : typeFeatures.keySet())
+			{
+				Map<String,String> values = typeFeatures.get(type);
+				typeIdFeatures.put(type.getId(), values);
+			}
+			prefs.setTypeFeatures(typeIdFeatures);
+			String xml = prefs.getAsXML();
+			monitor.worked(40);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.getPreferences().setValue(JAXPRuntime.PREF_FEATURE_XML, xml);
+			monitor.worked(30);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.savePreferences();
+			monitor.worked(30);
+		}
+		catch (Exception e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR,JAXPLaunchingPlugin.PLUGIN_ID,Messages.getString("XSLTRuntime.6"),e)); //$NON-NLS-1$
+		}
+		finally
+		{
+			monitor.done();
+		}
+	}
+
+	public static void saveOutputPropertyPreferences(Map<IProcessorType, Map<String,String>> typeProperties, IProgressMonitor monitor) throws CoreException
+	{
+		if (monitor.isCanceled())
+			return;
+		try
+		{
+			monitor.beginTask(Messages.getString("XSLTRuntime.7"), 100); //$NON-NLS-1$
+			OutputPropertyPreferences prefs = new OutputPropertyPreferences();
+			for (IProcessorType type : typeProperties.keySet())
+			{
+				prefs.setOutputPropertyValues(type.getId(), typeProperties.get(type));
+			}
+			String xml = prefs.getAsXML();
+			monitor.worked(40);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.getPreferences().setValue(JAXPRuntime.PREF_OUTPUT_PROPERTIES_XML, xml);
+			monitor.worked(30);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.savePreferences();
+			monitor.worked(30);
+		}
+		catch (Exception e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR,JAXPLaunchingPlugin.PLUGIN_ID,Messages.getString("XSLTRuntime.8"),e)); //$NON-NLS-1$
+		}
+		finally
+		{
+			monitor.done();
+		}
+	}
+
+	public static void saveProcessorPreferences(IProcessorInstall[] installs, IProcessorInstall defaultInstall, IProgressMonitor monitor) throws CoreException
+	{
+		if (monitor.isCanceled())
+			return;
+		try
+		{
+			monitor.beginTask(Messages.getString("XSLTRuntime.9"), 100); //$NON-NLS-1$
+			ProcessorPreferences prefs = new ProcessorPreferences();
+			if (defaultInstall != null)
+				prefs.setDefaultProcessorId(defaultInstall.getId());
+			prefs.setProcessors(new ArrayList<IProcessorInstall>(Arrays.asList(installs)));
+			String xml = prefs.getAsXML();
+			monitor.worked(40);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.getPreferences().setValue(JAXPRuntime.PREF_PROCESSOR_XML, xml);
+			monitor.worked(30);
+			if (monitor.isCanceled())
+				return;
+			JAXPRuntime.savePreferences();
+			monitor.worked(30);
+		}
+		catch (Exception e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR,JAXPLaunchingPlugin.PLUGIN_ID,Messages.getString("XSLTRuntime.10"),e)); //$NON-NLS-1$
+		}
+		finally
+		{
+			monitor.done();
+		}
+	}
+
+	public static Map<String,String> createDefaultOutputProperties(String typeId)
+	{
+		Map<String,String> props = new HashMap<String,String>();
+		if (JRE_DEFAULT_PROCESSOR_TYPE_ID.equals(typeId))
+			props.put("indent", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
+		else if (JAXPLaunchConfigurationConstants.XALAN_TYPE_ID.equals(typeId))
+		{
+			props.put("indent", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
+			props.put("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		else if (JAXPLaunchConfigurationConstants.SAXON_TYPE_ID.equals(typeId))
+		{
+			props.put("indent", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
+			props.put("{http://saxon.sf.net/}indent-spaces", "4"); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		else if (JAXPLaunchConfigurationConstants.SAXON_1_0_TYPE_ID.equals(typeId))
+		{
+			props.put("indent", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
+			props.put("{http://saxon.sf.net/}indent-spaces", "4"); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		return props;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchAttributes.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchAttributes.java
new file mode 100644
index 0000000..a23335b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchAttributes.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.xsl.launching.config.LaunchAttribute;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class LaunchAttributes
+{
+	private final Set<LaunchAttribute> attributes = new HashSet<LaunchAttribute>();
+
+	public Set<LaunchAttribute> getAttributes()
+	{
+		return attributes;
+	}
+
+	public void addAttribute(LaunchAttribute attribute)
+	{
+		attributes.add(attribute);
+	}
+
+	public LaunchAttribute getAttribute(String uri)
+	{
+		for (Iterator<LaunchAttribute> iter = attributes.iterator(); iter.hasNext();)
+		{
+			LaunchAttribute tv = (LaunchAttribute) iter.next();
+			if (tv.uri.equals(uri))
+				return tv;
+		}
+		return null;
+	}
+
+	public void removeAtribute(String uri)
+	{
+		for (Iterator<LaunchAttribute> iter = attributes.iterator(); iter.hasNext();)
+		{
+			LaunchAttribute attribute = (LaunchAttribute) iter.next();
+			if (attribute.uri.equals(uri))
+				iter.remove();
+		}
+	}
+
+	public String toXML() throws ParserConfigurationException, IOException, TransformerException
+	{
+		Document doc = PreferenceUtil.getDocument();
+
+		Element attributesEl = doc.createElement("Attributes"); //$NON-NLS-1$
+		doc.appendChild(attributesEl);
+
+		for (Iterator<LaunchAttribute> iter = attributes.iterator(); iter.hasNext();)
+		{
+			LaunchAttribute attribute = (LaunchAttribute) iter.next();
+			Element attributeEl = doc.createElement("Attribute"); //$NON-NLS-1$
+			attributeEl.setAttribute("name", attribute.uri); //$NON-NLS-1$
+			attributeEl.setAttribute("type", attribute.type); //$NON-NLS-1$
+			attributeEl.setAttribute("value", attribute.value); //$NON-NLS-1$
+			attributesEl.appendChild(attributeEl);
+		}
+
+		return PreferenceUtil.serializeDocument(doc);
+	}
+
+	public static LaunchAttributes fromXML(InputStream inputStream) throws CoreException
+	{
+		Document doc = PreferenceUtil.getDocument(inputStream);
+
+		LaunchAttributes pdef = new LaunchAttributes();
+
+		Element attributesEl = doc.getDocumentElement();
+
+		NodeList attributeEls = attributesEl.getElementsByTagName("Attribute"); //$NON-NLS-1$
+		for (int i = 0; i < attributeEls.getLength(); i++)
+		{
+			Element attributeEl = (Element) attributeEls.item(i);
+			String name = attributeEl.getAttribute("name"); //$NON-NLS-1$
+			String type = attributeEl.getAttribute("type"); //$NON-NLS-1$
+			String value = attributeEl.getAttribute("value"); //$NON-NLS-1$
+			pdef.addAttribute(new LaunchAttribute(name, type, value));
+		}
+
+		return pdef;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchProperties.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchProperties.java
new file mode 100644
index 0000000..d999eb1
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/LaunchProperties.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class LaunchProperties
+{
+	private final Map<String, String> properties = new HashMap<String, String>();
+
+	public Map<String, String> getProperties()
+	{
+		return properties;
+	}
+
+	public void setProperty(String name, String value)
+	{
+		properties.put(name, value);
+	}
+
+	public String getProperty(String name)
+	{
+		return (String) properties.get(name);
+	}
+
+	public void removeProperty(String name)
+	{
+		properties.remove(name);
+	}
+
+	public String toXML() throws ParserConfigurationException, IOException, TransformerException
+	{
+		Document doc = PreferenceUtil.getDocument();
+
+		Element propertysEl = doc.createElement("Properties"); //$NON-NLS-1$
+		doc.appendChild(propertysEl);
+
+		for (Map.Entry<String, String> property : properties.entrySet())
+		{
+			String name = property.getKey();
+			String value = property.getValue();
+			Element propertyEl = doc.createElement("Property"); //$NON-NLS-1$
+			propertyEl.setAttribute("name", name); //$NON-NLS-1$
+			propertyEl.setAttribute("value", value); //$NON-NLS-1$
+			propertysEl.appendChild(propertyEl);
+		}
+
+		return PreferenceUtil.serializeDocument(doc);
+	}
+
+	public static LaunchProperties fromXML(InputStream inputStream) throws CoreException
+	{
+		Document doc = PreferenceUtil.getDocument(inputStream);
+
+		LaunchProperties pdef = new LaunchProperties();
+
+		Element propertysEl = doc.getDocumentElement();
+
+		NodeList propertyEls = propertysEl.getElementsByTagName("Property"); //$NON-NLS-1$
+		for (int i = 0; i < propertyEls.getLength(); i++)
+		{
+			Element propertyEl = (Element) propertyEls.item(i);
+			String name = propertyEl.getAttribute("name"); //$NON-NLS-1$
+			String value = propertyEl.getAttribute("value"); //$NON-NLS-1$
+			pdef.setProperty(name, value);
+		}
+
+		return pdef;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/Messages.java
new file mode 100644
index 0000000..d454fb5
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/Messages.java
@@ -0,0 +1,22 @@
+package org.eclipse.wst.xsl.jaxp.launching;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.launching.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private Messages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ProcessorInstall.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ProcessorInstall.java
new file mode 100644
index 0000000..6ee8717
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/ProcessorInstall.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching;
+
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.internal.PluginProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.internal.Utils;
+
+public class ProcessorInstall implements IProcessorInstall
+{
+	private final String id;
+	private String name;
+	private String type;
+	private IProcessorJar[] jars;
+	private final boolean contributed;
+	private String debuggerId;
+	private String supports;
+
+	public ProcessorInstall(String id, String label, String typeId, IProcessorJar[] jars, String debuggerId, String supports, boolean contributed)
+	{
+		this.id = id;
+		name = label;
+		type = typeId;
+		this.debuggerId = debuggerId;
+		this.contributed = contributed;
+		this.jars = jars;
+		this.supports = supports;
+	}
+
+	public String getId()
+	{
+		return id;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+
+	public IProcessorJar[] getProcessorJars()
+	{
+		return jars;
+	}
+
+	public void setProcessorJars(IProcessorJar[] jars)
+	{
+		this.jars = jars;
+	}
+
+	public String getProcessorTypeId()
+	{
+		return type;
+	}
+
+	public IProcessorType getProcessorType()
+	{
+		return JAXPRuntime.getProcessorType(type);
+	}
+
+	public void setProcessorTypeId(String id)
+	{
+		type = id;
+	}
+
+	public boolean isContributed()
+	{
+		return contributed;
+	}
+
+	public static IProcessorJar[] createJars(String bundleId, String classpath)
+	{
+		IProcessorJar[] jars;
+		if (classpath == null)
+			return new IProcessorJar[0];
+		String[] jarstring = classpath.split(";"); //$NON-NLS-1$
+		jars = new IProcessorJar[jarstring.length];
+		for (int i = 0; i < jarstring.length; i++)
+		{
+			String jar = jarstring[i];
+			try
+			{
+				if (jar.startsWith("${eclipse_orbit:") && jar.endsWith("}")) //$NON-NLS-1$ //$NON-NLS-2$
+				{
+					jar = jar.substring("${eclipse_orbit:".length()); //$NON-NLS-1$
+					jar = jar.substring(0,jar.length()-1);
+					//jar = Utils.getFileLocation(jar,"");
+					jars[i] = new PluginProcessorJar(jar, null);
+				}
+				else
+				{
+					jar = Utils.getFileLocation(bundleId,jar);
+					jars[i] = new PluginProcessorJar(bundleId, new Path(jar));
+				}
+			}
+			catch (CoreException e)
+			{
+				JAXPLaunchingPlugin.log(e);
+			}
+		}
+		return jars;
+	}
+
+	public boolean hasDebugger()
+	{
+		return debuggerId != null;
+	}
+
+	public boolean supports(String xsltVersion)
+	{
+		return supports.indexOf(xsltVersion) >= 0;
+	}
+
+	public String getSupports()
+	{
+		return supports;
+	}
+
+	public void setSupports(String supports)
+	{
+		this.supports = supports;
+	}
+
+	public IDebugger getDebugger()
+	{
+		return JAXPRuntime.getDebugger(debuggerId);
+	}
+
+	public void setDebuggerId(String debuggerId)
+	{
+		this.debuggerId = debuggerId;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Attribute.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Attribute.java
new file mode 100644
index 0000000..7be3541
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Attribute.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.wst.xsl.jaxp.launching.IAttribute;
+
+public class Attribute implements IAttribute, Comparable<Object>
+{
+	private final String uri;
+	private final String description;
+	private final String type;
+
+	public Attribute(String uri, String type, String description)
+	{
+		this.uri = uri;
+		this.type = type;
+		this.description = description;
+	}
+
+	public String getDescription()
+	{
+		return description;
+	}
+
+	public String getType()
+	{
+		return type;
+	}
+
+	public String getURI()
+	{
+		return uri;
+	}
+
+	public IStatus validateValue(String value)
+	{
+		IStatus status = null;
+		if (TYPE_BOOLEAN.equals(type))
+		{
+			boolean valid = "true".equals(value) || "false".equals(value); //$NON-NLS-1$ //$NON-NLS-2$
+			if (!valid)
+				status = new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, 0, Messages.getString("Attribute.2"), null); //$NON-NLS-1$
+		}
+		else if (TYPE_INT.equals(type))
+		{
+			try
+			{
+				Integer.parseInt(value);
+			}
+			catch (NumberFormatException e)
+			{
+				status = new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, 0, Messages.getString("Attribute.1"), null); //$NON-NLS-1$
+			}
+		}
+		else if (TYPE_DOUBLE.equals(type))
+		{
+			try
+			{
+				Double.parseDouble(value);
+			}
+			catch (NumberFormatException e)
+			{
+				status = new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, 0, Messages.getString("Attribute.0"), null); //$NON-NLS-1$
+			}
+		}
+		else if (TYPE_FLOAT.equals(type))
+		{
+			try
+			{
+				Float.parseFloat(value);
+			}
+			catch (NumberFormatException e)
+			{
+				status = new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, 0, Messages.getString("Attribute.5"), null); //$NON-NLS-1$
+			}
+		}
+		else if (TYPE_CLASS.equals(type) || TYPE_OBJECT.equals(type))
+		{
+			//status = JavaConventions.validateJavaTypeName(value);
+		}
+		return status;
+	}
+
+	public int compareTo(Object o)
+	{
+		if (o instanceof IAttribute)
+		{
+			IAttribute f = (IAttribute) o;
+			return f.getURI().compareTo(getURI());
+		}
+		return 0;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/DebuggerDescriptor.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/DebuggerDescriptor.java
new file mode 100644
index 0000000..421dc71
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/DebuggerDescriptor.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import org.eclipse.wst.xsl.jaxp.launching.IDebugger;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class DebuggerDescriptor implements IDebugger
+{
+	private final String[] classpath;
+	private final String id;
+	private final String bundleId;
+	private final String name;
+	private final String processorTypeId;
+	private final String className;
+	private final String transformerFactory;
+
+	public DebuggerDescriptor(String id, String bundleId, String className, String[] classpath, String name, String processorTypeId, String transformerFactory)
+	{
+		this.id = id;
+		this.classpath = classpath;
+		this.bundleId = bundleId;
+		this.name = name;
+		this.processorTypeId = processorTypeId;
+		this.className = className;
+		this.transformerFactory = transformerFactory;
+	}
+
+	public String getClassName()
+	{
+		return className;
+	}
+
+	public String[] getClassPath()
+	{
+		return ProcessorInvokerDescriptor.createEntries(bundleId, classpath);
+	}
+
+	public String getId()
+	{
+		return id;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public IProcessorType getProcessorType()
+	{
+		return JAXPRuntime.getProcessorType(processorTypeId);
+	}
+
+	public String getTransformerFactory()
+	{
+		return transformerFactory;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/FeaturePreferences.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/FeaturePreferences.java
new file mode 100644
index 0000000..0a17c5f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/FeaturePreferences.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class FeaturePreferences
+{
+	private Map<String, Map<String, String>> typeFeatures;
+
+	public Map<String, String> getFeaturesValues(String typeId)
+	{
+		return typeFeatures.get(typeId);
+	}
+
+	public void setTypeFeatures(Map<String, Map<String, String>> typeFeatures)
+	{
+		this.typeFeatures = typeFeatures;
+	}
+
+	public String getAsXML() throws ParserConfigurationException, IOException, TransformerException
+	{
+		Document doc = PreferenceUtil.getDocument();
+		Element config = doc.createElement("featurePreferences");  //$NON-NLS-1$
+		doc.appendChild(config);
+		
+		for (String typeId : typeFeatures.keySet())
+		{
+			Element processorTypeElement = typeAsElement(doc, typeId);
+			Map<String, String> featureValues = typeFeatures.get(typeId);
+			featureValuesAsElement(doc, processorTypeElement, featureValues);
+			config.appendChild(processorTypeElement);
+		}
+
+		// Serialize the Document and return the resulting String
+		return PreferenceUtil.serializeDocument(doc);
+	}
+
+	public static FeaturePreferences fromXML(InputStream inputStream) throws CoreException
+	{
+		FeaturePreferences prefs = new FeaturePreferences();
+
+		// Do the parsing and obtain the top-level node
+		Document doc = PreferenceUtil.getDocument(inputStream);
+		Element config = doc.getDocumentElement();
+
+		Map<String, Map<String, String>> typeFeatures = new HashMap<String, Map<String, String>>();
+		Element[] processorTypeEls = PreferenceUtil.getChildElements(config, "processorType"); //$NON-NLS-1$
+		for (int i = 0; i < processorTypeEls.length; ++i)
+		{
+			Element processorTypeEl = processorTypeEls[i];
+			String type = elementAsType(processorTypeEl);
+			Map<String, String> featureValues = elementAsFeatureValues(processorTypeEl);
+			typeFeatures.put(type, featureValues);
+		}
+
+		prefs.setTypeFeatures(typeFeatures);
+
+		return prefs;
+	}
+
+	private static String elementAsType(Element parent)
+	{
+		String id = parent.getAttribute("id"); //$NON-NLS-1$
+		return id;
+	}
+
+	private static Element typeAsElement(Document doc, String type)
+	{
+		Element element = doc.createElement("processorType"); //$NON-NLS-1$
+		element.setAttribute("id", type); //$NON-NLS-1$
+		return element;
+	}
+
+	private static Map<String, String> elementAsFeatureValues(Element element)
+	{
+		Element[] featureEls = PreferenceUtil.getChildElements(element, "feature"); //$NON-NLS-1$
+		Map<String, String> featureValues = new HashMap<String, String>(featureEls.length);
+		for (Element featureEl : featureEls)
+		{
+			String uri = featureEl.getAttribute("uri"); //$NON-NLS-1$
+			String value = featureEl.getAttribute("value"); //$NON-NLS-1$
+			featureValues.put(uri, value);
+		}
+		return featureValues;
+	}
+
+	private static void featureValuesAsElement(Document doc, Element featuresEl, Map<String, String> featureValues)
+	{
+		if (featureValues != null)
+		{
+			for (Map.Entry<String,String> entry2 : featureValues.entrySet())
+			{
+				String uri = (String) entry2.getKey();
+				String value = (String) entry2.getValue();
+				Element element = doc.createElement("feature"); //$NON-NLS-1$
+				element.setAttribute("uri", uri); //$NON-NLS-1$
+				element.setAttribute("value", value); //$NON-NLS-1$
+				featuresEl.appendChild(element);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPJavaLaunchConfigurationDelegate.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPJavaLaunchConfigurationDelegate.java
new file mode 100644
index 0000000..24d890c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPJavaLaunchConfigurationDelegate.java
@@ -0,0 +1,443 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.jdt.launching.IVMRunner;
+import org.eclipse.jdt.launching.JavaLaunchDelegate;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.wst.xsl.jaxp.launching.IDebugger;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInvoker;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.launching.model.IXSLConstants;
+import org.eclipse.wst.xsl.launching.model.XSLDebugTarget;
+
+public class JAXPJavaLaunchConfigurationDelegate extends JavaLaunchDelegate implements IDebugEventSetListener
+{
+	private String mode;
+	LaunchHelper launchHelper;
+	
+	@Override
+	public synchronized void launch(ILaunchConfiguration configuration, final String mode, final ILaunch launch, IProgressMonitor monitor) throws CoreException
+	{
+		this.mode = mode;
+		launchHelper.save(getLaunchConfigFile());
+		
+		// set the launch name
+		IProcessorInstall install = getProcessorInstall(configuration, mode);
+		String tfactory = getTransformerFactory(install);
+		String name = install.getName();
+		if (tfactory != null)
+			name += "[" + tfactory + "]";
+		launch.setAttribute("launchName", name);
+
+		// the super.launch will add a Java source director if we set it to null here
+		final ISourceLocator configuredLocator = launch.getSourceLocator();
+		launch.setSourceLocator(null);
+
+		super.launch(configuration, mode, launch, monitor);
+		
+		// now get the java source locator
+		final ISourceLocator javaSourceLookupDirector = (ISourceLocator)launch.getSourceLocator();
+		// now add our own participant to the java director
+		launch.setSourceLocator(new ISourceLocator(){
+
+			public Object getSourceElement(IStackFrame stackFrame) 
+			{
+				// simply look at one and then the other
+				Object sourceElement = javaSourceLookupDirector.getSourceElement(stackFrame);
+				if (sourceElement == null)
+					sourceElement = configuredLocator.getSourceElement(stackFrame);
+				return sourceElement;
+			}});
+		
+//		IJavaDebugTarget javaTarget = (IJavaDebugTarget)launch.getDebugTarget();
+//		launch.removeDebugTarget(javaTarget);
+		
+		IDebugTarget javaTarget = launch.getDebugTarget();
+		IDebugTarget xslTarget = new XSLDebugTarget(launch, launch.getProcesses()[0], launchHelper);
+		
+		// remove java as the primary target and make xsl the primary target
+		launch.removeDebugTarget(javaTarget);
+		launch.addDebugTarget(xslTarget);
+		// add this here to make java the non-primary target
+	//	launch.addDebugTarget(javaTarget);
+		
+	//	launch.addDebugTarget(new JavaXSLDebugTarget(launch, launch.getProcesses()[0], launchHelper, javaTarget));
+		
+
+	}
+
+	/**
+	 * Get the Java breakpoint and the XSL breakpoints
+	 */
+	@Override
+	protected IBreakpoint[] getBreakpoints(ILaunchConfiguration configuration)
+	{
+		IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager();
+		if (!breakpointManager.isEnabled())
+			return null;
+		
+		IBreakpoint[] javaBreakpoints = super.getBreakpoints(configuration);
+		IBreakpoint[] xslBreakpoints = breakpointManager.getBreakpoints(IXSLConstants.ID_XSL_DEBUG_MODEL);
+		IBreakpoint[] breakpoints = new IBreakpoint[javaBreakpoints.length+xslBreakpoints.length];
+		System.arraycopy(javaBreakpoints, 0, breakpoints, 0, javaBreakpoints.length);
+		System.arraycopy(xslBreakpoints, 0, breakpoints, javaBreakpoints.length, xslBreakpoints.length);
+		
+		return breakpoints;
+	}
+
+	@Override
+	public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException
+	{
+		this.launchHelper = new LaunchHelper(configuration);
+		if (mode.equals(ILaunchManager.DEBUG_MODE))
+		{
+			// TODO don't like having UI code in the launching plugin...where else can it go?
+			final IProcessorInstall install = getProcessorInstall(configuration, ILaunchManager.RUN_MODE);
+			if (install.getDebugger() == null)
+			{
+				final boolean[] result = new boolean[]
+				{ false };
+				// open a dialog for choosing a different install that does have
+				// an associated debugger
+				PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+				{
+					public void run()
+					{
+						String debuggingInstallId = JAXPLaunchingPlugin.getDefault().getPluginPreferences().getString(JAXPLaunchConfigurationConstants.ATTR_DEFAULT_DEBUGGING_INSTALL_ID);
+						IProcessorInstall processor = JAXPRuntime.getProcessor(debuggingInstallId);
+
+						IWorkbenchWindow dw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+						
+						String title = Messages.getString("XSLTLaunchConfigurationDelegate.0"); //$NON-NLS-1$
+						String message = Messages.getString("XSLTLaunchConfigurationDelegate.1") + install.getName() + Messages.getString("XSLTLaunchConfigurationDelegate.2") //$NON-NLS-1$ //$NON-NLS-2$
+								+ Messages.getString("XSLTLaunchConfigurationDelegate.3") + processor.getName() + Messages.getString("XSLTLaunchConfigurationDelegate.4");//$NON-NLS-1$ //$NON-NLS-2$
+						
+						MessageDialog dialog = new MessageDialog(dw.getShell(), title, null, message, MessageDialog.QUESTION,
+								new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0); // yes is the default
+						
+				        result[0] = dialog.open() == 0;
+					}
+				});
+				return result[0];
+			}
+			else
+			{
+				String debuggerTF = install.getDebugger().getTransformerFactory();
+				String installTF = launchHelper.getTransformerFactory() == null ? null : launchHelper.getTransformerFactory().getFactoryClass();
+				if (!debuggerTF.equals(installTF))
+				{
+					PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+					{
+						public void run()
+						{
+							IWorkbenchWindow dw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+							
+							String title = Messages.getString("Change Transformer Factory");
+							String message = install.getName() + " must use the " + launchHelper.getTransformerFactory().getName() + " transformer factory when debugging.\n"
+									+ "Be aware that this may give different results to the " + launchHelper.getTransformerFactory().getName() + " transformer factory configured for this launch configuration.";
+							
+							MessageDialog dialog = new MessageDialog(dw.getShell(), title, null, message, MessageDialog.WARNING,
+									new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0); // yes is the default
+							dialog.open();
+						}
+					});
+				}
+			}
+		}
+		return super.preLaunchCheck(configuration, mode, monitor);
+	}
+
+	@Override
+	public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) throws CoreException
+	{
+		// comment this out in order to get java debugging as well as XSL debugging
+//		if (ILaunchManager.DEBUG_MODE.equals(mode))
+//			return super.getVMRunner(configuration, ILaunchManager.RUN_MODE);
+		return super.getVMRunner(configuration, mode);
+	}
+
+	private File getLaunchConfigFile()
+	{
+		IPath launchPath = Platform.getStateLocation(JAXPLaunchingPlugin.getDefault().getBundle()).append("launch"); //$NON-NLS-1$
+		File launchDir = launchPath.toFile();
+		if (!launchDir.exists())
+			launchDir.mkdir();
+		File file = new File(launchDir, "launch.xml"); //$NON-NLS-1$
+		return file;
+	}
+
+	@Override
+	public IPath getWorkingDirectoryPath(ILaunchConfiguration configuration) throws CoreException
+	{
+		// TODO changes are afoot so that working directory can be gotten from the Common launch tab
+		
+//		String path = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_PROCESSOR_WORKING_DIR, (String) null);
+//		if (path != null)
+//		{
+//			path = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(path);
+//			return new Path(path);
+//		}
+		return null;
+	}
+
+	private IProcessorInvoker getProcessorInvokerDescriptor(ILaunchConfiguration configuration) throws CoreException
+	{
+		String invokerId = configuration.getAttribute(JAXPLaunchConfigurationConstants.INVOKER_DESCRIPTOR, (String) null);
+		if (invokerId == null)
+			invokerId = "org.eclipse.wst.xsl.launching.jaxp.invoke"; //$NON-NLS-1$
+		return JAXPRuntime.getProcessorInvoker(invokerId);
+	}
+
+	public static IProcessorInstall getProcessorInstall(ILaunchConfiguration configuration, String mode) throws CoreException
+	{
+		IProcessorInstall install = LaunchHelper.getProcessorInstall(configuration);
+		if (mode.equals(ILaunchManager.DEBUG_MODE) && install.getDebugger() == null)
+		{
+			String debuggingInstallId = JAXPLaunchingPlugin.getDefault().getPluginPreferences().getString(JAXPLaunchConfigurationConstants.ATTR_DEFAULT_DEBUGGING_INSTALL_ID);
+			install = JAXPRuntime.getProcessor(debuggingInstallId);
+		}
+		return install;
+	}
+
+	@Override
+	public String getMainTypeName(ILaunchConfiguration configuration) throws CoreException
+	{
+		if (ILaunchManager.DEBUG_MODE.equals(mode))
+			return "org.eclipse.wst.xsl.jaxp.debug.debugger.DebugRunner"; //$NON-NLS-1$
+		return "org.eclipse.wst.xsl.jaxp.debug.invoker.internal.Main"; //$NON-NLS-1$
+	}
+
+	@Override
+	public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException
+	{
+		// classname, sourceurl, output file
+		IProcessorInvoker invoker = getProcessorInvokerDescriptor(configuration);
+		String clazz = invoker.getInvokerClassName();
+
+		StringBuffer sb = new StringBuffer();
+		sb.append(clazz);
+		sb.append(" "); //$NON-NLS-1$
+		sb.append("\"" + getLaunchConfigFile().getAbsolutePath() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append(" "); //$NON-NLS-1$
+		sb.append("\"" + launchHelper.getSource() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append(" "); //$NON-NLS-1$
+		sb.append("\"" + launchHelper.getTarget().getAbsolutePath() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+		if (ILaunchManager.DEBUG_MODE.equals(mode))
+		{
+			IProcessorInstall install = getProcessorInstall(configuration, mode);
+			if (install.getDebugger() != null)
+			{
+				IDebugger debugger = install.getDebugger();
+				String className = debugger.getClassName();
+				sb.append(" -debug ").append(className).append(" "); //$NON-NLS-1$ //$NON-NLS-2$
+				sb.append(launchHelper.getRequestPort());
+				sb.append(" ").append(launchHelper.getEventPort()); //$NON-NLS-1$
+				sb.append(" ").append(launchHelper.getGeneratePort()); //$NON-NLS-1$
+			}
+		}
+
+		return sb.toString();
+	}
+
+	@Override
+	public String[] getClasspath(ILaunchConfiguration configuration) throws CoreException
+	{
+		// get the classpath defined by the user
+		String[] userClasspath = super.getClasspath(configuration);
+
+		// get the classpath required for the transformation
+		IProcessorInvoker invoker = getProcessorInvokerDescriptor(configuration);
+		List<String> invokerCP = new ArrayList<String>();
+		for (String entry : invoker.getClasspathEntries())
+		{
+			invokerCP.add(entry);
+		}
+
+		// add the debugger...
+		IProcessorInstall install = getProcessorInstall(configuration, mode);
+		if (ILaunchManager.DEBUG_MODE.equals(mode) && install.getDebugger() != null)
+		{
+			String[] jars = install.getDebugger().getClassPath();
+			for (String jar : jars)
+			{
+				invokerCP.add(jar);
+			}
+		}
+
+		String[] invokerClasspath = (String[]) invokerCP.toArray(new String[0]);
+
+		// add them together
+		String[] classpath = new String[userClasspath.length + invokerClasspath.length];
+		System.arraycopy(invokerClasspath, 0, classpath, 0, invokerClasspath.length);
+		System.arraycopy(userClasspath, 0, classpath, invokerClasspath.length, userClasspath.length);
+
+		return classpath;
+	}
+
+	@Override
+	public String getVMArguments(ILaunchConfiguration configuration) throws CoreException
+	{
+		String vmargs = super.getVMArguments(configuration);
+
+		IProcessorInstall install = getProcessorInstall(configuration, mode);
+		if (install != null && !install.getProcessorType().isJREDefault())
+		{
+			// clear the endorsed dir
+			File tempDir = getEndorsedDir();
+			if (tempDir.exists())
+			{
+				File[] children = tempDir.listFiles();
+				for (File child : children)
+				{
+					child.delete();
+				}
+				tempDir.delete();
+			}
+			tempDir.mkdir();
+
+			// move the required jars to the endorsed dir
+			IProcessorJar[] jars = install.getProcessorJars();
+			for (int i = 0; i < jars.length; i++)
+			{
+				URL entry = jars[i].asURL();
+				if (entry == null)
+					throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("XSLTLaunchConfigurationDelegate.23") + jars[i], null)); //$NON-NLS-1$
+				File file = new File(tempDir, "END_" + i + ".jar"); //$NON-NLS-1$ //$NON-NLS-2$
+				moveFile(entry, file);
+			}
+			// add the endorsed dir
+			vmargs += " -Djava.endorsed.dirs=\"" + tempDir.getAbsolutePath() + "\""; //$NON-NLS-1$ //$NON-NLS-2$
+			
+			String tfactory = getTransformerFactory(install);
+			if (tfactory != null)
+				vmargs += " -Djavax.xml.transform.TransformerFactory=" + tfactory; //$NON-NLS-1$
+			
+			if (ILaunchManager.DEBUG_MODE.equals(mode))
+			{
+				// in debug mode, set the logging to ERROR. This prevents the console from popping up on top of the result view!
+				try
+				{
+					URL url = FileLocator.resolve(FileLocator.find(Platform.getBundle(JAXPLaunchingPlugin.PLUGIN_ID), new Path("/log4j.debug.properties"), null));
+					vmargs += " -Dlog4j.configuration=\""+url.toExternalForm()+"\""; //$NON-NLS-1$
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+		}
+		return vmargs;
+	}
+	
+	private String getTransformerFactory(IProcessorInstall install)
+	{
+		String tfactory = null;
+		if (ILaunchManager.DEBUG_MODE.equals(mode))
+			tfactory = install.getDebugger().getTransformerFactory();
+		else
+		{
+			ITransformerFactory t = launchHelper.getTransformerFactory();
+			if (t != null)
+				tfactory = t.getFactoryClass();
+		}
+		return tfactory;
+	}
+
+	private File getEndorsedDir()
+	{
+		IPath tempLocation = Platform.getStateLocation(JAXPLaunchingPlugin.getDefault().getBundle()).append("endorsed"); //$NON-NLS-1$
+		return tempLocation.toFile();
+	}
+
+	private static void moveFile(URL src, File target) throws CoreException
+	{
+		BufferedOutputStream bos = null;
+		BufferedInputStream bis = null;
+		try
+		{
+			bos = new BufferedOutputStream(new FileOutputStream(target));
+			bis = new BufferedInputStream(src.openStream());
+			while (bis.available() > 0)
+			{
+				int size = bis.available();
+				if (size > 1024)
+					size = 1024;
+				byte[] b = new byte[size];
+				bis.read(b, 0, b.length);
+				bos.write(b);
+			}
+		}
+		catch (IOException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("XSLTLaunchConfigurationDelegate.7") + src + Messages.getString("XSLTLaunchConfigurationDelegate.31") + target, e)); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		finally
+		{
+			if (bis != null)
+			{
+				try
+				{
+					bis.close();
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+			if (bos != null)
+			{
+				try
+				{
+					bos.close();
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPLaunchingPlugin.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPLaunchingPlugin.java
new file mode 100644
index 0000000..17ddda7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/JAXPLaunchingPlugin.java
@@ -0,0 +1,62 @@
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class JAXPLaunchingPlugin extends Plugin {
+
+	// The plug-in ID
+	public static final String PLUGIN_ID = "org.eclipse.wst.xsl.jaxp.launching";
+
+	// The shared instance
+	private static JAXPLaunchingPlugin plugin;
+	
+	/**
+	 * The constructor
+	 */
+	public JAXPLaunchingPlugin() {
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		plugin = this;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		plugin = null;
+		super.stop(context);
+	}
+
+	/**
+	 * Returns the shared instance
+	 *
+	 * @return the shared instance
+	 */
+	public static JAXPLaunchingPlugin getDefault() {
+		return plugin;
+	}
+
+	public static void log(Exception e)
+	{
+		getDefault().getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, 0, "", e)); //$NON-NLS-1$
+	}
+
+	public static void log(CoreException e)
+	{
+		getDefault().getLog().log(e.getStatus());
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/LaunchHelper.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/LaunchHelper.java
new file mode 100644
index 0000000..39a6392
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/LaunchHelper.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.PipelineDefinition;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.TransformDefinition;
+import org.eclipse.wst.xsl.jaxp.debug.invoker.TypedValue;
+import org.eclipse.wst.xsl.jaxp.launching.IAttribute;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchAttributes;
+import org.eclipse.wst.xsl.jaxp.launching.LaunchProperties;
+import org.eclipse.wst.xsl.launching.config.BaseLaunchHelper;
+import org.eclipse.wst.xsl.launching.config.LaunchAttribute;
+import org.eclipse.wst.xsl.launching.config.LaunchTransform;
+import org.eclipse.wst.xsl.launching.config.Messages;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+
+public class LaunchHelper extends BaseLaunchHelper
+{
+	private final LaunchAttributes attributes;
+	private final LaunchProperties outputProperties;
+	private final ITransformerFactory transformerFactory;
+
+	public LaunchHelper(ILaunchConfiguration configuration) throws CoreException
+	{
+		super(configuration);
+		attributes = hydrateAttributes(configuration);
+		outputProperties = hydrateOutputProperties(configuration);
+		transformerFactory = hydrateTransformerFactory(configuration);
+	}
+
+	public LaunchProperties getProperties()
+	{
+		return outputProperties;
+	}
+
+	public LaunchAttributes getAttributes()
+	{
+		return attributes;
+	}
+
+	public void save(File file) throws CoreException
+	{
+		BufferedWriter writer = null;
+		try
+		{
+			// ensure it exists
+			file.createNewFile();
+			writer = new BufferedWriter(new FileWriter(file));
+			PipelineDefinition pdef = new PipelineDefinition();
+			for (Iterator<?> iter = attributes.getAttributes().iterator(); iter.hasNext();)
+			{
+				LaunchAttribute att = (LaunchAttribute) iter.next();
+				pdef.addAttribute(new TypedValue(att.uri, TypedValue.TYPE_STRING, att.value));
+			}
+			for (Iterator<?> iter = pipeline.getTransformDefs().iterator(); iter.hasNext();)
+			{
+				LaunchTransform lt = (LaunchTransform) iter.next();
+				TransformDefinition tdef = new TransformDefinition();
+				URL url = pathToURL(lt.getLocation());
+				tdef.setStylesheetURL(url.toExternalForm());
+				tdef.setResolverClass(lt.getResolver());
+				for (Iterator<?> iterator = lt.getParameters().iterator(); iterator.hasNext();)
+				{
+					LaunchAttribute att = (LaunchAttribute) iterator.next();
+					tdef.addParameter(new TypedValue(att.uri, TypedValue.TYPE_STRING, att.getResolvedValue()));
+				}
+				// set the output props for the LAST transform only
+				if (!iter.hasNext())
+				{
+					for (Map.Entry<String, String> entry : outputProperties.getProperties().entrySet())
+					{
+						String name = entry.getKey();
+						String value = entry.getValue();
+						if (name != null && value != null)
+							tdef.setOutputProperty(name, value);
+					}
+				}
+				pdef.addTransformDef(tdef);
+			}
+
+			Document doc = pdef.toXML();
+			String s = PreferenceUtil.serializeDocument(doc);
+			writer.write(s);
+		}
+		catch (FileNotFoundException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("LaunchHelper.0"), e)); //$NON-NLS-1$
+		}
+		catch (IOException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("LaunchHelper.1"), e)); //$NON-NLS-1$
+		}
+		catch (ParserConfigurationException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, "ParserConfigurationException", e)); //$NON-NLS-1$
+		}
+		catch (TransformerException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, "TransformerException", e)); //$NON-NLS-1$
+		}
+		finally
+		{
+			if (writer != null)
+			{
+				try
+				{
+					writer.close();
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+		}
+	}
+
+	public static LaunchProperties hydrateOutputProperties(ILaunchConfiguration configuration) throws CoreException
+	{
+		LaunchProperties properties = null;
+		boolean usePreferenceProperties = false; //configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_PROPERTIES_FROM_PREFERENCES, true);
+		IProcessorType pt = getProcessorInstall(configuration).getProcessorType();
+		if (usePreferenceProperties)
+		{
+			properties = new LaunchProperties();
+			for (Map.Entry<String, String> entry : pt.getOutputPropertyValues().entrySet())
+			{
+				String name = (String) entry.getKey();
+				String value = (String) entry.getValue();
+				properties.setProperty(name, value);
+			}
+		}
+		else
+		{
+			String s = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_OUTPUT_PROPERTIES, (String) null);
+			if (s != null && s.length() > 0)
+			{
+				ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
+				properties = LaunchProperties.fromXML(inputStream);
+			}
+		}
+		return properties;
+	}
+
+	private static LaunchAttributes hydrateAttributes(ILaunchConfiguration configuration) throws CoreException
+	{
+		LaunchAttributes attributes = null;
+		boolean useDefaultAttributes = false; //configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_FEATURES_FROM_PREFERENCES, true);
+		if (useDefaultAttributes)
+		{
+			attributes = new LaunchAttributes();
+			IProcessorType pt = getProcessorInstall(configuration).getProcessorType();
+			Map<String, String> fvals = pt.getAttributeValues();
+			for (Map.Entry<String, String> entry : fvals.entrySet())
+			{
+				String uri = (String) entry.getKey();
+				IAttribute attribute = getAttribute(pt.getAttributes(), uri);
+				attributes.addAttribute(new LaunchAttribute(uri, "string", (String) entry.getValue()));
+			}
+		}
+		else
+		{
+			String s = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_ATTRIBUTES, (String) null);
+			if (s != null && s.length() > 0)
+			{
+				ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
+				attributes = LaunchAttributes.fromXML(inputStream);
+			}
+		}
+		return attributes;
+	}
+
+	private static IAttribute getAttribute(IAttribute[] attributes, String uri)
+	{
+		for (IAttribute attribute : attributes)
+		{
+			if (attribute.getURI().equals(uri))
+				return attribute;
+		}
+		return null;
+	}
+
+
+	public static IProcessorInstall getProcessorInstall(ILaunchConfiguration configuration) throws CoreException
+	{
+		boolean useDefaultProcessor = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_DEFAULT_PROCESSOR, true);
+		if (useDefaultProcessor)
+			return JAXPRuntime.getDefaultProcessor();
+		String processorId = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_PROCESSOR, ""); //$NON-NLS-1$
+		IProcessorInstall processor = JAXPRuntime.getProcessor(processorId);
+		return processor;
+	}
+
+	private static ITransformerFactory hydrateTransformerFactory(ILaunchConfiguration configuration) throws CoreException
+	{
+		IProcessorType type = getProcessorInstall(configuration).getProcessorType();
+		boolean useDefaultFactory = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_USE_DEFAULT_PROCESSOR, true);
+		if (useDefaultFactory)
+			return type.getDefaultTransformerFactory();
+		
+		String factoryId = configuration.getAttribute(JAXPLaunchConfigurationConstants.ATTR_TRANSFORMER_FACTORY, (String)null);
+		if (factoryId == null)
+			return null;
+		
+		for (ITransformerFactory factory : type.getTransformerFactories())
+		{
+			if (factory.getFactoryClass().equals(factoryId))
+				return factory;
+		}
+		return null;
+	}
+
+	public ITransformerFactory getTransformerFactory()
+	{
+		return transformerFactory;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Messages.java
new file mode 100644
index 0000000..a058701
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Messages.java
@@ -0,0 +1,22 @@
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.launching.internal.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private Messages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputProperty.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputProperty.java
new file mode 100644
index 0000000..c00c96f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputProperty.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import org.eclipse.wst.xsl.jaxp.launching.IOutputProperty;
+
+public class OutputProperty implements IOutputProperty
+{
+	private final String name;
+	private final String desc;
+
+	public OutputProperty(String key, String desc)
+	{
+		this.name = key;
+		this.desc = desc;
+	}
+
+	public String getDescription()
+	{
+		return desc;
+	}
+
+	public String getURI()
+	{
+		return name;
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputPropertyPreferences.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputPropertyPreferences.java
new file mode 100644
index 0000000..4073133
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/OutputPropertyPreferences.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class OutputPropertyPreferences
+{
+	private final Map<String, Map<String,String>> typeProperties = new HashMap<String, Map<String,String>>();
+
+	public Map<String,String> getOutputPropertyValues(String typeId)
+	{
+		return typeProperties.get(typeId);
+	}
+
+	public void setOutputPropertyValues(String typeId, Map<String,String> properties)
+	{
+		typeProperties.put(typeId, properties);
+	}
+
+	public String getAsXML() throws ParserConfigurationException, IOException, TransformerException
+	{
+		Document doc = PreferenceUtil.getDocument();
+		Element config = doc.createElement("outputPropertyPreferences"); //$NON-NLS-1$
+		doc.appendChild(config);
+
+		for (String type : typeProperties.keySet())
+		{
+			Element processorTypeElement = typeAsElement(doc, type);
+			Map<String,String> propertyValues = typeProperties.get(type);
+			featureValuesAsElement(doc, processorTypeElement, propertyValues);
+			config.appendChild(processorTypeElement);
+		}
+
+		// Serialize the Document and return the resulting String
+		return PreferenceUtil.serializeDocument(doc);
+	}
+
+	public static OutputPropertyPreferences fromXML(InputStream inputStream) throws CoreException
+	{
+		OutputPropertyPreferences prefs = new OutputPropertyPreferences();
+
+		// Do the parsing and obtain the top-level node
+		Document doc = PreferenceUtil.getDocument(inputStream);
+		Element config = doc.getDocumentElement();
+
+		Element[] processorTypeEls = PreferenceUtil.getChildElements(config, "processorType"); //$NON-NLS-1$
+		for (int i = 0; i < processorTypeEls.length; ++i)
+		{
+			Element processorTypeEl = processorTypeEls[i];
+			String type = elementAsType(processorTypeEl);
+			Map<String,String> featureValues = elementAsPropertyValues(processorTypeEl);
+			prefs.setOutputPropertyValues(type, featureValues);
+		}
+
+		return prefs;
+	}
+
+	private static String elementAsType(Element parent)
+	{
+		String id = parent.getAttribute("id"); //$NON-NLS-1$
+		return id;
+	}
+
+	private static Element typeAsElement(Document doc, String type)
+	{
+		Element element = doc.createElement("processorType"); //$NON-NLS-1$
+		element.setAttribute("id", type); //$NON-NLS-1$
+		return element;
+	}
+
+	private static Map<String, String> elementAsPropertyValues(Element element)
+	{
+		Element[] propertyEls = PreferenceUtil.getChildElements(element, "property"); //$NON-NLS-1$
+		Map<String, String> propertyValues = new HashMap<String,String>();
+		for (Element featureEl : propertyEls)
+		{
+			String name = featureEl.getAttribute("name"); //$NON-NLS-1$
+			String value = featureEl.getAttribute("value"); //$NON-NLS-1$
+			propertyValues.put(name, value);
+		}
+		return propertyValues;
+	}
+
+	private static void featureValuesAsElement(Document doc, Element featuresEl, Map<String, String> propertyValues)
+	{
+		if (propertyValues != null)
+		{
+			for (Map.Entry<String, String> entry : propertyValues.entrySet())
+			{
+				String name = entry.getKey();
+				String value = entry.getValue();
+				Element element = doc.createElement("property"); //$NON-NLS-1$
+				element.setAttribute("name", name); //$NON-NLS-1$
+				element.setAttribute("value", value); //$NON-NLS-1$
+				featuresEl.appendChild(element);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PluginProcessorJar.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PluginProcessorJar.java
new file mode 100644
index 0000000..15f1026
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PluginProcessorJar.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.osgi.framework.Bundle;
+
+public class PluginProcessorJar implements IProcessorJar
+{
+	private final String pluginId;
+	private final IPath path;
+
+	public PluginProcessorJar(String pluginId, IPath path)
+	{
+		this.pluginId = pluginId;
+		this.path = path;
+	}
+
+	public URL asURL()
+	{
+		URL url = null;
+		try
+		{
+			// FIXME very clumsy way to get location orbit jar file
+			// There is surely a better way, but I can'd find it.
+			if (path == null)
+			{
+				url = Platform.getBundle(pluginId).getEntry("/"); //$NON-NLS-1$
+				url = FileLocator.resolve(url);
+				String s = url.getPath();
+				if (s.endsWith("!/")) //$NON-NLS-1$
+				{
+					s = s.substring(0,s.length()-2);
+				}
+				url = new URL(s);
+			}
+			else
+			{
+				Bundle bundle = Platform.getBundle(pluginId);
+				IPath jarPath = new Path("/" + path); //$NON-NLS-1$
+				url = FileLocator.find(bundle, jarPath, null);
+				if (url != null)
+					url = FileLocator.resolve(url);
+			}
+		}
+		catch (IOException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		return url;
+	}
+
+	public IPath getPath()
+	{
+		return path;
+	}
+
+	@Override
+	public String toString()
+	{
+		return "Plugin " + pluginId + Messages.getString("PluginProcessorJar.0") + path; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PreferenceInitializer.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PreferenceInitializer.java
new file mode 100644
index 0000000..0bf1bca
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/PreferenceInitializer.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPLaunchConfigurationConstants;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer
+{
+
+	@Override
+	public void initializeDefaultPreferences()
+	{
+		IEclipsePreferences node = new DefaultScope().getNode(JAXPLaunchingPlugin.PLUGIN_ID);
+
+		ProcessorPreferences prefs = new ProcessorPreferences();
+		prefs.setDefaultProcessorId(JAXPRuntime.JRE_DEFAULT_PROCESSOR_ID);
+
+		OutputPropertyPreferences outputPrefs = new OutputPropertyPreferences();
+		outputPrefs.setOutputPropertyValues(JAXPRuntime.JRE_DEFAULT_PROCESSOR_TYPE_ID, JAXPRuntime.createDefaultOutputProperties(JAXPRuntime.JRE_DEFAULT_PROCESSOR_TYPE_ID));
+		outputPrefs.setOutputPropertyValues(JAXPLaunchConfigurationConstants.XALAN_TYPE_ID, JAXPRuntime.createDefaultOutputProperties(JAXPLaunchConfigurationConstants.XALAN_TYPE_ID));
+		outputPrefs.setOutputPropertyValues(JAXPLaunchConfigurationConstants.SAXON_TYPE_ID, JAXPRuntime.createDefaultOutputProperties(JAXPLaunchConfigurationConstants.SAXON_TYPE_ID));
+		outputPrefs.setOutputPropertyValues(JAXPLaunchConfigurationConstants.SAXON_1_0_TYPE_ID, JAXPRuntime.createDefaultOutputProperties(JAXPLaunchConfigurationConstants.SAXON_1_0_TYPE_ID));
+
+		try
+		{
+			String xml = prefs.getAsXML();
+			node.put(JAXPRuntime.PREF_PROCESSOR_XML, xml);
+
+			xml = outputPrefs.getAsXML();
+			node.put(JAXPRuntime.PREF_OUTPUT_PROPERTIES_XML, xml);
+
+			node.put(JAXPLaunchConfigurationConstants.ATTR_DEFAULT_DEBUGGING_INSTALL_ID, "org.eclipse.wst.xsl.launching.xalan.processor"); //$NON-NLS-1$
+		}
+		catch (ParserConfigurationException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		catch (IOException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		catch (TransformerException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorInvokerDescriptor.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorInvokerDescriptor.java
new file mode 100644
index 0000000..eb93ad9
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorInvokerDescriptor.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInvoker;
+
+public class ProcessorInvokerDescriptor implements IProcessorInvoker
+{
+
+	private final String invokerClass;
+	private final String[] classpath;
+	private final String id;
+	private final String bundleId;
+
+	public ProcessorInvokerDescriptor(String id, String bundleId, String invokerClass, String[] classpath)
+	{
+		this.id = id;
+		this.bundleId = bundleId;
+		this.invokerClass = invokerClass;
+		this.classpath = classpath;
+	}
+
+	public String[] getClasspathEntries()
+	{
+		return createEntries(bundleId,classpath);
+	}
+	
+	public static String[] createEntries(String bundleId, String[] classpath)
+	{
+		List<String> entries = new ArrayList<String>();
+		try {
+			// if in dev mode, use the bin dir
+			if (Platform.inDevelopmentMode())
+				entries.add(Utils.getFileLocation(bundleId, "/bin")); //$NON-NLS-1$
+			for (String jar : classpath)
+			{
+				String entry = null;
+				if (jar.startsWith("${eclipse_orbit:") && jar.endsWith("}")) //$NON-NLS-1$ //$NON-NLS-2$
+				{
+					jar = jar.substring("${eclipse_orbit:".length()); //$NON-NLS-1$
+					jar = jar.substring(0,jar.length()-1);
+					try
+					{
+						File bundleFile = FileLocator.getBundleFile(Platform.getBundle(jar));
+						if (bundleFile.isDirectory())
+							entry = Utils.getPluginLocation(jar) + "/bin";
+						else
+							entry = Utils.getPluginLocation(jar);
+					}
+					catch (IOException e)
+					{}
+				}
+				else
+				{
+					entry = Utils.getFileLocation(bundleId,jar);
+				}
+				if (entry!=null)
+					entries.add(entry);
+			}
+		} 
+		catch (CoreException e) 
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		return entries.toArray(new String[0]);
+	}
+
+	/**
+	 * The name of the class that implements IProcessorInvoker
+	 */
+	public String getInvokerClassName()
+	{
+		return invokerClass;
+	}
+
+	public String getId()
+	{
+		return id;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorJar.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorJar.java
new file mode 100644
index 0000000..fe1c76a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorJar.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+
+public class ProcessorJar implements IProcessorJar
+{
+	private final IPath path;
+
+	public ProcessorJar(IPath path)
+	{
+		this.path = path;
+	}
+
+	public URL asURL()
+	{
+		URL url = null;
+		try
+		{
+			// first try to resolve as workspace-relative path
+			IPath rootPath = ResourcesPlugin.getWorkspace().getRoot().getLocation();
+			File file = new File(rootPath.append(path).toOSString());
+			if (file.exists())
+				url = file.toURL();
+			else
+			{
+				// now try to resolve as an absolute path
+				file = new File(path.toOSString());
+				url = file.toURL();
+			}
+		}
+		catch (MalformedURLException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		return url;
+	}
+
+	public IPath getPath()
+	{
+		return path;
+	}
+
+	@Override
+	public String toString()
+	{
+		return path.toString();
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorPreferences.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorPreferences.java
new file mode 100644
index 0000000..3472278
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorPreferences.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.ProcessorInstall;
+import org.eclipse.wst.xsl.launching.config.PreferenceUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+public class ProcessorPreferences
+{
+	private String defaultProcessorId;
+	private List<IProcessorInstall> processors = new ArrayList<IProcessorInstall>();
+
+	public void setProcessors(List<IProcessorInstall> processors)
+	{
+		this.processors = processors;
+	}
+
+	public List<IProcessorInstall> getProcessors()
+	{
+		return processors;
+	}
+
+	public String getDefaultProcessorId()
+	{
+		return defaultProcessorId;
+	}
+
+	public void setDefaultProcessorId(String defaultProcessorId)
+	{
+		this.defaultProcessorId = defaultProcessorId;
+	}
+
+	public String getAsXML() throws ParserConfigurationException, IOException, TransformerException
+	{
+		Document doc = PreferenceUtil.getDocument();
+		Element config = doc.createElement("processorSettings");  //$NON-NLS-1$
+		doc.appendChild(config);
+
+		// Set the defaultVM attribute on the top-level node
+		if (defaultProcessorId != null)
+		{
+			config.setAttribute("defaultProcessor", defaultProcessorId);  //$NON-NLS-1$
+		}
+
+		for (Iterator<IProcessorInstall> iter = processors.iterator(); iter.hasNext();)
+		{
+			IProcessorInstall install = (IProcessorInstall) iter.next();
+			if (!install.isContributed())
+			{
+				Element vmTypeElement = installAsElement(doc, install);
+				config.appendChild(vmTypeElement);
+			}
+		}
+
+		// Serialize the Document and return the resulting String
+		return PreferenceUtil.serializeDocument(doc);
+	}
+
+	public static ProcessorPreferences fromXML(InputStream inputStream) throws CoreException
+	{
+		ProcessorPreferences prefs = new ProcessorPreferences();
+
+		Document doc = PreferenceUtil.getDocument(inputStream);
+		Element config = doc.getDocumentElement();
+
+		// Populate the default VM-related fields
+		prefs.setDefaultProcessorId(config.getAttribute("defaultProcessor")); //$NON-NLS-1$
+
+		List<IProcessorInstall> processors = new ArrayList<IProcessorInstall>();
+		// Traverse the parsed structure and populate the VMType to VM Map
+		Element[] processorEls = PreferenceUtil.getChildElements(config, "processor"); //$NON-NLS-1$
+		for (int i = 0; i < processorEls.length; ++i)
+		{
+			IProcessorInstall processor = elementAsInstall(processorEls[i]);
+			processors.add(processor);
+		}
+
+		prefs.setProcessors(processors);
+
+		return prefs;
+	}
+
+	private static IProcessorInstall elementAsInstall(Element parent)
+	{
+		String id = parent.getAttribute("id"); //$NON-NLS-1$
+		String label = parent.getAttribute("label"); //$NON-NLS-1$
+		String typeId = parent.getAttribute("type"); //$NON-NLS-1$
+		String supports = parent.getAttribute("supports"); //$NON-NLS-1$
+		String debuggerId = parent.getAttribute("debuggerId"); //$NON-NLS-1$
+
+		IProcessorJar[] jars = null;
+		Element[] jarsEls = PreferenceUtil.getChildElements(parent, "jars"); //$NON-NLS-1$
+		if (jarsEls.length == 1)
+		{
+			jars = elementAsJars(jarsEls[0]);
+		}
+		IProcessorInstall install = new ProcessorInstall(id, label, typeId, jars, debuggerId, supports, false);
+		return install;
+	}
+
+	private static Element installAsElement(Document doc, IProcessorInstall install)
+	{
+		Element element = doc.createElement("processor"); //$NON-NLS-1$
+		element.setAttribute("id", install.getId()); //$NON-NLS-1$
+		element.setAttribute("label", install.getName()); //$NON-NLS-1$
+		element.setAttribute("type", install.getProcessorType().getId()); //$NON-NLS-1$
+		element.setAttribute("supports", install.getSupports()); //$NON-NLS-1$
+		element.setAttribute("debuggerId", install.getDebugger() != null ? install.getDebugger().getId() : null); //$NON-NLS-1$
+		element.appendChild(jarsAsElement(doc, install.getProcessorJars()));
+		return element;
+	}
+
+	private static IProcessorJar[] elementAsJars(Element element)
+	{
+		Element[] jarEls = PreferenceUtil.getChildElements(element, "jar"); //$NON-NLS-1$
+		List<ProcessorJar> jars = new ArrayList<ProcessorJar>(jarEls.length);
+		for (Element jarEl : jarEls)
+		{
+			Node node = jarEl.getFirstChild();
+			if (node != null && node.getNodeType() == Node.TEXT_NODE)
+			{
+				String path = ((Text) node).getNodeValue();
+				jars.add(new ProcessorJar(Path.fromPortableString(path)));
+			}
+		}
+		return (IProcessorJar[]) jars.toArray(new IProcessorJar[0]);
+	}
+
+	private static Element jarsAsElement(Document doc, IProcessorJar[] jars)
+	{
+		Element jarsEl = doc.createElement("jars");  //$NON-NLS-1$
+		for (IProcessorJar jar : jars)
+		{
+			if (jar != null && jar.getPath() != null)
+			{
+				Element jarEl = doc.createElement("jar"); //$NON-NLS-1$
+				Text text = doc.createTextNode(jar.getPath().toPortableString());
+				jarEl.appendChild(text);
+				jarsEl.appendChild(jarEl);
+			}
+		}
+		return jarsEl;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorType.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorType.java
new file mode 100644
index 0000000..1136929
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/ProcessorType.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.wst.xsl.jaxp.launching.IAttribute;
+import org.eclipse.wst.xsl.jaxp.launching.IOutputProperty;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+
+public class ProcessorType implements IProcessorType
+{
+	private static final String DESC_SUFFIX = ".DESC"; //$NON-NLS-1$
+	private static final String TYPE_SUFFIX = ".TYPE"; //$NON-NLS-1$
+
+	private final String id;
+	private final String name;
+	private final ITransformerFactory[] transformerFactories;
+	private final URL attributePropertiesURL;
+	private final URL outputPropertiesURL;
+
+	private IAttribute[] attributes;
+	private IOutputProperty[] outputProperties;
+	private Map<String, String> outputPropertyValues;
+	private Map<String, String> attributeValues;
+
+	public ProcessorType(String id, String name, URL attributePropertiesURL, URL outputPropertiesURL, Map<String, String> attributeValues, Map<String, String> outputPropertyValues, ITransformerFactory[] transformerFactories)
+	{
+		this.id = id;
+		this.name = name;
+		this.attributePropertiesURL = attributePropertiesURL;
+		this.outputPropertiesURL = outputPropertiesURL;
+		this.attributeValues = attributeValues;
+		this.transformerFactories = transformerFactories;
+		this.outputPropertyValues = outputPropertyValues;
+	}
+
+	public String getId()
+	{
+		return id;
+	}
+
+	public String getLabel()
+	{
+		return name;
+	}
+
+	public Map<String, String> getAttributeValues()
+	{
+		return attributeValues;
+	}
+
+	public IAttribute[] getAttributes()
+	{
+		if (attributes == null)
+		{
+			if (attributePropertiesURL != null)
+				attributes = loadAttributes();
+			else
+				attributes = new IAttribute[0];
+		}
+		return attributes;
+	}
+
+	public Map<String,String> getOutputPropertyValues()
+	{
+		return outputPropertyValues;
+	}
+
+	public boolean isJREDefault()
+	{
+		return JAXPRuntime.JRE_DEFAULT_PROCESSOR_TYPE_ID.equals(id);
+	}
+
+	public ITransformerFactory[] getTransformerFactories()
+	{
+		return transformerFactories;
+	}
+	
+	public ITransformerFactory getDefaultTransformerFactory()
+	{
+		if (transformerFactories.length > 0)
+			return transformerFactories[0];
+		return null;
+	}
+
+	public IOutputProperty[] getOutputProperties()
+	{
+		if (outputProperties == null)
+		{
+			if (outputPropertiesURL != null)
+				outputProperties = loadOutputProperties();
+			else
+				outputProperties = new IOutputProperty[0];
+		}
+		return outputProperties;
+	}
+
+	private IOutputProperty[] loadOutputProperties()
+	{
+		BufferedInputStream is = null;
+		List<OutputProperty> outputs = new ArrayList<OutputProperty>();
+		Properties props = new Properties();
+		try
+		{
+
+			is = new BufferedInputStream(outputPropertiesURL.openStream());
+			props.load(is);
+			for (Object element : props.keySet())
+			{
+				String key = (String) element;
+				if (!key.endsWith(DESC_SUFFIX))
+				{
+					String name = key;
+					String uri = props.getProperty(key);
+					String desc = props.getProperty(key + DESC_SUFFIX);
+					if (uri != null && name != null && desc != null)
+					{
+						OutputProperty prop = new OutputProperty(uri.trim(), desc);
+						outputs.add(prop);
+					}
+					else
+					{
+						JAXPLaunchingPlugin.log(new CoreException(new Status(IStatus.WARNING, JAXPLaunchingPlugin.PLUGIN_ID, Messages.getString("ProcessorType.2") + outputPropertiesURL //$NON-NLS-1$
+								+ Messages.getString("ProcessorType.3") + key))); //$NON-NLS-1$
+					}
+				}
+			}
+		}
+		catch (IOException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		finally
+		{
+			if (is != null)
+			{
+				try
+				{
+					is.close();
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+		}
+		return (IOutputProperty[]) outputs.toArray(new IOutputProperty[0]);
+	}
+
+	private IAttribute[] loadAttributes()
+	{
+		BufferedInputStream is = null;
+		List<Attribute> attributesList = new ArrayList<Attribute>();
+		try
+		{
+			is = new BufferedInputStream(attributePropertiesURL.openStream());
+			Properties props = new Properties();
+			props.load(is);
+
+			for (Object element : props.keySet())
+			{
+				String key = (String) element;
+				if (!key.endsWith(DESC_SUFFIX) && !key.endsWith(TYPE_SUFFIX))
+				{
+					String uri = props.getProperty(key);
+					String type = props.getProperty(key + TYPE_SUFFIX);
+					String desc = props.getProperty(key + DESC_SUFFIX);
+					if (uri != null && type != null && desc != null)
+					{
+						Attribute attribute = new Attribute(uri.trim(), type.trim(), desc);
+						attributesList.add(attribute);
+					}
+					else
+					{
+						JAXPLaunchingPlugin.log(new CoreException(new Status(IStatus.WARNING, JAXPLaunchingPlugin.PLUGIN_ID, Messages.getString("ProcessorType.4") + attributePropertiesURL //$NON-NLS-1$
+								+ Messages.getString("ProcessorType.5") + key))); //$NON-NLS-1$
+					}
+				}
+			}
+
+		}
+		catch (IOException e)
+		{
+			JAXPLaunchingPlugin.log(e);
+		}
+		finally
+		{
+			if (is != null)
+			{
+				try
+				{
+					is.close();
+				}
+				catch (IOException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+		}
+		IAttribute[] attributes = (IAttribute[]) attributesList.toArray(new IAttribute[0]);
+		Arrays.sort(attributes);
+		return attributes;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/TransformerFactory.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/TransformerFactory.java
new file mode 100644
index 0000000..4049d42
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/TransformerFactory.java
@@ -0,0 +1,27 @@
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+
+public class TransformerFactory implements ITransformerFactory
+{
+	private final String factoryClass;
+	private final String name;
+	
+	public TransformerFactory(String name,String factoryClass)
+	{
+		super();
+		this.factoryClass = factoryClass;
+		this.name = name;
+	}
+
+	public String getFactoryClass()
+	{
+		return factoryClass;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Utils.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Utils.java
new file mode 100644
index 0000000..8e2ebc4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/Utils.java
@@ -0,0 +1,57 @@
+package org.eclipse.wst.xsl.jaxp.launching.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+public class Utils
+{
+
+	public static String getFileLocation(String bundleId, String path) throws CoreException
+	{
+		String location = null;
+		try
+		{
+			URL url = FileLocator.find(Platform.getBundle(bundleId), new Path(path), null);
+			if (url != null)
+			{
+				URL fileUrl = FileLocator.toFileURL(url);
+				File file = new File(fileUrl.getFile());
+				location = file.getAbsolutePath();
+			}
+		}
+		catch (IOException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("Utils.0") + path + Messages.getString("Utils.1") + bundleId, e)); //$NON-NLS-1$ //$NON-NLS-2$
+		} 
+		return location;
+	}
+
+	public static String getPluginLocation(String bundleId) throws CoreException
+	{
+		String location = null;
+		try
+		{
+			URL url = new URL("platform:/plugin/"+bundleId);
+			if (url != null)
+			{
+				URL fileUrl = FileLocator.toFileURL(url);
+				File file = new File(fileUrl.getFile());
+				location = file.getAbsolutePath();
+			}
+		}
+		catch (IOException e)
+		{
+			throw new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.ERROR, Messages.getString("Utils.0") + bundleId + Messages.getString("Utils.1") + bundleId, e)); //$NON-NLS-1$ //$NON-NLS-2$
+		} 
+		return location;
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/messages.properties
new file mode 100644
index 0000000..bdf2af0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/messages.properties
@@ -0,0 +1,21 @@
+Attribute.0=Value must be a double
+Attribute.1=Value must be an integer
+Attribute.2=Valid values are 'true' or 'false'
+Attribute.5=Value must be a float
+PluginProcessorJar.0=, path 
+ProcessorType.2=Output properties file 
+ProcessorType.3=\ not configured properly for key 
+ProcessorType.4=Attribute properties file 
+ProcessorType.5=\ not configured properly for key 
+Utils.0=Error determining jar file location: 
+Utils.1=\ from bundle: 
+XSLTLaunchConfigurationDelegate.0=Switch to Default Debugger
+XSLTLaunchConfigurationDelegate.1=The 
+XSLTLaunchConfigurationDelegate.2=\ XSLT processor does not support debugging.\n
+XSLTLaunchConfigurationDelegate.23=Could not locate jar file 
+XSLTLaunchConfigurationDelegate.3=Would you like to debug using the default 
+XSLTLaunchConfigurationDelegate.31=\ to 
+XSLTLaunchConfigurationDelegate.4=\ processor instead?
+XSLTLaunchConfigurationDelegate.5=launch
+XSLTLaunchConfigurationDelegate.6=launch.xml
+XSLTLaunchConfigurationDelegate.7=Error copying url 
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/AbstractRegistryReader.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/AbstractRegistryReader.java
new file mode 100644
index 0000000..233802a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/AbstractRegistryReader.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+
+public abstract class AbstractRegistryReader
+{
+	public static final String ATT_CLASS = "class"; //$NON-NLS-1$
+	public static final String TAG_DESCRIPTION = "description"; //$NON-NLS-1$
+
+	protected static void logError(IConfigurationElement element, String text)
+	{
+		IExtension extension = element.getDeclaringExtension();
+		StringBuffer buf = new StringBuffer();
+		buf.append("Plugin " + extension.getNamespaceIdentifier() + Messages.getString("AbstractRegistryReader.3") + extension.getExtensionPointUniqueIdentifier()); //$NON-NLS-1$ //$NON-NLS-2$
+		buf.append("\n" + text); //$NON-NLS-1$
+		JAXPLaunchingPlugin.log(new CoreException(new Status(IStatus.ERROR, JAXPLaunchingPlugin.PLUGIN_ID, IStatus.OK, buf.toString(), null)));
+	}
+
+	protected static void logMissingAttribute(IConfigurationElement element, String attributeName)
+	{
+		logError(element, Messages.getString("AbstractRegistryReader.5") + attributeName + Messages.getString("AbstractRegistryReader.6")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	protected static void logMissingElement(IConfigurationElement element, String elementName)
+	{
+		logError(element, Messages.getString("AbstractRegistryReader.7") + elementName + Messages.getString("AbstractRegistryReader.8")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	protected static void logUnknownElement(IConfigurationElement element)
+	{
+		logError(element, Messages.getString("AbstractRegistryReader.9") + element.getName()); //$NON-NLS-1$
+	}
+
+	public static IExtension[] orderExtensions(IExtension[] extensions)
+	{
+		IExtension[] sortedExtension = new IExtension[extensions.length];
+		System.arraycopy(extensions, 0, sortedExtension, 0, extensions.length);
+		Comparator<IExtension> comparer = new Comparator<IExtension>()
+		{
+			public int compare(IExtension arg0, IExtension arg1)
+			{
+				String s1 = arg0.getNamespaceIdentifier();
+				String s2 = arg1.getNamespaceIdentifier();
+				return s1.compareToIgnoreCase(s2);
+			}
+		};
+		Collections.sort(Arrays.asList(sortedExtension), comparer);
+		return sortedExtension;
+	}
+
+	protected abstract boolean readElement(IConfigurationElement element);
+
+	protected void readElementChildren(IConfigurationElement element)
+	{
+		readElements(element.getChildren());
+	}
+
+	protected void readElements(IConfigurationElement[] elements)
+	{
+		for (int i = 0; i < elements.length; i++)
+		{
+			if (!readElement(elements[i]))
+				logUnknownElement(elements[i]);
+		}
+	}
+
+	protected void readExtension(IExtension extension)
+	{
+		readElements(extension.getConfigurationElements());
+	}
+
+	public void readRegistry(IExtensionRegistry registry, String pluginId, String extensionPoint)
+	{
+		IExtensionPoint point = registry.getExtensionPoint(pluginId, extensionPoint);
+		if (point == null)
+			return;
+		IExtension[] extensions = point.getExtensions();
+		extensions = orderExtensions(extensions);
+		for (IExtension element : extensions)
+			readExtension(element);
+	}
+
+	public static String getDescription(IConfigurationElement configElement)
+	{
+		IConfigurationElement[] children = configElement.getChildren(TAG_DESCRIPTION);
+		if (children.length >= 1)
+		{
+			return children[0].getValue();
+		}
+		return ""; //$NON-NLS-1$
+	}
+
+	public static String getClassValue(IConfigurationElement configElement, String classAttributeName)
+	{
+		String className = configElement.getAttribute(classAttributeName);
+		if (className != null)
+			return className;
+		IConfigurationElement[] candidateChildren = configElement.getChildren(classAttributeName);
+		if (candidateChildren.length == 0)
+			return null;
+
+		return candidateChildren[0].getAttribute(ATT_CLASS);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistry.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistry.java
new file mode 100644
index 0000000..02142ab
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistry.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.wst.xsl.jaxp.launching.IDebugger;
+import org.eclipse.wst.xsl.jaxp.launching.internal.DebuggerDescriptor;
+
+public class DebuggerRegistry
+{
+	private final Map<String, DebuggerDescriptor> debuggers = new HashMap<String, DebuggerDescriptor>();
+
+	public DebuggerRegistry()
+	{
+		DebuggerRegistryReader registryReader = new DebuggerRegistryReader();
+		registryReader.addConfigs(this);
+	}
+
+	public IDebugger getDebugger(String id)
+	{
+		return (IDebugger) debuggers.get(id);
+	}
+
+	public IDebugger[] getDebuggers()
+	{
+		return (IDebugger[]) debuggers.values().toArray(new IDebugger[0]);
+	}
+
+	public void addDebugger(DebuggerDescriptor desc)
+	{
+		debuggers.put(desc.getId(), desc);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistryReader.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistryReader.java
new file mode 100644
index 0000000..98b9ee8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/DebuggerRegistryReader.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.internal.DebuggerDescriptor;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+
+public class DebuggerRegistryReader extends AbstractRegistryReader
+{
+	public static final String TAG_DEBUGGER = "debugger"; //$NON-NLS-1$
+	public static final String ATT_ID = "id"; //$NON-NLS-1$
+	public static final String ATT_CLASSNAME = "className"; //$NON-NLS-1$
+	public static final String ATT_CLASSPATH = "classpath"; //$NON-NLS-1$
+	public static final String ATT_NAME = "name"; //$NON-NLS-1$
+	public static final String ATT_PROCESSOR_TYPE_ID = "processorTypeId"; //$NON-NLS-1$
+	public static final String ATT_TRANSFORMER_FACTORY = "transformerFactoryClass"; //$NON-NLS-1$
+
+	private DebuggerRegistry registry;
+
+	@Override
+	protected boolean readElement(IConfigurationElement element)
+	{
+		if (!element.getName().equals(TAG_DEBUGGER))
+			return false;
+
+		String id = element.getAttribute(ATT_ID);
+		if (id == null)
+		{
+			logMissingAttribute(element, ATT_ID);
+			return true;
+		}
+
+		String className = element.getAttribute(ATT_CLASSNAME);
+		if (className == null)
+		{
+			logMissingAttribute(element, ATT_CLASSNAME);
+			return true;
+		}
+
+		String classpath = element.getAttribute(ATT_CLASSPATH);
+		if (classpath == null)
+		{
+			logMissingAttribute(element, ATT_CLASSPATH);
+			return true;
+		}
+
+		String[] entries = classpath.split(";"); //$NON-NLS-1$
+		for (int i = 0; i < entries.length; i++)
+		{
+			String string = entries[i];
+			entries[i] = string.trim();
+		}
+
+		String name = element.getAttribute(ATT_NAME);
+		if (name == null)
+		{
+			logMissingAttribute(element, ATT_NAME);
+			return true;
+		}
+
+		String processorTypeId = element.getAttribute(ATT_PROCESSOR_TYPE_ID);
+		if (processorTypeId == null)
+		{
+			logMissingAttribute(element, ATT_PROCESSOR_TYPE_ID);
+			return true;
+		}
+		String tFact = element.getAttribute(ATT_TRANSFORMER_FACTORY);
+
+		registry.addDebugger(new DebuggerDescriptor(id, element.getContributor().getName(), className, entries, name, processorTypeId, tFact));
+
+		return true;
+	}
+
+	public void readElement(DebuggerRegistry registry, IConfigurationElement element)
+	{
+		this.registry = registry;
+		readElement(element);
+	}
+
+	public void addConfigs(DebuggerRegistry registry)
+	{
+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+		this.registry = registry;
+		readRegistry(extensionRegistry, JAXPLaunchingPlugin.PLUGIN_ID, "debugger"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistry.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistry.java
new file mode 100644
index 0000000..9a40916
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistry.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInvoker;
+
+public class InvokerRegistry
+{
+	private final Map<String, IProcessorInvoker> invokers = new HashMap<String, IProcessorInvoker>();
+
+	public InvokerRegistry()
+	{
+		InvokerRegistryReader registryReader = new InvokerRegistryReader();
+		registryReader.addConfigs(this);
+	}
+
+	public IProcessorInvoker getProcessorInvoker(String id)
+	{
+		return (IProcessorInvoker) invokers.get(id);
+	}
+
+	public IProcessorInvoker[] getProcessorInvokers()
+	{
+		return (IProcessorInvoker[]) invokers.values().toArray(new IProcessorInvoker[0]);
+	}
+
+	public void addInvokerDescriptor(IProcessorInvoker desc)
+	{
+		invokers.put(desc.getId(), desc);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistryReader.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistryReader.java
new file mode 100644
index 0000000..b9e6137
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/InvokerRegistryReader.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.internal.ProcessorInvokerDescriptor;
+
+public class InvokerRegistryReader extends AbstractRegistryReader
+{
+	public static final String TAG_INVOKE = "invoker"; //$NON-NLS-1$
+	public static final String ATT_ID = "id"; //$NON-NLS-1$
+	public static final String ATT_CLASS = "class"; //$NON-NLS-1$
+	public static final String ATT_CLASSPATH = "classpath"; //$NON-NLS-1$
+
+	private InvokerRegistry registry;
+
+	@Override
+	protected boolean readElement(IConfigurationElement element)
+	{
+		if (!element.getName().equals(TAG_INVOKE))
+			return false;
+
+		String id = element.getAttribute(ATT_ID);
+		if (id == null)
+		{
+			logMissingAttribute(element, ATT_ID);
+			return true;
+		}
+
+		String classname = element.getAttribute(ATT_CLASS);
+		if (classname == null)
+		{
+			logMissingAttribute(element, ATT_CLASS);
+			return true;
+		}
+
+		String classpath = element.getAttribute(ATT_CLASSPATH);
+		if (classpath == null)
+		{
+			logMissingAttribute(element, ATT_CLASSPATH);
+			return true;
+		}
+
+		String[] entries = classpath.split(";"); //$NON-NLS-1$
+		for (int i = 0; i < entries.length; i++)
+		{
+			String string = entries[i];
+			entries[i] = string.trim();
+		}
+
+		registry.addInvokerDescriptor(new ProcessorInvokerDescriptor(id, element.getContributor().getName(), classname, entries));
+
+		return true;
+	}
+
+	public void readElement(InvokerRegistry registry, IConfigurationElement element)
+	{
+		this.registry = registry;
+		readElement(element);
+	}
+
+	public void addConfigs(InvokerRegistry registry)
+	{
+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+		this.registry = registry;
+		readRegistry(extensionRegistry, JAXPLaunchingPlugin.PLUGIN_ID, "invoke"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/Messages.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/Messages.java
new file mode 100644
index 0000000..b8c8eb9
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/Messages.java
@@ -0,0 +1,22 @@
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+	private static final String BUNDLE_NAME = "org.eclipse.wst.xsl.jaxp.launching.internal.registry.messages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private Messages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistry.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistry.java
new file mode 100644
index 0000000..1a7ee25
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistry.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorJar;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.ProcessorInstall;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.internal.ProcessorPreferences;
+
+public class ProcessorRegistry
+{
+	private final List<ProcessorInstall> contributedInstalls = new ArrayList<ProcessorInstall>();
+	private List<IProcessorInstall> userInstalls = new ArrayList<IProcessorInstall>();
+	private IProcessorInstall defaultProcessor;
+	private IProcessorInstall jreDefaultProcessor;
+	private IProcessorInstall[] installs;
+
+	public ProcessorRegistry()
+	{
+		initializeFromStorage();
+	}
+
+	private void initializeFromStorage()
+	{
+		// read from the registry
+		ProcessorRegistryReader registryReader = new ProcessorRegistryReader();
+		registryReader.addConfigs(this);
+		// find the jre default
+		for (Iterator<ProcessorInstall> iter = contributedInstalls.iterator(); iter.hasNext();)
+		{
+			IProcessorInstall install = (IProcessorInstall) iter.next();
+			if (install.getId().equals(JAXPRuntime.JRE_DEFAULT_PROCESSOR_ID))
+			{
+				jreDefaultProcessor = install;
+				break;
+			}
+		}
+		// read from the preferences
+		addPersistedVMs();
+	}
+
+	private void addPersistedVMs()
+	{
+		// Try retrieving the VM preferences from the preference store
+		String vmXMLString = JAXPLaunchingPlugin.getDefault().getPluginPreferences().getString(JAXPRuntime.PREF_PROCESSOR_XML);
+
+		// If the preference was found, load VMs from it into memory
+		if (vmXMLString.length() > 0)
+		{
+			try
+			{
+				ByteArrayInputStream inputStream = new ByteArrayInputStream(vmXMLString.getBytes());
+				ProcessorPreferences prefs = ProcessorPreferences.fromXML(inputStream);
+				String defaultProcessorId = prefs.getDefaultProcessorId();
+				userInstalls = prefs.getProcessors();
+				for (Iterator<IProcessorInstall> iter = userInstalls.iterator(); iter.hasNext();)
+				{
+					IProcessorInstall install = (IProcessorInstall) iter.next();
+					if (install.getId().equals(defaultProcessorId))
+					{
+						defaultProcessor = install;
+					}
+				}
+				if (defaultProcessor == null)
+				{
+					for (Iterator<ProcessorInstall> iter = contributedInstalls.iterator(); iter.hasNext();)
+					{
+						IProcessorInstall install = (IProcessorInstall) iter.next();
+						if (defaultProcessor == null && install.getId().equals(defaultProcessorId))
+						{
+							defaultProcessor = install;
+						}
+					}
+				}
+			}
+			catch (CoreException e)
+			{
+				JAXPLaunchingPlugin.log(e);
+			}
+		}
+		// make the JRE the default default
+		if (defaultProcessor == null)
+		{
+			defaultProcessor = jreDefaultProcessor;
+		}
+	}
+
+	public void addProcessor(String bundleId, String id, String label, String processorTypeId, String classpath, String debuggerId, String supports)
+	{
+		IProcessorJar[] jars = ProcessorInstall.createJars(bundleId, classpath);
+		contributedInstalls.add(new ProcessorInstall(id, label, processorTypeId, jars, debuggerId, supports, true));
+	}
+
+	public void addProcessor(IProcessorInstall install)
+	{
+		if (!install.isContributed())
+			userInstalls.add(install);
+		IProcessorInstall[] newinstalls = new IProcessorInstall[installs.length + 1];
+		System.arraycopy(installs, 0, newinstalls, 0, installs.length);
+		newinstalls[installs.length] = install;
+		installs = newinstalls;
+	}
+
+	public void removeProcessor(int index)
+	{
+		IProcessorInstall removed = installs[index];
+		if (!removed.isContributed())
+			userInstalls.remove(removed);
+		IProcessorInstall[] newinstalls = new IProcessorInstall[installs.length - 1];
+		System.arraycopy(installs, 0, newinstalls, 0, index);
+		System.arraycopy(installs, index + 1, newinstalls, index, newinstalls.length - index);
+		installs = newinstalls;
+	}
+
+	public IProcessorInstall[] getProcessors()
+	{
+		if (installs == null)
+		{
+			installs = new IProcessorInstall[contributedInstalls.size() + userInstalls.size()];
+			int startIndex = 0;
+			for (int i = 0; i < contributedInstalls.size(); i++)
+			{
+				installs[i] = (IProcessorInstall) contributedInstalls.get(i);
+				startIndex = i + 1;
+			}
+			for (int i = 0; i < userInstalls.size(); i++)
+			{
+				installs[startIndex + i] = (IProcessorInstall) userInstalls.get(i);
+			}
+		}
+		return installs;
+	}
+
+	public IProcessorInstall[] getProcessors(String id)
+	{
+		IProcessorInstall[] installs = getProcessors();
+		List<IProcessorInstall> result = new ArrayList<IProcessorInstall>();
+		for (IProcessorInstall type : installs)
+		{
+			if (type.getProcessorType().getId().equals(id))
+				result.add(type);
+		}
+		return (IProcessorInstall[]) result.toArray(new IProcessorInstall[0]);
+	}
+
+	public void setDefaultProcessor(IProcessorInstall defaultInstall)
+	{
+		defaultProcessor = defaultInstall;
+	}
+
+	public IProcessorInstall getDefaultProcessor()
+	{
+		return defaultProcessor;
+	}
+
+	public IProcessorInstall getJREDefaultProcessor()
+	{
+		return jreDefaultProcessor;
+	}
+
+	public IProcessorInstall[] getContributedProcessors()
+	{
+		return (IProcessorInstall[]) contributedInstalls.toArray(new IProcessorInstall[0]);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistryReader.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistryReader.java
new file mode 100644
index 0000000..1be3d31
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorRegistryReader.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+
+public class ProcessorRegistryReader extends AbstractRegistryReader
+{
+	public static final String TAG_processor = "processor"; //$NON-NLS-1$
+	public static final String ATT_ID = "id"; //$NON-NLS-1$
+	public static final String ATT_LABEL = "label"; //$NON-NLS-1$
+	public static final String ATT_TYPE_ID = "processorTypeId"; //$NON-NLS-1$
+	public static final String ATT_DEBUGGER_ID = "debuggerId"; //$NON-NLS-1$
+	public static final String ATT_CLASSPATH = "classpath"; //$NON-NLS-1$
+	public static final String ATT_SUPPORTS = "supports"; //$NON-NLS-1$
+
+	private ProcessorRegistry registry;
+
+	@Override
+	protected boolean readElement(IConfigurationElement element)
+	{
+		if (!element.getName().equals(TAG_processor))
+			return false;
+
+		String id = element.getAttribute(ATT_ID);
+		if (id == null)
+		{
+			logMissingAttribute(element, ATT_ID);
+			return true;
+		}
+
+		String label = element.getAttribute(ATT_LABEL);
+		if (label == null)
+		{
+			logMissingAttribute(element, ATT_LABEL);
+			return true;
+		}
+
+		String processorTypeId = element.getAttribute(ATT_TYPE_ID);
+		if (processorTypeId == null)
+		{
+			logMissingAttribute(element, ATT_TYPE_ID);
+			return true;
+		}
+
+		String classpath = element.getAttribute(ATT_CLASSPATH);
+		if (classpath == null)
+		{
+			logMissingAttribute(element, ATT_CLASSPATH);
+			return true;
+		}
+
+		String debuggerId = element.getAttribute(ATT_DEBUGGER_ID);
+
+		String supports = element.getAttribute(ATT_SUPPORTS);
+		if (classpath == null)
+		{
+			logMissingAttribute(element, ATT_SUPPORTS);
+			return true;
+		}
+
+		registry.addProcessor(element.getContributor().getName(), id, label, processorTypeId, classpath, debuggerId, supports);
+
+		return true;
+	}
+
+	public void readElement(ProcessorRegistry registry, IConfigurationElement element)
+	{
+		this.registry = registry;
+		readElement(element);
+	}
+
+	public void addConfigs(ProcessorRegistry registry)
+	{
+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+		this.registry = registry;
+		readRegistry(extensionRegistry, JAXPLaunchingPlugin.PLUGIN_ID, "processor"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistry.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistry.java
new file mode 100644
index 0000000..1e3e520
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistry.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.IProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.ITransformerFactory;
+import org.eclipse.wst.xsl.jaxp.launching.JAXPRuntime;
+import org.eclipse.wst.xsl.jaxp.launching.internal.FeaturePreferences;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+import org.eclipse.wst.xsl.jaxp.launching.internal.OutputPropertyPreferences;
+import org.eclipse.wst.xsl.jaxp.launching.internal.ProcessorType;
+import org.eclipse.wst.xsl.jaxp.launching.internal.TransformerFactory;
+
+public class ProcessorTypeRegistry
+{
+	protected static final String DESC_SUFFIX = ".DESC"; //$NON-NLS-1$
+	protected static final String TYPE_SUFFIX = ".TYPE"; //$NON-NLS-1$
+
+	private final List<IConfigurationElement> elements = new ArrayList<IConfigurationElement>();
+	private IProcessorType[] installTypes;
+
+	public ProcessorTypeRegistry()
+	{
+		ProcessorTypeRegistryReader registryReader = new ProcessorTypeRegistryReader();
+		registryReader.addConfigs(this);
+	}
+
+	public IProcessorType[] getProcessorTypes()
+	{
+		if (installTypes == null)
+		{
+			List<ProcessorType> types = new ArrayList<ProcessorType>();
+			String featureXMLString = JAXPLaunchingPlugin.getDefault().getPluginPreferences().getString(JAXPRuntime.PREF_FEATURE_XML);
+			// If the preference was found, load VMs from it into memory
+			FeaturePreferences prefs = null;
+			if (featureXMLString.length() > 0)
+			{
+				try
+				{
+					ByteArrayInputStream inputStream = new ByteArrayInputStream(featureXMLString.getBytes());
+					prefs = FeaturePreferences.fromXML(inputStream);
+				}
+				catch (CoreException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+
+			String propXMLString = JAXPLaunchingPlugin.getDefault().getPluginPreferences().getString(JAXPRuntime.PREF_OUTPUT_PROPERTIES_XML);
+			// If the preference was found, load VMs from it into memory
+			OutputPropertyPreferences outputprefs = null;
+			if (propXMLString.length() > 0)
+			{
+				try
+				{
+					ByteArrayInputStream inputStream = new ByteArrayInputStream(propXMLString.getBytes());
+					outputprefs = OutputPropertyPreferences.fromXML(inputStream);
+				}
+				catch (CoreException e)
+				{
+					JAXPLaunchingPlugin.log(e);
+				}
+			}
+
+			for (Iterator<IConfigurationElement> iter = elements.iterator(); iter.hasNext();)
+			{
+				IConfigurationElement element = (IConfigurationElement) iter.next();
+				String id = element.getAttribute(ProcessorTypeRegistryReader.ATT_ID);
+				String label = element.getAttribute(ProcessorTypeRegistryReader.ATT_LABEL);
+				Map<String, String> featureValues = new HashMap<String, String>();
+				Map<String, String> propertyValues = new HashMap<String, String>();
+				if (prefs != null && prefs.getFeaturesValues(id) != null)
+					featureValues.putAll(prefs.getFeaturesValues(id));
+				if (outputprefs != null && outputprefs.getOutputPropertyValues(id) != null)
+					propertyValues.putAll(outputprefs.getOutputPropertyValues(id));
+
+				String outputProperties = element.getAttribute(ProcessorTypeRegistryReader.ATT_OUTPUT_PROPERTIES);
+				URL outputPropertiesURL = FileLocator.find(Platform.getBundle(element.getContributor().getName()), new Path(outputProperties), null);
+				String featureProperties = element.getAttribute(ProcessorTypeRegistryReader.ATT_ATTRIBUTE_PROPERTIES);
+				URL featurePropertiesURL = FileLocator.find(Platform.getBundle(element.getContributor().getName()), new Path(featureProperties), null);
+				
+				List<ITransformerFactory> transFactoryList = new ArrayList<ITransformerFactory>();
+				IConfigurationElement[] transFactEls = element.getChildren(ProcessorTypeRegistryReader.EL_TRANSFORMER_FACTORY);
+				for (IConfigurationElement transFactEl : transFactEls)
+				{
+					String transFactoryName = transFactEl.getAttribute(ProcessorTypeRegistryReader.ATT_TRANSFORMER_FACTORY_NAME);
+					String transFactoryClass = transFactEl.getAttribute(ProcessorTypeRegistryReader.ATT_TRANSFORMER_FACTORY_CLASS);
+					transFactoryList.add(new TransformerFactory(transFactoryName,transFactoryClass));
+				}
+				
+				types.add(new ProcessorType(id, label, featurePropertiesURL, outputPropertiesURL, featureValues, propertyValues, transFactoryList.toArray(new ITransformerFactory[0])));
+			}
+			installTypes = types.toArray(new IProcessorType[0]);
+		}
+		return installTypes;
+	}
+
+	public IProcessorType[] getProcessorTypesExclJREDefault()
+	{
+		IProcessorType[] installTypes = getProcessorTypes();
+		List<IProcessorType> exclTypes = new ArrayList<IProcessorType>(installTypes.length - 1);
+		for (IProcessorType type : installTypes)
+		{
+			if (!type.isJREDefault())
+				exclTypes.add(type);
+		}
+		return (IProcessorType[]) exclTypes.toArray(new IProcessorType[0]);
+	}
+
+	public void addType(IConfigurationElement element)
+	{
+		elements.add(element);
+	}
+
+	public IProcessorType getProcessorType(String id)
+	{
+		IProcessorType[] installTypes = getProcessorTypes();
+		for (IProcessorType type : installTypes)
+		{
+			if (type.getId().equals(id))
+				return type;
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistryReader.java b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistryReader.java
new file mode 100644
index 0000000..201e2f6
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/ProcessorTypeRegistryReader.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
+ * 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
+ *
+ * Contributors:
+ *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xsl.jaxp.launching.internal.registry;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xsl.jaxp.launching.internal.JAXPLaunchingPlugin;
+
+public class ProcessorTypeRegistryReader extends AbstractRegistryReader
+{
+	public static final String TAG_processorType = "processorType"; //$NON-NLS-1$
+	public static final String ATT_ID = "id"; //$NON-NLS-1$
+	public static final String ATT_LABEL = "label"; //$NON-NLS-1$
+	public static final String ATT_OUTPUT_PROPERTIES = "outputProperties"; //$NON-NLS-1$
+	public static final String ATT_ATTRIBUTE_PROPERTIES = "attributeProperties"; //$NON-NLS-1$
+	public static final String EL_TRANSFORMER_FACTORY = "transformerFactory";
+	public static final String ATT_TRANSFORMER_FACTORY_NAME = "name";
+	public static final String ATT_TRANSFORMER_FACTORY_CLASS = "factoryClass";
+
+	private ProcessorTypeRegistry registry;
+
+	@Override
+	protected boolean readElement(IConfigurationElement element)
+	{
+		if (!element.getName().equals(TAG_processorType))
+			return false;
+
+		String id = element.getAttribute(ATT_ID);
+		if (id == null)
+		{
+			logMissingAttribute(element, ATT_ID);
+			return true;
+		}
+
+		String label = element.getAttribute(ATT_LABEL);
+		if (label == null)
+		{
+			logMissingAttribute(element, ATT_LABEL);
+			return true;
+		}
+
+		String outputProperties = element.getAttribute(ATT_OUTPUT_PROPERTIES);
+		if (outputProperties == null)
+		{
+			logMissingAttribute(element, ATT_OUTPUT_PROPERTIES);
+			return true;
+		}
+
+		String featureProperties = element.getAttribute(ATT_ATTRIBUTE_PROPERTIES);
+		if (featureProperties == null)
+		{
+			logMissingAttribute(element, ATT_ATTRIBUTE_PROPERTIES);
+			return true;
+		}
+
+		registry.addType(element);
+
+		return true;
+	}
+
+	public void readElement(ProcessorTypeRegistry registry, IConfigurationElement element)
+	{
+		this.registry = registry;
+		readElement(element);
+	}
+
+	protected void addConfigs(ProcessorTypeRegistry registry)
+	{
+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+		this.registry = registry;
+		readRegistry(extensionRegistry, JAXPLaunchingPlugin.PLUGIN_ID, "processorType"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/messages.properties
new file mode 100644
index 0000000..6a64057
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/internal/registry/messages.properties
@@ -0,0 +1,6 @@
+AbstractRegistryReader.3=, extension 
+AbstractRegistryReader.5=Required attribute '
+AbstractRegistryReader.6=' not defined
+AbstractRegistryReader.7=Required sub element '
+AbstractRegistryReader.8=' not defined
+AbstractRegistryReader.9=Unknown extension tag found: 
diff --git a/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/messages.properties b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/messages.properties
new file mode 100644
index 0000000..5d604fa
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.jaxp.launching/src/org/eclipse/wst/xsl/jaxp/launching/messages.properties
@@ -0,0 +1,6 @@
+XSLTRuntime.10=Failed to save process preferences
+XSLTRuntime.5=Saving attributes...
+XSLTRuntime.6=Failed to save attribute preferences
+XSLTRuntime.7=Saving properties...
+XSLTRuntime.8=Failed to save output property preferences
+XSLTRuntime.9=Saving processors...