Bug 573076 - PDE should provide a generic "test report" view

A JUnit Plugin test runner client for Unit Test View bundle.

Change-Id: I50da75952c84c02a878b72e452fbd9574b8b6561
Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/179677
Tested-by: PDE Bot <pde-bot@eclipse.org>
Tested-by: Vikas Chandra <Vikas.Chandra@in.ibm.com>
Reviewed-by: Vikas Chandra <Vikas.Chandra@in.ibm.com>
diff --git a/features/org.eclipse.pde.unittest.junit-feature/.project b/features/org.eclipse.pde.unittest.junit-feature/.project
new file mode 100644
index 0000000..46f6e44
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.pde.unittest.junit-feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.resources.prefs b/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.runtime.prefs b/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/features/org.eclipse.pde.unittest.junit-feature/build.properties b/features/org.eclipse.pde.unittest.junit-feature/build.properties
new file mode 100644
index 0000000..3b0a539
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/build.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2021 Red Hat, Inc. and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+#     Red Hat, Inc. - initial API and implementation
+###############################################################################
+bin.includes=\
+feature.xml,\
+feature.properties
diff --git a/features/org.eclipse.pde.unittest.junit-feature/feature.properties b/features/org.eclipse.pde.unittest.junit-feature/feature.properties
new file mode 100644
index 0000000..f966d8c
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/feature.properties
@@ -0,0 +1,42 @@
+###############################################################################
+# Copyright (c) 2021 Red Hat, Inc. and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+# 
+# Contributors:
+#     Red Hat, Inc. - initial API and implementation
+###############################################################################
+# feature.properties
+# contains externalized strings for feature.xml
+# "%foo" in feature.xml corresponds to the key "foo" in this file
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+
+# "featureName" property - name of the feature
+featureName=Eclipse Plug-in Test runner client for UnitTest View (Experimental)
+
+# "providerName" property - name of the company that provides the feature
+providerName=Eclipse.org
+
+# "description" property - description of the feature
+description=Eclipse plug-in test runner client for UnitTest View.
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2021 Red Hat, Inc. and others.\n\
+\n\
+This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License 2.0\n\
+which accompanies this distribution, and is available at\n\
+https://www.eclipse.org/legal/epl-2.0/\n\
+\n\
+SPDX-License-Identifier: EPL-2.0\n\
+\n\
+Contributors:\n\
+    Red Hat, Inc. - initial API and implementation\n
+################ end of copyright property ####################################
diff --git a/features/org.eclipse.pde.unittest.junit-feature/feature.xml b/features/org.eclipse.pde.unittest.junit-feature/feature.xml
new file mode 100644
index 0000000..485aace
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/feature.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.pde.unittest.junit"
+      label="%featureName"
+      version="1.0.0.qualifier"
+      provider-name="%providerName"
+      license-feature="org.eclipse.license"
+      license-feature-version="0.0.0">
+
+   <description>
+      %description
+   </description>
+
+   <copyright>
+      %copyright
+   </copyright>
+
+   <license url="%licenseURL">
+      %license
+   </license>
+
+   <requires>
+      <import plugin="org.eclipse.unittest.ui"/>
+      <import plugin="org.eclipse.pde.ui"/>
+      <import plugin="org.eclipse.jdt.ui.unittest.junit"/>
+      <import plugin="org.eclipse.ui"/>
+      <import plugin="org.eclipse.debug.ui"/>
+      <import plugin="org.eclipse.jdt.core"/>
+      <import plugin="org.eclipse.core.runtime"/>
+      <import plugin="org.eclipse.core.variables"/>
+      <import plugin="org.eclipse.jdt.debug.ui"/>
+      <import plugin="org.eclipse.jdt.launching"/>
+      <import plugin="org.eclipse.jdt.junit"/>
+   </requires>
+
+   <plugin
+         id="org.eclipse.pde.unittest.junit"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/features/org.eclipse.pde.unittest.junit-feature/pom.xml b/features/org.eclipse.pde.unittest.junit-feature/pom.xml
new file mode 100644
index 0000000..f05e305
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/pom.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright (c) 2012, 2019 Eclipse Foundation and others.
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Distribution License v1.0
+  which accompanies this distribution, and is available at
+  http://www.eclipse.org/org/documents/edl-v10.php
+ 
+  Contributors:
+     Igor Fedorenko - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>eclipse.pde.ui</artifactId>
+    <groupId>eclipse.pde.ui</groupId>
+    <version>4.20.0-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+  <groupId>org.eclipse.pde.unittest.junit.feature</groupId>
+  <artifactId>org.eclipse.pde.unittest.junit</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>eclipse-feature</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-source-plugin</artifactId>
+        <version>${tycho.version}</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <id>feature-source</id>
+            <goals>
+              <goal>feature-source</goal>
+            </goals>
+            <configuration>
+              <excludes>
+                  <plugin id="org.eclipse.pde"/>
+                  <plugin id="org.eclipse.pde.doc.user"/>
+              </excludes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-p2-plugin</artifactId>
+        <version>${tycho.version}</version>
+        <executions>
+          <execution>
+            <id>attach-p2-metadata</id>
+            <phase>package</phase>
+            <goals>
+              <goal>p2-metadata</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/features/org.eclipse.pde.unittest.junit-feature/sourceTemplateFeature/feature.properties b/features/org.eclipse.pde.unittest.junit-feature/sourceTemplateFeature/feature.properties
new file mode 100644
index 0000000..01d7dd4
--- /dev/null
+++ b/features/org.eclipse.pde.unittest.junit-feature/sourceTemplateFeature/feature.properties
@@ -0,0 +1,42 @@
+###############################################################################
+#  Copyright (c) 2021 Red Hat, Inc. and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+# 
+# Contributors:
+#      Red Hat Inc. - initial API and implementation
+###############################################################################
+# feature.properties
+# contains externalized strings for feature.xml
+# "%foo" in feature.xml corresponds to the key "foo" in this file
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+
+# "featureName" property - name of the feature
+featureName=Eclipse PDE Plug-in Developer Unit Test support Resources
+
+# "providerName" property - name of the company that provides the feature
+providerName=Eclipse.org
+
+# "description" property - description of the feature
+description=Eclipse plug-in development environment Unit Test support, including documentation and source code zips.
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2021 Red Hat, Inc. and others.\n\
+\n\
+This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License 2.0\n\
+which accompanies this distribution, and is available at\n\
+https://www.eclipse.org/legal/epl-2.0/\n\
+\n\
+SPDX-License-Identifier: EPL-2.0\n\
+\n\
+Contributors:\n\
+    Red Hat Inc. - initial API and implementation\n
+################ end of copyright property ####################################
diff --git a/pom.xml b/pom.xml
index 2048294..bc7281f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,8 @@
     <module>ui/org.eclipse.ui.trace</module>
     <module>ui/org.eclipse.pde.genericeditor.extension</module>
     <module>ui/org.eclipse.pde.genericeditor.extension.tests</module>
+    <module>ui/org.eclipse.pde.unittest.junit</module>
     <module>features/org.eclipse.pde-feature</module>
+    <module>features/org.eclipse.pde.unittest.junit-feature</module>
   </modules>
 </project>
diff --git a/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF
index f6b64d0..8f6a2a2 100644
--- a/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF
@@ -21,7 +21,8 @@
    org.eclipse.pde.ua.ui,
    org.eclipse.pde.ds.ui,
    org.eclipse.pde.ua.core,
-   org.eclipse.pde.api.tools.tests",
+   org.eclipse.pde.api.tools.tests,
+   org.eclipse.pde.unittest.junit",
  org.eclipse.pde.internal.core.build;x-friends:="org.eclipse.pde.ui,org.eclipse.pde.ds.ui,org.eclipse.pde.ua.ui",
  org.eclipse.pde.internal.core.builders;x-friends:="org.eclipse.pde.ui,org.eclipse.pde.launching,org.eclipse.pde.ds.core",
  org.eclipse.pde.internal.core.bundle;x-friends:="org.eclipse.pde.ui,org.eclipse.pde.ds.ui",
@@ -73,7 +74,8 @@
    org.eclipse.pde.ds.core,
    org.eclipse.pde.ds.ui,
    org.eclipse.pde.ua.core,
-   org.eclipse.pde.api.tools",
+   org.eclipse.pde.api.tools,
+   org.eclipse.pde.unittest.junit",
  org.eclipse.pde.internal.core.variables;x-internal:=true
 Require-Bundle: 
  org.eclipse.core.runtime;bundle-version="[3.14.0,4.0.0)",
diff --git a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
index a2946f2..d53cecb 100644
--- a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
@@ -16,8 +16,10 @@
  org.eclipse.jdt.debug;bundle-version="[3.2.0,4.0.0)",
  org.eclipse.core.filesystem;bundle-version="[1.0.0,2.0.0)"
 Bundle-Activator: org.eclipse.pde.internal.launching.PDELaunchingPlugin
-Export-Package: org.eclipse.pde.internal.launching;x-friends:="org.eclipse.pde.ui",
- org.eclipse.pde.internal.launching.launcher;x-friends:="org.eclipse.pde.ui",
+Export-Package: org.eclipse.pde.internal.launching;x-friends:="org.eclipse.pde.ui,
+ org.eclipse.pde.unittest.junit",
+ org.eclipse.pde.internal.launching.launcher;x-friends:="org.eclipse.pde.ui,
+ org.eclipse.pde.unittest.junit",
  org.eclipse.pde.internal.launching.sourcelookup;x-internal:=true,
  org.eclipse.pde.launching
 Bundle-ActivationPolicy: lazy
diff --git a/ui/org.eclipse.pde.unittest.junit/.classpath b/ui/org.eclipse.pde.unittest.junit/.classpath
new file mode 100644
index 0000000..685a699
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.classpath
@@ -0,0 +1,11 @@
+<?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/JavaSE-11">
+		<attributes>
+			<attribute name="module" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/ui/org.eclipse.pde.unittest.junit/.project b/ui/org.eclipse.pde.unittest.junit/.project
new file mode 100644
index 0000000..5756547
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.project
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.pde.unittest.junit</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>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+	</natures>
+</projectDescription>
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.resources.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.runtime.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6bdfa2d
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,538 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=f
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=fg
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.compiler.problem.APILeak=warning
+org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=info
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=error
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=error
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=info
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=enabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=info
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=info
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=info
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=info
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
+org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=info
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assertion_message=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_record_components=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.text_block_indentation=0
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.ui.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..724c757
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,86 @@
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=20
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;sun;com;org;org.apache;org.w3c;org.eclipse;org.eclipse.swt;org.eclipse.core;org.eclipse.core.runtime;org.eclipse.core.resources;org.eclipse.core.filebuffers;org.eclipse.text;org.eclipse.jface;org.eclipse.jface.text;org.eclipse.ui;org.eclipse.ui.workbench.texteditor;org.eclipse.ui.texteditor;org.eclipse.ui.editors;org.eclipse.compare;org.eclipse.debug;org.eclipse.debug.ui;org.eclipse.search;org.eclipse.search2;org.eclipse.ltk;org.eclipse.jdt.core;org.eclipse.jdt.internal;org.eclipse.jdt.launching;org.eclipse.jdt.ui;org.eclipse.jdt.internal.ui;
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=true
+sp_cleanup.convert_to_enhanced_for_loop=true
+sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.lazy_logical_operator=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.merge_conditional_blocks=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.number_suffix=false
+sp_cleanup.objects_equals=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.precompile_regex=true
+sp_cleanup.push_down_negation=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=true
+sp_cleanup.remove_redundant_semicolons=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_array_creation=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.simplify_lambda_expression_and_method_ref=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_autoboxing=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_directly_map_method=true
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_unboxing=false
+sp_cleanup.use_var=false
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.m2e.core.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.api.tools.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..9d6e2dc
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,102 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_FIELD=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_DEFAULT_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Ignore
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+changed_execution_env=Error
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_report_major_without_breaking_change=Error
+incompatible_api_component_version_report_minor_without_api_change=Error
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.prefs b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..0eb6933
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,36 @@
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=0
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=2
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.exec-env-too-low=1
+compilers.p.internal=1
+compilers.p.missing-packages=2
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=2
+compilers.p.missing-version-require-bundle=2
+compilers.p.no-required-att=0
+compilers.p.no.automatic.module=1
+compilers.p.not-externalized-att=1
+compilers.p.service.component.without.lazyactivation=1
+compilers.p.unknown-attribute=0
+compilers.p.unknown-class=0
+compilers.p.unknown-element=0
+compilers.p.unknown-identifier=0
+compilers.p.unknown-resource=0
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+compilers.use-project=true
+eclipse.preferences.version=1
diff --git a/ui/org.eclipse.pde.unittest.junit/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.unittest.junit/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..d52f6ce
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.eclipse.pde.unittest.junit
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.pde.unittest.junit;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: 
+ org.eclipse.unittest.ui,
+ org.eclipse.pde.ui,
+ org.eclipse.jdt.ui.unittest.junit,
+ org.eclipse.ui;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.debug.ui;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.jdt.core;bundle-version="[3.18.0,4.0.0)",
+ org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
+ org.eclipse.jdt.launching;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.jdt.debug.ui;bundle-version="[3.3.0,4.0.0)",
+ org.eclipse.core.variables;bundle-version="[3.2.200,4.0.0)",
+ org.eclipse.jdt.junit;bundle-version="3.11.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/ui/org.eclipse.pde.unittest.junit/about.html b/ui/org.eclipse.pde.unittest.junit/about.html
new file mode 100644
index 0000000..164f781
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>About</title>
+</head>
+<body lang="EN-US">
+	<h2>About This Content</h2>
+
+	<p>November 30, 2017</p>
+	<h3>License</h3>
+
+	<p>
+		The Eclipse Foundation makes available all content in this plug-in
+		(&quot;Content&quot;). Unless otherwise indicated below, the Content
+		is provided to you under the terms and conditions of the Eclipse
+		Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+		available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; 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
+		(&quot;Redistributor&quot;) 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>
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.unittest.junit/build.properties b/ui/org.eclipse.pde.unittest.junit/build.properties
new file mode 100644
index 0000000..5105873
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/build.properties
@@ -0,0 +1,25 @@
+###############################################################################
+# Copyright (c) 2000, 2021 IBM Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+bin.includes = plugin.xml,\
+               about.html,\
+               icons/,\
+               plugin.properties,\
+               .,\
+               META-INF/
+
+source.. = src/
+
+src.includes = about.html
+
+javacWarnings..=-unavoidableGenericProblems
diff --git a/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn.png b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn.png
new file mode 100644
index 0000000..502b922
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn.png
Binary files differ
diff --git a/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn@2x.png b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn@2x.png
new file mode 100644
index 0000000..854e56b
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/julaunchpgn@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test.png b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test.png
new file mode 100644
index 0000000..c95f6b5
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test.png
Binary files differ
diff --git a/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test@2x.png b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test@2x.png
new file mode 100644
index 0000000..c404f65
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/icons/full/obj16/test@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.unittest.junit/plugin.properties b/ui/org.eclipse.pde.unittest.junit/plugin.properties
new file mode 100644
index 0000000..2669ae7
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/plugin.properties
@@ -0,0 +1,29 @@
+#################################################################################
+#  Copyright (c) 2021 Red Hat, Inc.
+#
+#  This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License 2.0
+#  which accompanies this distribution, and is available at
+#  https://www.eclipse.org/legal/epl-2.0/
+#
+#  SPDX-License-Identifier: EPL-2.0
+#
+#  Contributors:
+#      Red Hat Inc. - initial API and implementation
+#################################################################################
+pluginName=Plug-in Development Unit Test support
+providerName=Eclipse.org
+
+JUnitPluginLaunchDelegate.name=Eclipse JUnit Plug-in Unit Test Launcher
+JUnitPluginLaunchDelegate.description=The Eclipse JUnit Plug-in Unit Test Launcher supports running and debugging Unit test suites for plug-in projects
+
+RunJUnitPluginLaunchShortcut.description=Runs a set of Unit tests
+DebugJUnitPluginLaunchShortcut.description=Debugs a set of Unit tests
+
+Launch.label= JUnit Plug-in Test (generic Test view)
+
+JUnitPluginTestShortcut.label= JUnit Plug-in Test (generic Test view)
+
+JUnitPluginTabGroup.description.debug= Create a configuration that will launch a Unit test in debug mode.
+JUnitPluginTabGroup.description.run= Create a configuration that will launch a Unit test.
+
diff --git a/ui/org.eclipse.pde.unittest.junit/plugin.xml b/ui/org.eclipse.pde.unittest.junit/plugin.xml
new file mode 100644
index 0000000..7c40da0
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/plugin.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+
+   <extension
+         point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+      <launchConfigurationTypeImage
+            icon="$nl$/icons/full/obj16/julaunchpgn.png"
+            configTypeID="org.eclipse.pde.unittest.junit.launchConfiguration"
+            id="org.eclipse.unittest.launchimage">
+      </launchConfigurationTypeImage>
+   </extension>
+   
+   <extension
+         point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+      <launchConfigurationTabGroup
+            class="org.eclipse.pde.unittest.junit.internal.launcher.JUnitPluginTabGroup"
+            helpContextId="org.eclipse.pde.doc.user.launcher_junit_plugin"
+            id="org.eclipse.pde.ui.launcher.JUnitPluginTabGroup"
+            type="org.eclipse.pde.unittest.junit.launchConfiguration">
+         <launchMode
+               description="%JUnitPluginTabGroup.description.debug"
+               perspective="org.eclipse.debug.ui.DebugPerspective"
+               mode="debug">
+         </launchMode>
+         <launchMode
+               description="%JUnitPluginTabGroup.description.run"
+               mode="run">
+         </launchMode>
+      </launchConfigurationTabGroup>
+   </extension>
+
+   <extension
+         point="org.eclipse.debug.core.launchConfigurationTypes">
+      <launchConfigurationType
+            allowCommandLine="true"
+            delegate="org.eclipse.pde.unittest.junit.launcher.AdvancedJUnitPluginLaunchConfigurationDelegate"
+            delegateDescription="%JUnitPluginLaunchDelegate.description"
+            delegateName="%JUnitPluginLaunchDelegate.name"
+            id="org.eclipse.pde.unittest.junit.launchConfiguration"
+            migrationDelegate="org.eclipse.pde.internal.launching.launcher.PDEMigrationDelegate"
+            modes="run, debug"
+            name="%Launch.label"
+            sourceLocatorId="org.eclipse.pde.ui.launcher.PDESourceLookupDirector"
+            sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
+      </launchConfigurationType>
+   </extension>
+
+   <extension
+         point="org.eclipse.debug.ui.launchShortcuts">
+      <shortcut
+            class="org.eclipse.pde.unittest.junit.launcher.JUnitPluginLaunchShortcut"
+            helpContextId="org.eclipse.pde.doc.user.launcher_junit_plugin"
+            icon="$nl$/icons/full/obj16/julaunchpgn.png"
+            id="org.eclipse.pde.ui.junitWorkbenchShortcut"
+            label="%JUnitPluginTestShortcut.label"
+            modes="run, debug">
+         <contextualLaunch>
+            <enablement>
+               <with variable="selection">
+                  <count value="1"/>
+               	  <iterate>
+                      <adapt type="org.eclipse.jdt.core.IJavaElement">
+		                <test property="org.eclipse.jdt.core.isInJavaProjectWithNature" value="org.eclipse.pde.PluginNature"/>
+		                <test property="org.eclipse.jdt.core.hasTypeOnClasspath" value="junit.framework.Test"/>
+		                <test property="org.eclipse.jdt.junit.canLaunchAsJUnit" forcePluginActivation="true"/>
+		             </adapt>
+		          </iterate>
+               </with>
+            </enablement>
+         </contextualLaunch>
+         <configurationType
+               id="org.eclipse.pde.unittest.junit.launchConfiguration">
+         </configurationType>
+         <description
+               description="%RunJUnitPluginLaunchShortcut.description"
+               mode="run">
+         </description>
+         <description
+               description="%DebugJUnitPluginLaunchShortcut.description"
+               mode="debug">
+         </description>
+      </shortcut>
+   </extension>
+
+   <extension
+         point="org.eclipse.unittest.ui.unittestViewSupport">
+      <viewSupport
+            class="org.eclipse.pde.unittest.junit.ui.JUnitPluginTestViewSupport"
+            id="org.eclipse.pde.unittest.junit">
+      </viewSupport>
+   </extension>
+</plugin>
diff --git a/ui/org.eclipse.pde.unittest.junit/pom.xml b/ui/org.eclipse.pde.unittest.junit/pom.xml
new file mode 100644
index 0000000..5034e6e
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright (c) 2012, 2021 Eclipse Foundation and others.
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Distribution License v1.0
+  which accompanies this distribution, and is available at
+  http://www.eclipse.org/org/documents/edl-v10.php
+ 
+  Contributors:
+     Igor Fedorenko - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>eclipse.pde.ui</artifactId>
+    <groupId>eclipse.pde.ui</groupId>
+    <version>4.20.0-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+  <groupId>org.eclipse.pde</groupId>
+  <artifactId>org.eclipse.pde.unittest.junit</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>eclipse-plugin</packaging>
+  <properties>
+      <skipAPIAnalysis>true</skipAPIAnalysis>
+  </properties>
+</project>
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/JUnitPluginTestPlugin.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/JUnitPluginTestPlugin.java
new file mode 100644
index 0000000..570fe51
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/JUnitPluginTestPlugin.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * The plug-in runtime class for the JUnit Plugin Unit Test plug-in.
+ */
+@SuppressWarnings("deprecation")
+public class JUnitPluginTestPlugin extends AbstractUIPlugin {
+
+	/**
+	 * The single instance of this plug-in runtime class.
+	 */
+	private static JUnitPluginTestPlugin fgPlugin = null;
+
+	public static final String PLUGIN_ID = "org.eclipse.pde.unittest.junit"; //$NON-NLS-1$
+
+	public static final String UNIT_TEST_VIEW_SUPPORT_ID = "org.eclipse.pde.unittest.junit"; //$NON-NLS-1$
+
+	private BundleContext fBundleContext;
+
+	public JUnitPluginTestPlugin() {
+		fgPlugin = this;
+	}
+
+	public static JUnitPluginTestPlugin getDefault() {
+		return fgPlugin;
+	}
+
+	public static String getPluginId() {
+		return PLUGIN_ID;
+	}
+
+	public static void log(Throwable e) {
+		log(new Status(IStatus.ERROR, getPluginId(), IStatus.ERROR, "Error", e)); //$NON-NLS-1$
+	}
+
+	public static void log(IStatus status) {
+		getDefault().getLog().log(status);
+	}
+
+	@Override
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		fBundleContext = context;
+	}
+
+	@Override
+	public void stop(BundleContext context) throws Exception {
+		super.stop(context);
+		fBundleContext = null;
+	}
+
+	/**
+	 * Returns a service with the specified name or <code>null</code> if none.
+	 *
+	 * @param serviceName name of service
+	 * @return service object or <code>null</code> if none
+	 */
+	public Object getService(String serviceName) {
+		ServiceReference<?> reference = fBundleContext.getServiceReference(serviceName);
+		if (reference == null)
+			return null;
+		return fBundleContext.getService(reference);
+	}
+
+	/**
+	 * Returns the bundle for a given bundle name, regardless whether the bundle is
+	 * resolved or not.
+	 *
+	 * @param bundleName the bundle name
+	 * @return the bundle
+	 */
+	public Bundle getBundle(String bundleName) {
+		Bundle[] bundles = getBundles(bundleName, null);
+		if (bundles != null && bundles.length > 0)
+			return bundles[0];
+		return null;
+	}
+
+	/**
+	 * Returns the bundles for a given bundle name,
+	 *
+	 * @param bundleName the bundle name
+	 * @param version    the version of the bundle
+	 * @return the bundles of the given name
+	 */
+	public Bundle[] getBundles(String bundleName, String version) {
+		Bundle[] bundles = Platform.getBundles(bundleName, version);
+		if (bundles != null)
+			return bundles;
+
+		// Accessing unresolved bundle
+		ServiceReference<PackageAdmin> serviceRef = fBundleContext.getServiceReference(PackageAdmin.class);
+		PackageAdmin admin = fBundleContext.getService(serviceRef);
+		bundles = admin.getBundles(bundleName, version);
+		if (bundles != null && bundles.length > 0)
+			return bundles;
+		return null;
+	}
+
+	/**
+	 * Returns this workbench window's shell.
+	 *
+	 * @return the shell containing this window's controls or <code>null</code> if
+	 *         the shell has not been created yet or if the window has been closed
+	 */
+	public static Shell getActiveWorkbenchShell() {
+		IWorkbenchWindow workBenchWindow = getActiveWorkbenchWindow();
+		if (workBenchWindow == null)
+			return null;
+		return workBenchWindow.getShell();
+	}
+
+	/**
+	 * Returns the active workbench window
+	 *
+	 * @return the active workbench window, or <code>null</code> if there is no
+	 *         active workbench window or if called from a non-UI thread
+	 */
+	public static IWorkbenchWindow getActiveWorkbenchWindow() {
+		if (fgPlugin == null)
+			return null;
+		IWorkbench workBench = PlatformUI.getWorkbench();
+		if (workBench == null)
+			return null;
+		return workBench.getActiveWorkbenchWindow();
+	}
+
+	/**
+	 * Returns the currently active page for this workbench window.
+	 *
+	 * @return the active page, or <code>null</code> if none
+	 */
+	public static IWorkbenchPage getActivePage() {
+		IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
+		if (activeWorkbenchWindow == null)
+			return null;
+		return activeWorkbenchWindow.getActivePage();
+	}
+
+	/**
+	 * Activates UnitTestBundle. Eclipse uses lazy bundle loading by default, which
+	 * means a bundle will not be loaded in many cases until some of its class is
+	 * used. This method allows the clients to instantiate the Unit Test bundle in
+	 * order to make it setup its launch listeners that are used to create and
+	 * activate Unit Test View. The Unit Test client bundles must call this method
+	 * before a Unit Test launch is created (preferably right before creation of the
+	 * launch in order to not make Eclipse to load the Unit Test bundle when it is
+	 * not really required), To load the Unit Test bundle the clients, for example,
+	 * might call this method inside their
+	 * 'ILaunchConfigurationDelegate2.getLaunch(ILaunchConfiguration, String)'
+	 * method of their launch configuration implementation.
+	 */
+	public static void activateUnitTestCoreBundle() {
+		Assert.isNotNull(Platform.getBundle("org.eclipse.unittest.ui")); //$NON-NLS-1$
+	}
+}
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/internal/launcher/JUnitPluginTabGroup.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/internal/launcher/JUnitPluginTabGroup.java
new file mode 100644
index 0000000..9422fb3
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/internal/launcher/JUnitPluginTabGroup.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.internal.launcher;
+
+import org.eclipse.jdt.debug.ui.launchConfigurations.JavaArgumentsTab;
+import org.eclipse.pde.ui.launcher.AbstractPDELaunchConfigurationTabGroup;
+import org.eclipse.pde.ui.launcher.ConfigurationTab;
+import org.eclipse.pde.ui.launcher.PluginJUnitMainTab;
+import org.eclipse.pde.ui.launcher.PluginsTab;
+import org.eclipse.pde.ui.launcher.TracingTab;
+import org.eclipse.pde.unittest.junit.launcher.JUnitPluginTestTab;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+
+import org.eclipse.jdt.internal.junit.launcher.AssertionVMArg;
+
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+
+public class JUnitPluginTabGroup extends AbstractPDELaunchConfigurationTabGroup {
+
+	@Override
+	public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+		ILaunchConfigurationTab[] tabs = null;
+		tabs = new ILaunchConfigurationTab[] { new JUnitPluginTestTab(), new PluginJUnitMainTab(),
+				new JavaArgumentsTab(), new PluginsTab(), new ConfigurationTab(true), new TracingTab(),
+				new EnvironmentTab(), new CommonTab() };
+		setTabs(tabs);
+	}
+
+	@Override
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+		super.setDefaults(configuration);
+
+		String vmArgs;
+		try {
+			vmArgs = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, ""); //$NON-NLS-1$
+		} catch (CoreException e) {
+			vmArgs = ""; //$NON-NLS-1$
+		}
+		vmArgs = AssertionVMArg.enableAssertInArgString(vmArgs);
+		if (vmArgs.length() > 0)
+			configuration.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, vmArgs);
+	}
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/AdvancedJUnitPluginLaunchConfigurationDelegate.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/AdvancedJUnitPluginLaunchConfigurationDelegate.java
new file mode 100644
index 0000000..8526daa
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/AdvancedJUnitPluginLaunchConfigurationDelegate.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.launcher;
+
+/**
+ * Launch configuration delegate for a JUnit test as a Java application with
+ * advanced source lookup support.
+ *
+ * @provisional This is part of work in progress and can be changed, moved or
+ *              removed without notice
+ */
+public class AdvancedJUnitPluginLaunchConfigurationDelegate extends JUnitPluginLaunchConfigurationDelegate {
+
+	public AdvancedJUnitPluginLaunchConfigurationDelegate() {
+		super();
+		allowAdvancedSourcelookup();
+	}
+
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java
new file mode 100644
index 0000000..61a06cc
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java
@@ -0,0 +1,1265 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.launcher;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.core.plugin.IFragmentModel;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+import org.eclipse.pde.core.plugin.TargetPlatform;
+import org.eclipse.pde.internal.core.ClasspathHelper;
+import org.eclipse.pde.internal.core.ICoreConstants;
+import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.internal.core.TargetPlatformHelper;
+import org.eclipse.pde.internal.core.util.CoreUtility;
+import org.eclipse.pde.internal.core.util.VersionUtil;
+import org.eclipse.pde.internal.launching.IPDEConstants;
+import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
+import org.eclipse.pde.internal.launching.launcher.EclipsePluginValidationOperation;
+import org.eclipse.pde.internal.launching.launcher.LaunchArgumentsHelper;
+import org.eclipse.pde.internal.launching.launcher.LaunchConfigurationHelper;
+import org.eclipse.pde.internal.launching.launcher.LaunchPluginValidator;
+import org.eclipse.pde.internal.launching.launcher.LauncherUtils;
+import org.eclipse.pde.internal.launching.launcher.VMHelper;
+import org.eclipse.pde.launching.IPDELauncherConstants;
+import org.eclipse.pde.launching.PDESourcePathProvider;
+import org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin;
+
+import org.eclipse.core.variables.VariablesPlugin;
+
+import org.eclipse.core.runtime.Assert;
+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.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.URIUtil;
+
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+
+import org.eclipse.jdt.internal.junit.launcher.ITestKind;
+import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
+import org.eclipse.jdt.internal.junit.launcher.JUnitRuntimeClasspathEntry;
+import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
+
+import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
+import org.eclipse.jdt.launching.ExecutionArguments;
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.IVMRunner;
+import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jdt.launching.SocketUtil;
+import org.eclipse.jdt.launching.VMRunnerConfiguration;
+
+import org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin;
+import org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin.JUnitVersion;
+
+/**
+ * Launch configuration delegate for a JUnit test as a Java application.
+ *
+ * <p>
+ * Clients can instantiate and extend this class.
+ * </p>
+ */
+public class JUnitPluginLaunchConfigurationDelegate extends AbstractJavaLaunchConfigurationDelegate {
+
+	// This needs to be differnet from JunitLaunchConfigurationConstants.ATTR_PORT
+	// or the "legacy" view handles it first
+	public static final String ATTR_PORT = JUnitPluginTestPlugin.PLUGIN_ID + ".PORT"; //$NON-NLS-1$
+
+	private boolean fKeepAlive = false;
+	private int fPort;
+	private IJavaElement[] fTestElements;
+
+	private static final String DEFAULT = "<default>"; //$NON-NLS-1$
+
+	@Override
+	public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+		JUnitPluginTestPlugin.activateUnitTestCoreBundle();
+		return super.getLaunch(configuration, mode);
+	}
+
+	@Override
+	public String showCommandLine(ILaunchConfiguration configuration, String mode, ILaunch launch,
+			IProgressMonitor monitor) throws CoreException {
+		launch.setAttribute(PDE_JUNIT_SHOW_COMMAND, "true"); //$NON-NLS-1$
+
+		if (monitor == null) {
+			monitor = new NullProgressMonitor();
+		}
+		try {
+			VMRunnerConfiguration runConfig = getVMRunnerConfiguration(configuration, launch, mode, monitor);
+			if (runConfig == null) {
+				return ""; //$NON-NLS-1$
+			}
+			IVMRunner runner = getVMRunner(configuration, mode);
+			String cmdLine = runner.showCommandLine(runConfig, launch, monitor);
+
+			// check for cancellation
+			if (monitor.isCanceled()) {
+				return ""; //$NON-NLS-1$
+			}
+			return cmdLine;
+		} finally {
+			monitor.done();
+		}
+	}
+
+	private VMRunnerConfiguration getVMRunnerConfiguration(ILaunchConfiguration configuration, ILaunch launch,
+			String mode, IProgressMonitor monitor) throws CoreException {
+		VMRunnerConfiguration runConfig = null;
+		monitor.beginTask(MessageFormat.format("{0}...", configuration.getName()), 5); //$NON-NLS-1$
+		// check for cancellation
+		if (monitor.isCanceled()) {
+			return null;
+		}
+
+		try {
+			if (mode.equals(JUnitLaunchConfigurationConstants.MODE_RUN_QUIETLY_MODE)) {
+				launch.setAttribute(JUnitLaunchConfigurationConstants.ATTR_NO_DISPLAY, "true"); //$NON-NLS-1$
+				mode = ILaunchManager.RUN_MODE;
+			}
+
+			monitor.subTask(Messages.JUnitPluginLaunchConfigurationDelegate_verifying_attriburtes_description);
+
+			try {
+				preLaunchCheck(configuration, launch, SubMonitor.convert(monitor, 2));
+			} catch (CoreException e) {
+				if (e.getStatus().getSeverity() == IStatus.CANCEL) {
+					monitor.setCanceled(true);
+					return null;
+				}
+				throw e;
+			}
+			// check for cancellation
+			if (monitor.isCanceled()) {
+				return null;
+			}
+
+			fKeepAlive = mode.equals(ILaunchManager.DEBUG_MODE)
+					&& configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_KEEPRUNNING, false);
+			fPort = evaluatePort();
+			launch.setAttribute(ATTR_PORT, String.valueOf(fPort));
+
+			JUnitVersion junitVersion = getJUnitVersion(configuration);
+			IJavaProject javaProject = getJavaProject(configuration);
+			if (junitVersion == JUnitVersion.JUNIT3 || junitVersion == JUnitVersion.JUNIT4) {
+				fTestElements = evaluateTests(configuration, SubMonitor.convert(monitor, 1));
+			} else {
+				IJavaElement testTarget = getTestTarget(configuration, javaProject);
+				if (testTarget instanceof IPackageFragment || testTarget instanceof IPackageFragmentRoot
+						|| testTarget instanceof IJavaProject) {
+					fTestElements = new IJavaElement[] { testTarget };
+				} else {
+					fTestElements = evaluateTests(configuration, SubMonitor.convert(monitor, 1));
+				}
+			}
+
+			String mainTypeName = verifyMainTypeName(configuration);
+
+			File workingDir = verifyWorkingDirectory(configuration);
+			String workingDirName = null;
+			if (workingDir != null) {
+				workingDirName = workingDir.getAbsolutePath();
+			}
+
+			// Environment variables
+			String[] envp = getEnvironment(configuration);
+
+			ArrayList<String> vmArguments = new ArrayList<>();
+			ArrayList<String> programArguments = new ArrayList<>();
+			collectExecutionArguments(configuration, vmArguments, programArguments);
+			vmArguments.addAll(Arrays.asList(DebugPlugin.parseArguments(getVMArguments(configuration, mode))));
+			if (JavaRuntime.isModularProject(javaProject)) {
+				vmArguments.add("--add-modules=ALL-MODULE-PATH"); //$NON-NLS-1$
+			}
+
+			// VM-specific attributes
+
+			Map<String, Object> vmAttributesMap = getVMSpecificAttributesMap(configuration);
+
+			// Classpath and modulepath
+			String[][] classpathAndModulepath = getClasspathAndModulepath(configuration);
+			String[] classpath = classpathAndModulepath[0];
+			String[] modulepath = classpathAndModulepath[1];
+
+			if (junitVersion == JUnitVersion.JUNIT5) {
+				if (!configuration.getAttribute(
+						JUnitLaunchConfigurationConstants.ATTR_DONT_ADD_MISSING_JUNIT5_DEPENDENCY, false)) {
+					if (!Arrays.stream(classpath).anyMatch(
+							s -> s.contains("junit-platform-launcher") || s.contains("org.junit.platform.launcher"))) { //$NON-NLS-1$ //$NON-NLS-2$
+						try {
+							JUnitRuntimeClasspathEntry x = new JUnitRuntimeClasspathEntry("org.junit.platform.launcher", //$NON-NLS-1$
+									null);
+							String entryString = new ClasspathLocalizer(Platform.inDevelopmentMode()).entryString(x);
+							int length = classpath.length;
+							System.arraycopy(classpath, 0, classpath = new String[length + 1], 0, length);
+							classpath[length] = entryString;
+						} catch (IOException | URISyntaxException e) {
+							throw new CoreException(
+									new Status(IStatus.ERROR, JUnitPluginTestPlugin.PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+						}
+					}
+				}
+			}
+
+			// Create VM config
+			runConfig = new VMRunnerConfiguration(mainTypeName, classpath);
+			runConfig.setVMArguments(vmArguments.toArray(new String[vmArguments.size()]));
+			runConfig.setProgramArguments(programArguments.toArray(new String[programArguments.size()]));
+			runConfig.setEnvironment(envp);
+			runConfig.setWorkingDirectory(workingDirName);
+			runConfig.setVMSpecificAttributesMap(vmAttributesMap);
+			runConfig.setPreviewEnabled(supportsPreviewFeatures(configuration));
+
+			if (!JavaRuntime.isModularConfiguration(configuration)) {
+				// Bootpath
+				runConfig.setBootClassPath(getBootpath(configuration));
+			} else {
+				// module path
+				runConfig.setModulepath(modulepath);
+				if (!configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_MODULE_CLI_OPTIONS,
+						true)) {
+					runConfig.setOverrideDependencies(
+							configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_CLI_OPTIONS, "")); //$NON-NLS-1$
+				} else {
+					runConfig.setOverrideDependencies(getModuleCLIOptions(configuration));
+				}
+			}
+
+			// check for cancellation
+			if (monitor.isCanceled()) {
+				return null;
+			}
+		} finally {
+			// done the verification phase
+			monitor.worked(1);
+		}
+		return runConfig;
+	}
+
+	static JUnitVersion getJUnitVersion(ILaunchConfiguration configuration) {
+		try {
+			String junitTestKindId = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
+					""); //$NON-NLS-1$
+			if (!junitTestKindId.isEmpty()) {
+				return JUnitVersion.fromJUnitTestKindId(junitTestKindId);
+			}
+		} catch (Exception ex) {
+			JUnitPluginTestPlugin.log(ex);
+		}
+		IJavaProject javaProject = JUnitLaunchConfigurationConstants.getJavaProject(configuration);
+		if (javaProject != null) {
+			return JUnitTestPlugin.getJUnitVersion(javaProject);
+		}
+		return JUnitVersion.JUNIT3;
+	}
+
+	@Override
+	public synchronized void launch(ILaunchConfiguration configuration, String mode, ILaunch launch,
+			IProgressMonitor monitor) throws CoreException {
+		if (monitor == null) {
+			monitor = new NullProgressMonitor();
+		}
+
+		try {
+
+			VMRunnerConfiguration runConfig = getVMRunnerConfiguration(configuration, launch, mode, monitor);
+			if (monitor.isCanceled() || runConfig == null) {
+				return;
+			}
+			IVMRunner runner = getVMRunner(configuration, mode);
+			monitor.subTask(Messages.JUnitPluginLaunchConfigurationDelegate_create_source_locator_description);
+			// set the default source locator if required
+			setDefaultSourceLocator(launch, configuration);
+			monitor.worked(1);
+
+			// Launch the configuration - 1 unit of work
+			runner.run(runConfig, launch, monitor);
+		} finally {
+			fTestElements = null;
+			monitor.done();
+		}
+	}
+
+	private int evaluatePort() throws CoreException {
+		int port = SocketUtil.findFreePort();
+		if (port == -1) {
+			abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_no_socket, null,
+					IJavaLaunchConfigurationConstants.ERR_NO_SOCKET_AVAILABLE);
+		}
+		return port;
+	}
+
+	/**
+	 * Performs a check on the launch configuration's attributes. If an attribute
+	 * contains an invalid value, a {@link CoreException} with the error is thrown.
+	 *
+	 * @param configuration the launch configuration to verify
+	 * @param launch        the launch to verify
+	 * @param monitor       the progress monitor to use
+	 * @throws CoreException an exception is thrown when the verification fails
+	 */
+	protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor)
+			throws CoreException {
+		fWorkspaceLocation = null;
+		fConfigDir = null;
+		fModels = BundleLauncherHelper.getMergedBundleMap(configuration, false);
+		fAllBundles = new LinkedHashMap<>(fModels.size());
+		Iterator<IPluginModelBase> iter = fModels.keySet().iterator();
+		while (iter.hasNext()) {
+			IPluginModelBase model = iter.next();
+			fAllBundles.put(model.getPluginBase().getId(), model);
+		}
+
+		// implicitly add the plug-ins required for JUnit testing if necessary
+		String[] requiredPlugins = getRequiredPlugins(configuration);
+		for (String requiredPlugin : requiredPlugins) {
+			String id = requiredPlugin;
+			if (!fAllBundles.containsKey(id)) {
+				IPluginModelBase model = findRequiredPluginInTargetOrHost(id);
+				fAllBundles.put(id, model);
+				fModels.put(model, "default:default"); //$NON-NLS-1$
+			}
+		}
+		String attribute = launch.getAttribute(PDE_JUNIT_SHOW_COMMAND);
+		boolean isShowCommand = false;
+		if (attribute != null) {
+			isShowCommand = attribute.equals("true"); //$NON-NLS-1$
+		}
+		boolean autoValidate = configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_VALIDATE, false);
+		SubMonitor subMonitor = SubMonitor.convert(monitor, autoValidate ? 3 : 4);
+		if (isShowCommand == false) {
+			if (autoValidate)
+				validatePluginDependencies(configuration, subMonitor.split(1));
+			validateProjectDependencies(configuration, subMonitor.split(1));
+			LauncherUtils.setLastLaunchMode(launch.getLaunchMode());
+			clear(configuration, subMonitor.split(1));
+		}
+		launch.setAttribute(PDE_JUNIT_SHOW_COMMAND, "false"); //$NON-NLS-1$
+		launch.setAttribute(IPDELauncherConstants.CONFIG_LOCATION, getConfigurationDirectory(configuration).toString());
+		synchronizeManifests(configuration, subMonitor.split(1));
+	}
+
+	@Override
+	public String getJavaProjectName(ILaunchConfiguration configuration) throws CoreException {
+		return configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
+	}
+
+	@Override
+	public String getMainTypeName(ILaunchConfiguration configuration) throws CoreException {
+		String mainType = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
+				(String) null);
+		if (mainType == null) {
+			return null;
+		}
+		return VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(mainType);
+	}
+
+	@Override
+	public String verifyMainTypeName(ILaunchConfiguration configuration) throws CoreException {
+		if (TargetPlatformHelper.getTargetVersion() >= 3.3)
+			return "org.eclipse.equinox.launcher.Main"; //$NON-NLS-1$
+		return "org.eclipse.core.launcher.Main"; //$NON-NLS-1$
+	}
+
+	/**
+	 * Evaluates all test elements selected by the given launch configuration. The
+	 * elements are of type {@link IType} or {@link IMethod}. At the moment it is
+	 * only possible to run a single method or a set of types, but not mixed or more
+	 * than one method at a time.
+	 *
+	 * @param configuration the launch configuration to inspect
+	 * @param monitor       the progress monitor
+	 * @return returns all types or methods that should be ran
+	 * @throws CoreException an exception is thrown when the search for tests failed
+	 */
+	protected IMember[] evaluateTests(ILaunchConfiguration configuration, IProgressMonitor monitor)
+			throws CoreException {
+		IJavaProject javaProject = getJavaProject(configuration);
+
+		IJavaElement testTarget = getTestTarget(configuration, javaProject);
+		String testMethodName = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_NAME, ""); //$NON-NLS-1$
+		if (testMethodName.length() > 0) {
+			if (testTarget instanceof IType) {
+				// If parameters exist, testMethodName is followed by a comma-separated list of
+				// fully qualified parameter type names in parentheses.
+				// The testMethodName is required in this format by #collectExecutionArguments,
+				// hence it will be used as it is with the handle-only method IType#getMethod
+				// here.
+				return new IMember[] { ((IType) testTarget).getMethod(testMethodName, new String[0]) };
+			}
+		}
+		HashSet<IType> result = new HashSet<>();
+		org.eclipse.jdt.internal.junit.launcher.ITestKind junitTestKind = getJUnitVersion(configuration)
+				.getJUnitTestKind();
+		junitTestKind.getFinder().findTestsInContainer(testTarget, result, monitor);
+		if (result.isEmpty()) {
+			String msg = MessageFormat.format(Messages.JUnitPluginLaunchConfigurationDelegate_error_notests_kind,
+					junitTestKind.getDisplayName());
+			abort(msg, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+		}
+		return result.toArray(new IMember[result.size()]);
+	}
+
+	/**
+	 * Collects all VM and program arguments. Implementors can modify and add
+	 * arguments.
+	 *
+	 * @param configuration the configuration to collect the arguments for
+	 * @param vmArguments   a {@link List} of {@link String} representing the
+	 *                      resulting VM arguments
+	 * @param programArgs   a {@link List} of {@link String} representing the
+	 *                      resulting program arguments
+	 * @exception CoreException if unable to collect the execution arguments
+	 */
+	protected void collectExecutionArguments(ILaunchConfiguration configuration, List<String> vmArguments,
+			List<String> programArgs) throws CoreException {
+		internalCollectExecutionArguments(configuration, vmArguments, programArgs);
+
+		// Specify the JUnit Plug-in test application to launch
+		programArgs.add("-application"); //$NON-NLS-1$
+		String application = getApplication(configuration);
+
+		programArgs.add(application);
+
+		// If a product is specified, then add it to the program args
+		if (configuration.getAttribute(IPDELauncherConstants.USE_PRODUCT, false)) {
+			programArgs.add("-product"); //$NON-NLS-1$
+			programArgs.add(configuration.getAttribute(IPDELauncherConstants.PRODUCT, "")); //$NON-NLS-1$
+		} else {
+			// Specify the application to test
+			String defaultApplication = TargetPlatform.getDefaultApplication();
+			if (IPDEConstants.CORE_TEST_APPLICATION.equals(application)) {
+				// If we are launching the core test application we don't need a test app
+				defaultApplication = null;
+			} else if (IPDEConstants.NON_UI_THREAD_APPLICATION.equals(application)) {
+				// When running in a non-UI thread, run the core test app to avoid opening the
+				// workbench
+				defaultApplication = IPDEConstants.CORE_TEST_APPLICATION;
+			}
+
+			String testApplication = configuration.getAttribute(IPDELauncherConstants.APP_TO_TEST, defaultApplication);
+			if (testApplication != null) {
+				programArgs.add("-testApplication"); //$NON-NLS-1$
+				programArgs.add(testApplication);
+			}
+		}
+
+		// Specify the location of the runtime workbench
+		if (fWorkspaceLocation == null) {
+			fWorkspaceLocation = LaunchArgumentsHelper.getWorkspaceLocation(configuration);
+		}
+		if (fWorkspaceLocation.length() > 0) {
+			programArgs.add("-data"); //$NON-NLS-1$
+			programArgs.add(fWorkspaceLocation);
+		}
+
+		// Create the platform configuration for the runtime workbench
+		String productID = LaunchConfigurationHelper.getProductID(configuration);
+		LaunchConfigurationHelper.createConfigIniFile(configuration, productID, fAllBundles, fModels,
+				getConfigurationDirectory(configuration));
+		TargetPlatformHelper.checkPluginPropertiesConsistency(fAllBundles, getConfigurationDirectory(configuration));
+
+		programArgs.add("-configuration"); //$NON-NLS-1$
+		programArgs.add("file:" //$NON-NLS-1$
+				+ new Path(getConfigurationDirectory(configuration).getPath()).addTrailingSeparator().toString());
+
+		// Specify the output folder names
+		programArgs.add("-dev"); //$NON-NLS-1$
+		programArgs.add(ClasspathHelper.getDevEntriesProperties(
+				getConfigurationDirectory(configuration).toString() + "/dev.properties", fAllBundles)); //$NON-NLS-1$
+
+		// Create the .options file if tracing is turned on
+		if (configuration.getAttribute(IPDELauncherConstants.TRACING, false) && !IPDELauncherConstants.TRACING_NONE
+				.equals(configuration.getAttribute(IPDELauncherConstants.TRACING_CHECKED, (String) null))) {
+			programArgs.add("-debug"); //$NON-NLS-1$
+			String path = getConfigurationDirectory(configuration).getPath() + IPath.SEPARATOR
+					+ ICoreConstants.OPTIONS_FILENAME;
+			programArgs.add(LaunchArgumentsHelper.getTracingFileArgument(configuration, path));
+		}
+
+		// add the program args specified by the user
+		String[] userArgs = LaunchArgumentsHelper.getUserProgramArgumentArray(configuration);
+		for (String userArg : userArgs) {
+			// be forgiving if people have tracing turned on and forgot
+			// to remove the -debug from the program args field.
+			if (userArg.equals("-debug") && programArgs.contains("-debug")) //$NON-NLS-1$ //$NON-NLS-2$
+				continue;
+			programArgs.add(userArg);
+		}
+
+		if (!configuration.getAttribute(IPDEConstants.APPEND_ARGS_EXPLICITLY, false)) {
+			if (!programArgs.contains("-os")) { //$NON-NLS-1$
+				programArgs.add("-os"); //$NON-NLS-1$
+				programArgs.add(TargetPlatform.getOS());
+			}
+			if (!programArgs.contains("-ws")) { //$NON-NLS-1$
+				programArgs.add("-ws"); //$NON-NLS-1$
+				programArgs.add(TargetPlatform.getWS());
+			}
+			if (!programArgs.contains("-arch")) { //$NON-NLS-1$
+				programArgs.add("-arch"); //$NON-NLS-1$
+				programArgs.add(TargetPlatform.getOSArch());
+			}
+		}
+
+		programArgs.add("-testpluginname"); //$NON-NLS-1$
+		programArgs.add(getTestPluginId(configuration));
+		IVMInstall launcher = VMHelper.createLauncher(configuration);
+		boolean isModular = JavaRuntime.isModularJava(launcher);
+		if (isModular) {
+			String modAllSystem = "--add-modules=ALL-SYSTEM"; //$NON-NLS-1$
+			if (!vmArguments.contains(modAllSystem))
+				vmArguments.add(modAllSystem);
+		}
+		// if element is a test class annotated with @RunWith(JUnitPlatform.class, we
+		// add this in program arguments
+		if (configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_RUN_WITH_JUNIT_PLATFORM_ANNOTATION,
+				false)) {
+			programArgs.add("-runasjunit5"); //$NON-NLS-1$
+		}
+	}
+
+	private void internalCollectExecutionArguments(ILaunchConfiguration configuration, List<String> vmArguments,
+			List<String> programArguments) throws CoreException {
+
+		// add program & VM arguments provided by getProgramArguments and getVMArguments
+		String pgmArgs = getProgramArguments(configuration);
+		String vmArgs = getVMArguments(configuration);
+		ExecutionArguments execArgs = new ExecutionArguments(vmArgs, pgmArgs);
+		vmArguments.addAll(Arrays.asList(execArgs.getVMArgumentsArray()));
+		programArguments.addAll(Arrays.asList(execArgs.getProgramArgumentsArray()));
+
+		boolean isModularProject = JavaRuntime.isModularProject(getJavaProject(configuration));
+		String addOpensTargets;
+		if (isModularProject) {
+			if (getJUnitVersion(configuration) == JUnitVersion.JUNIT5) {
+				if (isOnModulePath(getJavaProject(configuration), "org.junit.jupiter.api.Test")) { //$NON-NLS-1$
+					addOpensTargets = "org.junit.platform.commons,ALL-UNNAMED"; //$NON-NLS-1$
+				} else {
+					addOpensTargets = "ALL-UNNAMED"; //$NON-NLS-1$
+				}
+			} else {
+				if (isOnModulePath(getJavaProject(configuration), "junit.framework.TestCase")) { //$NON-NLS-1$
+					addOpensTargets = "junit,ALL-UNNAMED"; //$NON-NLS-1$
+				} else {
+					addOpensTargets = "ALL-UNNAMED"; //$NON-NLS-1$
+				}
+			}
+		} else {
+			addOpensTargets = null;
+		}
+		List<String> addOpensVmArgs = new ArrayList<>();
+
+		/*
+		 * The "-version" "3" arguments don't make sense and should eventually be
+		 * removed. But we keep them for now, since users may want to run with older
+		 * releases of org.eclipse.jdt.junit[4].runtime, where this is still read by
+		 * org.eclipse.jdt.internal.junit.runner.RemoteTestRunner#defaultInit(String[])
+		 * and used in
+		 * org.eclipse.jdt.internal.junit.runner.DefaultClassifier#isComparisonFailure(
+		 * Throwable). The JUnit4 equivalent of the latter method is already
+		 * version-agnostic:
+		 * org.eclipse.jdt.internal.junit4.runner.JUnit4TestListener#testFailure(
+		 * Failure, boolean)
+		 */
+		programArguments.add("-version"); //$NON-NLS-1$
+		programArguments.add("3"); //$NON-NLS-1$
+
+		programArguments.add("-port"); //$NON-NLS-1$
+		programArguments.add(String.valueOf(fPort));
+
+		if (fKeepAlive)
+			programArguments.add(0, "-keepalive"); //$NON-NLS-1$
+
+		ITestKind testRunnerKind = getJUnitVersion(configuration).getJUnitTestKind();
+
+		programArguments.add("-testLoaderClass"); //$NON-NLS-1$
+		programArguments.add(testRunnerKind.getLoaderClassName());
+		programArguments.add("-loaderpluginname"); //$NON-NLS-1$
+		programArguments.add(testRunnerKind.getLoaderPluginId());
+
+		// Enable Debugging mode:
+		// programArguments.add("-debugging"); //$NON-NLS-1$
+
+		IJavaElement[] testElements = fTestElements;
+
+		if (testElements.length == 1) { // a test name was specified just run the single test, or a test container was
+										// specified
+			IJavaElement testElement = testElements[0];
+			if (testElement instanceof IMethod) {
+				IMethod method = (IMethod) testElement;
+				programArguments.add("-test"); //$NON-NLS-1$
+				programArguments.add(method.getDeclaringType().getFullyQualifiedName() + ':' + method.getElementName());
+				collectAddOpensVmArgs(addOpensTargets, addOpensVmArgs, method, configuration);
+			} else if (testElement instanceof IType) {
+				IType type = (IType) testElement;
+				programArguments.add("-classNames"); //$NON-NLS-1$
+				programArguments.add(type.getFullyQualifiedName());
+				collectAddOpensVmArgs(addOpensTargets, addOpensVmArgs, type, configuration);
+			} else if (testElement instanceof IPackageFragment || testElement instanceof IPackageFragmentRoot
+					|| testElement instanceof IJavaProject) {
+				Set<String> pkgNames = new HashSet<>();
+				String fileName = createPackageNamesFile(testElement, testRunnerKind, pkgNames);
+				programArguments.add("-packageNameFile"); //$NON-NLS-1$
+				programArguments.add(fileName);
+				for (String pkgName : pkgNames) {
+					if (!DEFAULT.equals(pkgName)) { // skip --add-opens for default package
+						collectAddOpensVmArgs(addOpensTargets, addOpensVmArgs, pkgName, configuration);
+					}
+				}
+			} else {
+				abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_wrong_input, null,
+						IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+			}
+		} else if (testElements.length > 1) {
+			String fileName = createTestNamesFile(testElements);
+			programArguments.add("-testNameFile"); //$NON-NLS-1$
+			programArguments.add(fileName);
+			for (IJavaElement testElement : testElements) {
+				collectAddOpensVmArgs(addOpensTargets, addOpensVmArgs, testElement, configuration);
+			}
+		}
+
+		String testFailureNames = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_FAILURES_NAMES, ""); //$NON-NLS-1$
+		if (testFailureNames.length() > 0) {
+			programArguments.add("-testfailures"); //$NON-NLS-1$
+			programArguments.add(testFailureNames);
+		}
+
+		String uniqueId = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_UNIQUE_ID, ""); //$NON-NLS-1$
+		if (!uniqueId.trim().isEmpty()) {
+			programArguments.add("-uniqueId"); //$NON-NLS-1$
+			programArguments.add(uniqueId);
+		}
+
+		boolean hasIncludeTags = configuration
+				.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_HAS_INCLUDE_TAGS, false);
+		if (hasIncludeTags) {
+			String includeTags = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_INCLUDE_TAGS,
+					""); //$NON-NLS-1$
+			if (includeTags != null && !includeTags.trim().isEmpty()) {
+				String[] tags = includeTags.split(","); //$NON-NLS-1$
+				for (String tag : tags) {
+					programArguments.add("--include-tag"); //$NON-NLS-1$
+					programArguments.add(tag.trim());
+				}
+			}
+		}
+
+		boolean hasExcludeTags = configuration
+				.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_HAS_EXCLUDE_TAGS, false);
+		if (hasExcludeTags) {
+			String excludeTags = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_EXCLUDE_TAGS,
+					""); //$NON-NLS-1$
+			if (excludeTags != null && !excludeTags.trim().isEmpty()) {
+				String[] tags = excludeTags.split(","); //$NON-NLS-1$
+				for (String tag : tags) {
+					programArguments.add("--exclude-tag"); //$NON-NLS-1$
+					programArguments.add(tag.trim());
+				}
+			}
+		}
+
+		if (addOpensTargets != null) {
+			vmArguments.addAll(addOpensVmArgs);
+		}
+	}
+
+	private static boolean isOnModulePath(IJavaProject javaProject, String typeToCheck) {
+		try {
+			IType type = javaProject.findType(typeToCheck);
+			if (type == null)
+				return false;
+			IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) type.getPackageFragment().getParent();
+			IClasspathEntry resolvedClasspathEntry = packageFragmentRoot.getResolvedClasspathEntry();
+			return Arrays.stream(resolvedClasspathEntry.getExtraAttributes())
+					.anyMatch(p -> p.getName().equals(IClasspathAttribute.MODULE) && p.getValue().equals("true")); //$NON-NLS-1$
+		} catch (JavaModelException e) {
+			// if anything goes wrong, assume true (in the worst case, user get a warning
+			// because of a redundant add-opens)
+			return true;
+		}
+	}
+
+	private void collectAddOpensVmArgs(String addOpensTargets, List<String> addOpensVmArgs, IJavaElement javaElem,
+			ILaunchConfiguration configuration) throws CoreException {
+		if (addOpensTargets != null) {
+			IPackageFragment pkg = getParentPackageFragment(javaElem);
+			if (pkg != null) {
+				String pkgName = pkg.getElementName();
+				collectAddOpensVmArgs(addOpensTargets, addOpensVmArgs, pkgName, configuration);
+			}
+		}
+	}
+
+	private void collectAddOpensVmArgs(String addOpensTargets, List<String> addOpensVmArgs, String pkgName,
+			ILaunchConfiguration configuration) throws CoreException {
+		if (addOpensTargets != null) {
+			IJavaProject javaProject = getJavaProject(configuration);
+			String sourceModuleName = javaProject.getModuleDescription().getElementName();
+			addOpensVmArgs.add("--add-opens"); //$NON-NLS-1$
+			addOpensVmArgs.add(sourceModuleName + "/" + pkgName + "=" + addOpensTargets); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	private IPackageFragment getParentPackageFragment(IJavaElement element) {
+		IJavaElement parent = element.getParent();
+		while (parent != null) {
+			if (parent instanceof IPackageFragment) {
+				return (IPackageFragment) parent;
+			}
+			parent = parent.getParent();
+		}
+		return null;
+	}
+
+	private String createPackageNamesFile(IJavaElement testContainer, ITestKind testRunnerKind, Set<String> pkgNames)
+			throws CoreException {
+		try {
+			File file = File.createTempFile("packageNames", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$
+			file.deleteOnExit();
+
+			try (BufferedWriter bw = new BufferedWriter(
+					new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
+				if (testContainer instanceof IPackageFragment) {
+					pkgNames.add(getPackageName(testContainer.getElementName()));
+				} else if (testContainer instanceof IPackageFragmentRoot) {
+					addAllPackageFragments((IPackageFragmentRoot) testContainer, pkgNames);
+				} else if (testContainer instanceof IJavaProject) {
+					for (IPackageFragmentRoot pkgFragmentRoot : ((IJavaProject) testContainer)
+							.getPackageFragmentRoots()) {
+						if (!pkgFragmentRoot.isExternal() && !pkgFragmentRoot.isArchive()) {
+							addAllPackageFragments(pkgFragmentRoot, pkgNames);
+						}
+					}
+				} else {
+					abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_wrong_input, null,
+							IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+				}
+				if (pkgNames.isEmpty()) {
+					String msg = MessageFormat.format(
+							Messages.JUnitPluginLaunchConfigurationDelegate_error_notests_kind,
+							testRunnerKind.getDisplayName());
+					abort(msg, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+				} else {
+					for (String pkgName : pkgNames) {
+						bw.write(pkgName);
+						bw.newLine();
+					}
+				}
+			}
+			return file.getAbsolutePath();
+		} catch (IOException | JavaModelException e) {
+			throw new CoreException(new Status(IStatus.ERROR, JUnitPluginTestPlugin.PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+		}
+	}
+
+	private Set<String> addAllPackageFragments(IPackageFragmentRoot pkgFragmentRoot, Set<String> pkgNames)
+			throws JavaModelException {
+		for (IJavaElement child : pkgFragmentRoot.getChildren()) {
+			if (child instanceof IPackageFragment && ((IPackageFragment) child).hasChildren()) {
+				pkgNames.add(getPackageName(child.getElementName()));
+			}
+		}
+		return pkgNames;
+	}
+
+	private String getPackageName(String elementName) {
+		if (elementName.isEmpty()) {
+			return DEFAULT;
+		}
+		return elementName;
+	}
+
+	private String createTestNamesFile(IJavaElement[] testElements) throws CoreException {
+		try {
+			File file = File.createTempFile("testNames", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$
+			file.deleteOnExit();
+			try (BufferedWriter bw = new BufferedWriter(
+					new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));) {
+				for (IJavaElement testElement : testElements) {
+					if (testElement instanceof IType) {
+						IType type = (IType) testElement;
+						String testName = type.getFullyQualifiedName();
+						bw.write(testName);
+						bw.newLine();
+					} else {
+						abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_wrong_input, null,
+								IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+					}
+				}
+			}
+			return file.getAbsolutePath();
+		} catch (IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, JUnitPluginTestPlugin.PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	public String[][] getClasspathAndModulepath(ILaunchConfiguration configuration) throws CoreException {
+		String[] classpath = LaunchArgumentsHelper.constructClasspath(configuration);
+		if (classpath == null) {
+			abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_noStartup, null, IStatus.OK);
+		}
+		String[][] cpmp = internalGetClasspathAndModulepath(configuration);
+		cpmp[0] = classpath;
+		return cpmp;
+	}
+
+	public String[][] internalGetClasspathAndModulepath(ILaunchConfiguration configuration) throws CoreException {
+		String[][] cpmp = super.getClasspathAndModulepath(configuration);
+		String[] cp = cpmp[0];
+
+		List<String> junitEntries = new ClasspathLocalizer(Platform.inDevelopmentMode())
+				.localizeClasspath(getJUnitVersion(configuration));
+
+		String[] classPath = new String[cp.length + junitEntries.size()];
+		Object[] jea = junitEntries.toArray();
+		System.arraycopy(cp, 0, classPath, 0, cp.length);
+		System.arraycopy(jea, 0, classPath, cp.length, jea.length);
+
+		cpmp[0] = classPath;
+
+		return cpmp;
+	}
+
+	private static class ClasspathLocalizer {
+
+		private boolean fInDevelopmentMode;
+
+		public ClasspathLocalizer(boolean inDevelopmentMode) {
+			fInDevelopmentMode = inDevelopmentMode;
+		}
+
+		public List<String> localizeClasspath(JUnitVersion junitVersion) {
+			JUnitRuntimeClasspathEntry[] entries = junitVersion.getJUnitTestKind().getClasspathEntries();
+			List<String> junitEntries = new ArrayList<>();
+
+			for (JUnitRuntimeClasspathEntry entrie : entries) {
+				try {
+					addEntry(junitEntries, entrie);
+				} catch (IOException | URISyntaxException e) {
+					Assert.isTrue(false, entrie.getPluginId() + " is available (required JAR)"); //$NON-NLS-1$
+				}
+			}
+			return junitEntries;
+		}
+
+		private void addEntry(List<String> junitEntries, final JUnitRuntimeClasspathEntry entry)
+				throws IOException, MalformedURLException, URISyntaxException {
+			String entryString = entryString(entry);
+			if (entryString != null)
+				junitEntries.add(entryString);
+		}
+
+		private String entryString(final JUnitRuntimeClasspathEntry entry)
+				throws IOException, MalformedURLException, URISyntaxException {
+			if (inDevelopmentMode()) {
+				try {
+					return localURL(entry.developmentModeEntry());
+				} catch (IOException e3) {
+					// fall through and try default
+				}
+			}
+			return localURL(entry);
+		}
+
+		private boolean inDevelopmentMode() {
+			return fInDevelopmentMode;
+		}
+
+		private String localURL(JUnitRuntimeClasspathEntry jar)
+				throws IOException, MalformedURLException, URISyntaxException {
+			Bundle bundle = JUnitPluginTestPlugin.getDefault().getBundle(jar.getPluginId());
+			URL url;
+			if (jar.getPluginRelativePath() == null) {
+				String bundleClassPath = bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
+				url = bundleClassPath != null ? bundle.getEntry(bundleClassPath) : null;
+				if (url == null) {
+					url = bundle.getEntry("/"); //$NON-NLS-1$
+				}
+			} else {
+				url = bundle.getEntry(jar.getPluginRelativePath());
+			}
+
+			if (url == null)
+				throw new IOException();
+			return URIUtil.toFile(URIUtil.toURI(FileLocator.toFileURL(url))).getAbsolutePath(); // See bug 503050
+		}
+	}
+
+	private final IJavaElement getTestTarget(ILaunchConfiguration configuration, IJavaProject javaProject)
+			throws CoreException {
+		String containerHandle = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$
+		if (containerHandle.length() != 0) {
+			IJavaElement element = JavaCore.create(containerHandle);
+			if (element == null || !element.exists()) {
+				abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_input_element_deosn_not_exist, null,
+						IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+			}
+			return element;
+		}
+		String testTypeName = getMainTypeName(configuration);
+		if (testTypeName != null && testTypeName.length() != 0) {
+			IType type = javaProject.findType(testTypeName);
+			if (type != null && type.exists()) {
+				return type;
+			}
+		}
+		abort(Messages.JUnitPluginLaunchConfigurationDelegate_input_type_does_not_exist, null,
+				IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+		return null; // not reachable
+	}
+
+	@Override
+	protected void abort(String message, Throwable exception, int code) throws CoreException {
+		throw new CoreException(new Status(IStatus.ERROR, JUnitPluginTestPlugin.PLUGIN_ID, code, message, exception));
+	}
+
+	// PDE JUnit delegate
+	/**
+	 * To avoid duplicating variable substitution (and duplicate prompts) this
+	 * variable will store the substituted workspace location.
+	 */
+	private String fWorkspaceLocation;
+
+	/**
+	 * Caches the configuration directory when a launch is started
+	 */
+	protected File fConfigDir = null;
+
+	// used to generate the dev classpath entries
+	// key is bundle ID, value is a model
+	private Map<String, IPluginModelBase> fAllBundles;
+
+	// key is a model, value is startLevel:autoStart
+	private Map<IPluginModelBase, String> fModels;
+
+	private static final String PDE_JUNIT_SHOW_COMMAND = "pde.junit.showcommandline"; //$NON-NLS-1$
+
+	@Override
+	public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) throws CoreException {
+		IVMInstall launcher = VMHelper.createLauncher(configuration);
+		return launcher.getVMRunner(mode);
+	}
+
+	private String getTestPluginId(ILaunchConfiguration configuration) throws CoreException {
+		IJavaProject javaProject = getJavaProject(configuration);
+		IPluginModelBase model = PluginRegistry.findModel(javaProject.getProject());
+		if (model == null) {
+			abort(NLS.bind(Messages.JUnitPluginLaunchConfigurationDelegate_error_notaplugin,
+					javaProject.getProject().getName()), null, IStatus.OK);
+			return null;
+		}
+		if (model instanceof IFragmentModel)
+			return ((IFragmentModel) model).getFragment().getPluginId();
+
+		return model.getPluginBase().getId();
+	}
+
+	@Override
+	public String getModuleCLIOptions(ILaunchConfiguration configuration) throws CoreException {
+		// The JVM options should be specified in target platform, see getVMArguments()
+		return ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns the application to launch plug-in tests with
+	 *
+	 * @since 3.5
+	 *
+	 * @param configuration The launch configuration in which the application is
+	 *                      specified.
+	 * @return the application
+	 */
+	protected String getApplication(ILaunchConfiguration configuration) {
+		String application = null;
+
+		boolean shouldRunInUIThread = true;
+		try {
+			shouldRunInUIThread = configuration.getAttribute(IPDELauncherConstants.RUN_IN_UI_THREAD, true);
+		} catch (CoreException e) {
+			// Ignore
+		}
+
+		if (!shouldRunInUIThread) {
+			return IPDEConstants.NON_UI_THREAD_APPLICATION;
+		}
+
+		try {
+			// if application is set, it must be a headless app.
+			application = configuration.getAttribute(IPDELauncherConstants.APPLICATION, (String) null);
+		} catch (CoreException e) {
+			// Ignore
+		}
+
+		// launch the UI test application
+		if (application == null)
+			application = IPDEConstants.UI_TEST_APPLICATION;
+		return application;
+	}
+
+	private IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException {
+		IPluginModelBase model = PluginRegistry.findModel(id);
+		if (model == null) {
+			model = PDECore.getDefault().findPluginInHost(id);
+		}
+		if (model == null) {
+			abort(NLS.bind(Messages.JUnitPluginLaunchConfigurationDelegate_error_missingPlugin, id), null, IStatus.OK);
+		}
+		return model;
+	}
+
+	@Override
+	public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException {
+		return LaunchArgumentsHelper.getUserProgramArguments(configuration);
+	}
+
+	@Override
+	public String getVMArguments(ILaunchConfiguration configuration) throws CoreException {
+		String vmArgs = LaunchArgumentsHelper.getUserVMArguments(configuration);
+
+		// necessary for PDE to know how to load plugins when target platform = host
+		// platform
+		IPluginModelBase base = fAllBundles.get(PDECore.PLUGIN_ID);
+		if (base != null && VersionUtil.compareMacroMinorMicro(base.getBundleDescription().getVersion(),
+				new Version("3.3.1")) >= 0) { //$NON-NLS-1$
+			vmArgs = concatArg(vmArgs, "-Declipse.pde.launch=true"); //$NON-NLS-1$
+		}
+		// For p2 target, add "-Declipse.p2.data.area=@config.dir/p2" unless already
+		// specified by user
+		if (fAllBundles.containsKey("org.eclipse.equinox.p2.core")) { //$NON-NLS-1$
+			if (!vmArgs.contains("-Declipse.p2.data.area=")) { //$NON-NLS-1$
+				vmArgs = concatArg(vmArgs, "-Declipse.p2.data.area=@config.dir" + File.separator + "p2"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		return vmArgs;
+	}
+
+	/**
+	 * Returns the result of concatenating the given argument to the specified
+	 * vmArgs.
+	 *
+	 * @param vmArgs existing VM arguments
+	 * @param arg    argument to concatenate
+	 * @return result of concatenation
+	 */
+	private String concatArg(String vmArgs, String arg) {
+		if (vmArgs.length() > 0 && !vmArgs.endsWith(" ")) //$NON-NLS-1$
+			vmArgs = vmArgs.concat(" "); //$NON-NLS-1$
+		return vmArgs.concat(arg);
+	}
+
+	@Override
+	public String[] getEnvironment(ILaunchConfiguration configuration) throws CoreException {
+		return DebugPlugin.getDefault().getLaunchManager().getEnvironment(configuration);
+	}
+
+	@Deprecated
+	@Override
+	public String[] getClasspath(ILaunchConfiguration configuration) throws CoreException {
+		String[] classpath = LaunchArgumentsHelper.constructClasspath(configuration);
+		if (classpath == null) {
+			abort(Messages.JUnitPluginLaunchConfigurationDelegate_error_noStartup, null, IStatus.OK);
+		}
+		return classpath;
+	}
+
+	@Override
+	public File getWorkingDirectory(ILaunchConfiguration configuration) throws CoreException {
+		return LaunchArgumentsHelper.getWorkingDirectory(configuration);
+	}
+
+	@Override
+	public Map<String, Object> getVMSpecificAttributesMap(ILaunchConfiguration configuration) throws CoreException {
+		return LaunchArgumentsHelper.getVMSpecificAttributesMap(configuration);
+	}
+
+	@Override
+	protected void setDefaultSourceLocator(ILaunch launch, ILaunchConfiguration configuration) throws CoreException {
+		ILaunchConfigurationWorkingCopy wc = null;
+		if (configuration.isWorkingCopy()) {
+			wc = (ILaunchConfigurationWorkingCopy) configuration;
+		} else {
+			wc = configuration.getWorkingCopy();
+		}
+		String id = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER,
+				(String) null);
+		if (!PDESourcePathProvider.ID.equals(id)) {
+			wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER, PDESourcePathProvider.ID);
+			wc.doSave();
+		}
+
+		manageLaunch(launch);
+	}
+
+	/**
+	 * Returns the location of the configuration area
+	 *
+	 * @param configuration the launch configuration
+	 * @return a directory where the configuration area is located
+	 */
+	protected File getConfigurationDirectory(ILaunchConfiguration configuration) {
+		if (fConfigDir == null)
+			fConfigDir = LaunchConfigurationHelper.getConfigurationArea(configuration);
+		return fConfigDir;
+	}
+
+	@Override
+	protected IProject[] getBuildOrder(ILaunchConfiguration configuration, String mode) throws CoreException {
+		return computeBuildOrder(LaunchPluginValidator.getAffectedProjects(configuration));
+	}
+
+	@Override
+	protected IProject[] getProjectsForProblemSearch(ILaunchConfiguration configuration, String mode)
+			throws CoreException {
+		return LaunchPluginValidator.getAffectedProjects(configuration);
+	}
+
+	/**
+	 * Adds a listener to the launch to be notified at interesting launch lifecycle
+	 * events such as when the launch terminates.
+	 *
+	 * @param launch the launch
+	 */
+	protected void manageLaunch(ILaunch launch) {
+//		PDELaunchingPlugin.getDefault().getLaunchListener().manage(launch);
+	}
+
+	private String[] getRequiredPlugins(ILaunchConfiguration configuration) {
+		// if we are using JUnit4, we need to include the junit4 specific bundles
+		ITestKind testKind = JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
+		if (TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId()))
+			return new String[] { "org.junit", "org.eclipse.jdt.junit.runtime", "org.eclipse.pde.junit.runtime", //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+					"org.eclipse.jdt.junit4.runtime" }; //$NON-NLS-1$
+		return new String[] { "org.junit", "org.eclipse.jdt.junit.runtime", "org.eclipse.pde.junit.runtime" }; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+	}
+
+	/**
+	 * Checks for old-style plugin.xml files that have become stale since the last
+	 * launch. For any stale plugin.xml files found, the corresponding MANIFEST.MF
+	 * is deleted from the runtime configuration area so that it gets regenerated
+	 * upon startup.
+	 *
+	 * @param configuration the launch configuration
+	 * @param monitor       the progress monitor
+	 */
+	protected void synchronizeManifests(ILaunchConfiguration configuration, IProgressMonitor monitor) {
+		LaunchConfigurationHelper.synchronizeManifests(configuration, getConfigurationDirectory(configuration));
+		monitor.done();
+	}
+
+	/**
+	 * Clears the workspace prior to launching if the workspace exists and the
+	 * option to clear it is turned on. Also clears the configuration area if that
+	 * option is chosen.
+	 *
+	 * @param configuration the launch configuration
+	 * @param monitor       the progress monitor
+	 * @throws CoreException if unable to retrieve launch attribute values
+	 * @since 3.3
+	 */
+	protected void clear(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+		if (fWorkspaceLocation == null) {
+			fWorkspaceLocation = LaunchArgumentsHelper.getWorkspaceLocation(configuration);
+		}
+
+		SubMonitor subMon = SubMonitor.convert(monitor, 50);
+
+		// Clear workspace and prompt, if necessary
+		LauncherUtils.clearWorkspace(configuration, fWorkspaceLocation, subMon.split(25));
+
+		subMon.setWorkRemaining(25);
+
+		// clear config area, if necessary
+		if (configuration.getAttribute(IPDELauncherConstants.CONFIG_CLEAR_AREA, false)) {
+			CoreUtility.deleteContent(getConfigurationDirectory(configuration), subMon.split(25));
+		}
+
+		subMon.done();
+	}
+
+	/**
+	 * Checks if the Automated Management of Dependencies option is turned on. If
+	 * so, it makes aure all manifests are updated with the correct dependencies.
+	 *
+	 * @param configuration the launch configuration
+	 * @param monitor       a progress monitor
+	 */
+	protected void validateProjectDependencies(ILaunchConfiguration configuration, IProgressMonitor monitor) {
+		LauncherUtils.validateProjectDependencies(configuration, monitor);
+	}
+
+	/**
+	 * Validates inter-bundle dependencies automatically prior to launching if that
+	 * option is turned on.
+	 *
+	 * @param configuration the launch configuration
+	 * @param monitor       a progress monitor
+	 * @throws CoreException if unable to validate the dependencies
+	 */
+	protected void validatePluginDependencies(ILaunchConfiguration configuration, IProgressMonitor monitor)
+			throws CoreException {
+		EclipsePluginValidationOperation op = new EclipsePluginValidationOperation(configuration);
+		LaunchPluginValidator.runValidationOperation(op, monitor);
+	}
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchShortcut.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchShortcut.java
new file mode 100644
index 0000000..5429638
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchShortcut.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.launcher;
+
+import org.eclipse.pde.ui.launcher.JUnitWorkbenchLaunchShortcut;
+import org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin;
+import org.eclipse.unittest.ui.ConfigureViewerSupport;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * The launch shortcut to launch JUnit Plug-in tests.
+ *
+ * <p>
+ * This class may be instantiated and subclassed.
+ * </p>
+ */
+public class JUnitPluginLaunchShortcut extends JUnitWorkbenchLaunchShortcut {
+
+	@Override
+	protected String getLaunchConfigurationTypeId() {
+		return JUnitPluginTestPlugin.PLUGIN_ID + ".launchConfiguration"; //$NON-NLS-1$
+	}
+
+	@Override
+	protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element) throws CoreException {
+		ILaunchConfigurationWorkingCopy wc = super.createLaunchConfiguration(element);
+		new ConfigureViewerSupport(JUnitPluginTestPlugin.UNIT_TEST_VIEW_SUPPORT_ID).apply(wc);
+		return wc;
+	}
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginTestTab.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginTestTab.java
new file mode 100644
index 0000000..50f9119
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginTestTab.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.launcher;
+
+import org.eclipse.pde.ui.launcher.TestTab;
+import org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin;
+import org.eclipse.unittest.ui.ConfigureViewerSupport;
+
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+
+public class JUnitPluginTestTab extends TestTab {
+
+	@Override
+	public void performApply(ILaunchConfigurationWorkingCopy config) {
+		// TODO Auto-generated method stub
+		super.performApply(config);
+
+		new ConfigureViewerSupport(JUnitPluginTestPlugin.UNIT_TEST_VIEW_SUPPORT_ID).apply(config);
+
+	}
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.java
new file mode 100644
index 0000000..dfe84b3
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.launcher;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class Messages extends NLS {
+
+	private static final String BUNDLE_NAME = "org.eclipse.pde.unittest.junit.launcher.Messages";//$NON-NLS-1$
+
+	public static String JUnitPluginLaunchConfigurationDelegate_create_source_locator_description;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_input_element_deosn_not_exist;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_no_socket;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_notests_kind;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_wrong_input;
+	public static String JUnitPluginLaunchConfigurationDelegate_input_type_does_not_exist;
+	public static String JUnitPluginLaunchConfigurationDelegate_verifying_attriburtes_description;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_notaplugin;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_noStartup;
+	public static String JUnitPluginLaunchConfigurationDelegate_error_missingPlugin;
+
+	static {
+		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+	}
+
+	private Messages() {
+		// Do not instantiate
+	}
+}
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.properties b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.properties
new file mode 100644
index 0000000..6280672
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/Messages.properties
@@ -0,0 +1,23 @@
+#################################################################################
+#  Copyright (c) 2021 Red Hat, Inc.
+#
+#  This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License 2.0
+#  which accompanies this distribution, and is available at
+#  https://www.eclipse.org/legal/epl-2.0/
+#
+#  SPDX-License-Identifier: EPL-2.0
+#
+#  Contributors:
+#      Red Hat Inc. - initial API and implementation
+#################################################################################
+JUnitPluginLaunchConfigurationDelegate_verifying_attriburtes_description=Verifying launch attributes...
+JUnitPluginLaunchConfigurationDelegate_create_source_locator_description=Creating source locator...
+JUnitPluginLaunchConfigurationDelegate_error_no_socket=No socket available
+JUnitPluginLaunchConfigurationDelegate_error_notests_kind=No tests found with test runner ''{0}''.
+JUnitPluginLaunchConfigurationDelegate_error_wrong_input=Can only run types or single method
+JUnitPluginLaunchConfigurationDelegate_error_input_element_deosn_not_exist=The input element of the launch configuration does not exist
+JUnitPluginLaunchConfigurationDelegate_input_type_does_not_exist=The input type of the launch configuration does not exist
+JUnitPluginLaunchConfigurationDelegate_error_notaplugin = Could not launch the JUnit plug-in tests because project ''{0}'' is not a plug-in project.
+JUnitPluginLaunchConfigurationDelegate_error_noStartup = Launching failed. Bootstrap code cannot be found.
+JUnitPluginLaunchConfigurationDelegate_error_missingPlugin = Required plug-in ''{0}'' could not be found.
diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/ui/JUnitPluginTestViewSupport.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/ui/JUnitPluginTestViewSupport.java
new file mode 100644
index 0000000..a82a2ed
--- /dev/null
+++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/ui/JUnitPluginTestViewSupport.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.unittest.junit.ui;
+
+import org.eclipse.pde.unittest.junit.launcher.JUnitPluginLaunchConfigurationDelegate;
+import org.eclipse.unittest.launcher.ITestRunnerClient;
+import org.eclipse.unittest.model.ITestRunSession;
+
+import org.eclipse.jdt.ui.unittest.junit.ui.JUnitTestViewSupport;
+
+public class JUnitPluginTestViewSupport extends JUnitTestViewSupport {
+	@Override
+	public String getDisplayName() {
+		return "JUnit Plugin"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ITestRunnerClient newTestRunnerClient(ITestRunSession session) {
+		String portAsString = session.getLaunch().getAttribute(JUnitPluginLaunchConfigurationDelegate.ATTR_PORT);
+		return new org.eclipse.jdt.ui.unittest.junit.launcher.JUnitRemoteTestRunnerClient(
+				portAsString != null ? Integer.parseInt(portAsString) : -1, session);
+	}
+}
+/*
+ * implements ITestViewSupport {
+ *
+ * public static final String FRAME_LINE_PREFIX = "at "; //$NON-NLS-1$
+ *
+ * @Override public Collection<StringMatcher> getTraceExclusionFilterPatterns()
+ * { return Arrays
+ * .stream(JUnitPreferencesConstants.parseList(Platform.getPreferencesService().
+ * getString( JUnitCorePlugin.CORE_PLUGIN_ID,
+ * JUnitPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, "", null))) //$NON-NLS-1$
+ * .filter(Predicate.not(String::isBlank)) // .map(pattern -> new
+ * StringMatcher(pattern, true, false)) // .collect(Collectors.toList()); }
+ *
+ * @Override public IAction getOpenTestAction(Shell shell, ITestCaseElement
+ * testCase) { return new OpenTestAction(shell, testCase,
+ * getParameterTypes(testCase)); }
+ *
+ * @Override public IAction getOpenTestAction(Shell shell, ITestSuiteElement
+ * testSuite) { String testName = testSuite.getTestName(); List<? extends
+ * ITestElement> children = testSuite.getChildren(); if
+ * (testName.startsWith("[") && testName.endsWith("]") && !children.isEmpty()
+ * //$NON-NLS-1$ //$NON-NLS-2$ && children.get(0) instanceof ITestCaseElement) {
+ * // a group of parameterized tests return new OpenTestAction(shell,
+ * (ITestCaseElement) children.get(0), null); }
+ *
+ * int index = testName.indexOf('('); // test factory method if (index > 0) {
+ * return new OpenTestAction(shell, testSuite.getTestName(),
+ * testName.substring(0, index), getParameterTypes(testSuite), true,
+ * testSuite.getTestRunSession()); }
+ *
+ * // regular test class return new OpenTestAction(shell, testName,
+ * testSuite.getTestRunSession());
+ *
+ * }
+ *
+ * @Override public IAction createOpenEditorAction(Shell shell, ITestElement
+ * failure, String traceLine) { try { String testName = traceLine; int
+ * indexOfFramePrefix = testName.indexOf(FRAME_LINE_PREFIX); if
+ * (indexOfFramePrefix == -1) { return null; } testName =
+ * testName.substring(indexOfFramePrefix); testName =
+ * testName.substring(FRAME_LINE_PREFIX.length(),
+ * testName.lastIndexOf('(')).trim(); int indexOfModuleSeparator =
+ * testName.lastIndexOf('/'); if (indexOfModuleSeparator != -1) { testName =
+ * testName.substring(indexOfModuleSeparator + 1); } testName =
+ * testName.substring(0, testName.lastIndexOf('.')); int innerSeparatorIndex =
+ * testName.indexOf('$'); if (innerSeparatorIndex != -1) testName =
+ * testName.substring(0, innerSeparatorIndex);
+ *
+ * String lineNumber = traceLine; lineNumber =
+ * lineNumber.substring(lineNumber.indexOf(':') + 1,
+ * lineNumber.lastIndexOf(')')); int line; try { line =
+ * Integer.parseInt(lineNumber); } catch (NumberFormatException e) { // In some
+ * cases the line number can be omitted from a stack trace line line = 1; }
+ * return new OpenEditorAtLineAction(shell, testName, line,
+ * failure.getTestRunSession()); } catch (IndexOutOfBoundsException e) {
+ * JUnitPluginTestPlugin.log(e); } return null; }
+ *
+ * @Override public Runnable
+ * createShowStackTraceInConsoleViewActionDelegate(ITestElement failedTest) {
+ * return new ShowStackTraceInConsoleViewActionDelegate(failedTest); }
+ *
+ * @Override public ILaunchConfiguration
+ * getRerunLaunchConfiguration(List<ITestElement> tests) { if (tests.size() > 1)
+ * { MessageDialog.openInformation(Display.getDefault().getActiveShell(),
+ * JUnitMessages.JUnitCantRunMultipleTests,
+ * JUnitMessages.JUnitCantRunMultipleTests); return null; } ITestElement
+ * testSuite = tests.get(0); String testMethodName = null; // test method name
+ * is null when re-running a regular test class String testName =
+ * testSuite.getTestName();
+ *
+ * ILaunchConfiguration launchConfiguration =
+ * testSuite.getTestRunSession().getLaunch().getLaunchConfiguration(); ITestKind
+ * junitKind; try { junitKind = JUnitVersion
+ * .fromJUnitTestKindId(launchConfiguration
+ * .getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, ""))
+ * //$NON-NLS-1$ .getJUnitTestKind(); } catch (CoreException e) {
+ * JUnitPluginTestPlugin.log(e); return null; }
+ *
+ * IJavaProject project = JUnitLaunchConfigurationConstants
+ * .getJavaProject(testSuite.getTestRunSession().getLaunch().
+ * getLaunchConfiguration()); if (project == null) { return null; }
+ *
+ * String qualifiedName = null; IType testType = findTestClass(testSuite,
+ * junitKind.getFinder(), project, true); if (testType != null) { qualifiedName
+ * = testType.getFullyQualifiedName();
+ *
+ * if (!qualifiedName.equals(testName)) { int index = testName.indexOf('('); if
+ * (index > 0) { // test factory method testMethodName = testName.substring(0,
+ * index); } } String[] parameterTypes = getParameterTypes(testSuite); if
+ * (testMethodName != null && parameterTypes != null) { String paramTypesStr =
+ * Arrays.stream(parameterTypes).collect(Collectors.joining(",")); //$NON-NLS-1$
+ * testMethodName = testMethodName + "(" + paramTypesStr + ")"; //$NON-NLS-1$
+ * //$NON-NLS-2$ } } else { // see bug 443498 testType =
+ * findTestClass(testSuite.getParent(), junitKind.getFinder(), project, false);
+ * if (testType != null && testSuite instanceof ITestSuiteElement) {
+ * qualifiedName = testType.getFullyQualifiedName();
+ *
+ * String className = getClassName(testSuite); if
+ * (!qualifiedName.equals(className)) { testMethodName = testName; } } }
+ *
+ * ILaunchConfigurationWorkingCopy res; try { res =
+ * launchConfiguration.copy(launchConfiguration.getName() + " - rerun");
+ * //$NON-NLS-1$
+ * res.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME,
+ * testMethodName); return res; } catch (CoreException e) {
+ * JUnitPluginTestPlugin.log(e); return null; }
+ *
+ * }
+ */
+/*
+ * Returns the element's test class or the next container's test class, which
+ * exists, and for which ITestFinder.isTest() is true.
+ */
+/*
+ * private IType findTestClass(ITestElement element, ITestFinder finder,
+ * IJavaProject project, boolean checkOnlyCurrentElement) { ITestElement current
+ * = element; while (current != null) { try { String className = null; if
+ * (current instanceof ITestRunSession) { ILaunch launch =
+ * element.getTestRunSession().getLaunch(); if (launch != null) {
+ * ILaunchConfiguration configuration = launch.getLaunchConfiguration(); if
+ * (configuration != null) { className = configuration
+ * .getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)
+ * null); } } } else { className = getClassName(current); }
+ *
+ * if (className != null) { IType type = project.findType(className); if (type
+ * != null && finder.isTest(type)) { return type; } else if
+ * (checkOnlyCurrentElement) { return null; } } } catch (CoreException e) {
+ * JUnitPluginTestPlugin.log(e); } current = current.getParent(); } return null;
+ * }
+ *
+ * @Override public String getDisplayName() { return "JUnit Plugin";
+ * //$NON-NLS-1$ }
+ *
+ * @Override public ITestRunnerClient newTestRunnerClient(ITestRunSession
+ * session) { String portAsString =
+ * session.getLaunch().getAttribute(JUnitPluginLaunchConfigurationDelegate.
+ * ATTR_PORT); return new JUnitRemoteTestRunnerClient(portAsString != null ?
+ * Integer.parseInt(portAsString) : -1, session); }
+ */
+/**
+ * Returns the parameter types specified for this test element
+ *
+ * @param test test
+ * @return a parameter type array
+ */
+/*
+ * private String[] getParameterTypes(ITestElement test) { String testName =
+ * test.getDisplayName(); if (testName != null) { int index =
+ * testName.lastIndexOf("method:"); //$NON-NLS-1$ if (index != -1) { index =
+ * testName.indexOf('(', index); if (index > 0) { int closeIndex =
+ * testName.indexOf(')', index); if (closeIndex > 0) { String params =
+ * testName.substring(index + 1, closeIndex); return params.split(",");
+ * //$NON-NLS-1$ } } } } return null; }
+ */
+/**
+ * Returns the type/class of the test element
+ *
+ * @param test test
+ * @return return the type/class name
+ */
+/*
+ * public static String getClassName(ITestElement test) { return
+ * extractClassName(test.getTestName()); }
+ *
+ * private static String extractClassName(String testNameString) {
+ * testNameString = extractRawClassName(testNameString); testNameString =
+ * testNameString.replace('$', '.'); // see bug 178503 return testNameString; }
+ */
+/**
+ * Extracts and returns a raw class name from a test element name
+ *
+ * @param testNameString a test element name
+ *
+ * @return an extracted raw class name
+ */
+/*
+ * public static String extractRawClassName(String testNameString) { if
+ * (testNameString.startsWith("[") && testNameString.endsWith("]")) {
+ * //$NON-NLS-1$ //$NON-NLS-2$ // a group of parameterized tests, see //
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 return testNameString; }
+ * int index = testNameString.lastIndexOf('('); if (index < 0) return
+ * testNameString; int end = testNameString.lastIndexOf(')'); return
+ * testNameString.substring(index + 1, end > index ? end :
+ * testNameString.length()); }
+ *
+ * public static String getTestMethodName(ITestElement test) { String testName =
+ * test.getTestName(); int index = testName.lastIndexOf('('); if (index > 0)
+ * return testName.substring(0, index); index = testName.indexOf('@'); if (index
+ * > 0) return testName.substring(0, index); return testName; }
+ *
+ * }
+ */
\ No newline at end of file