Bug 553183 - Add Lemminx Extension Jar

Change-Id: I28ae7a5a6c5e9db6640a904b7220b9e3576795a4
Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
Signed-off-by: Mickael Istria <mistria@redhat.com>
diff --git a/org.eclipse.m2e.editor.lemminx.tests/META-INF/MANIFEST.MF b/org.eclipse.m2e.editor.lemminx.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6b7566a
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Test for pom edition in generic editor
+Bundle-SymbolicName: org.eclipse.m2e.editor.lemminx.tests
+Bundle-Version: 1.16.0.qualifier
+Automatic-Module-Name: org.eclipse.m2e.xmlls.extension.tests
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-Vendor: Eclipse m2e
+Require-Bundle: org.junit;bundle-version="4.12.0",
+ org.eclipse.ui.genericeditor;bundle-version="1.1.0",
+ org.eclipse.ui;bundle-version="3.115.0",
+ org.eclipse.ui.ide;bundle-version="3.16.0",
+ org.eclipse.core.resources;bundle-version="3.13.0",
+ org.eclipse.ui.workbench.texteditor;bundle-version="3.14.0",
+ org.eclipse.core.runtime;bundle-version="3.16.0",
+ org.eclipse.ui.tests.harness,
+ org.eclipse.jface.text;bundle-version="3.16.0",
+ org.eclipse.m2e.editor.lemminx;bundle-version="1.15.0"
diff --git a/org.eclipse.m2e.editor.lemminx.tests/build.properties b/org.eclipse.m2e.editor.lemminx.tests/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx.tests/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/org.eclipse.m2e.editor.lemminx.tests/pom.xml b/org.eclipse.m2e.editor.lemminx.tests/pom.xml
new file mode 100644
index 0000000..f6e4016
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx.tests/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+		<groupId>org.eclipse.m2e</groupId>
+		<artifactId>m2e-core</artifactId>
+		<version>1.16.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>org.eclipse.m2e.editor.lemminx.tests</artifactId>
+	<packaging>eclipse-test-plugin</packaging>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-surefire-plugin</artifactId>
+				<configuration>
+					<requiresUIHarness>true</requiresUIHarness>
+					<requiresUIThread>true</requiresUIThread>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/EditorTest.java b/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/EditorTest.java
new file mode 100644
index 0000000..75e4310
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/EditorTest.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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
+ *******************************************************************************/
+package org.eclipse.m2e.editor.lemminx.tests;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.junit.After;
+import org.junit.Test;
+
+public class EditorTest {
+
+	private IWorkbenchPage page;
+	private IProject project;
+
+	@After
+	public void closeAndDeleteAll() throws CoreException {
+		page.closeAllEditors(false);
+		project.delete(true, null);
+	}
+
+	@Test
+	public void testGenericEditorHasMavenExtensionEnabled() throws Exception {
+		page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		project = ResourcesPlugin.getWorkspace().getRoot().getProject("test" + System.currentTimeMillis());
+		project.create(null);
+		project.open(null);
+		IFile pomFile = project.getFile("pom.xml");
+		pomFile.create(getClass().getResourceAsStream("pom.xml"), true, null);
+		ITextEditor editorPart = (ITextEditor)IDE.openEditor(page, pomFile, "org.eclipse.ui.genericeditor.GenericEditor");
+		Display display = page.getWorkbenchWindow().getShell().getDisplay();
+		assertTrue("Missing diagnostic report", DisplayHelper.waitForCondition(display, 10000, () ->
+			{
+				try {
+					return Arrays.stream(pomFile.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO)).anyMatch(marker ->
+						marker.getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR &&
+						marker.getAttribute(IMarker.MESSAGE, "").contains("artifactId")
+					);
+				} catch (CoreException e) {
+					return false;
+				}
+			}
+		));
+		int offset = editorPart.getDocumentProvider().getDocument(editorPart.getEditorInput()).get().indexOf("</scope>");
+		Set<Shell> beforeShells = Arrays.stream(display.getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
+		editorPart.getSelectionProvider().setSelection(new TextSelection(offset, 0));
+		editorPart.getAction(ITextEditorActionConstants.CONTENT_ASSIST).run();
+		assertTrue("Missing completion proposals", DisplayHelper.waitForCondition(display, 3000, () -> {
+			Set<Shell> afterShells = Arrays.stream(display.getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
+			afterShells.removeAll(beforeShells);
+			return afterShells.stream()
+				.flatMap(shell -> Arrays.stream(shell.getChildren()))
+				.filter(Table.class::isInstance)
+				.map(Table.class::cast)
+				.findFirst()
+				.map(table -> Boolean.valueOf(Arrays.stream(table.getItems()).map(TableItem::getText).anyMatch("compile"::equals)))
+				.orElse(Boolean.FALSE).booleanValue();
+		}));
+		
+	}
+}
diff --git a/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/pom.xml b/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/pom.xml
new file mode 100644
index 0000000..1fcf589
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx.tests/src/org/eclipse/m2e/editor/lemminx/tests/pom.xml
@@ -0,0 +1,19 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+
+	<!-- missing artifactId should generate error -->
+	<groupId>org.test</groupId>
+	<version>0.0.1-SNAPSHOT</version>
+
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope></scope>
+		</dependency>
+	</dependencies>
+
+</project>
\ No newline at end of file
diff --git a/org.eclipse.m2e.editor.lemminx/.gitignore b/org.eclipse.m2e.editor.lemminx/.gitignore
new file mode 100644
index 0000000..d2e020f
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/.gitignore
@@ -0,0 +1,2 @@
+maven-xmlls-extension.jar
+lemminx-maven.jar
\ No newline at end of file
diff --git a/org.eclipse.m2e.editor.lemminx/META-INF/MANIFEST.MF b/org.eclipse.m2e.editor.lemminx/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..33d1a8c
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: POM File editor using Wild Web Developer, Lemminx and Maven LS extension
+Bundle-SymbolicName: org.eclipse.m2e.editor.lemminx;singleton:=true
+Bundle-Version: 1.16.0.qualifier
+Automatic-Module-Name: org.eclipse.m2e.xmlls.extension
+Import-Package: org.eclipse.core.runtime;version="3.5.0",
+ org.eclipse.m2e.core,
+ org.eclipse.m2e.core.internal,
+ org.slf4j;version="1.7.2"
+Require-Bundle: org.eclipse.m2e.maven.runtime,
+ org.eclipse.osgi,
+ org.eclipse.wildwebdeveloper.xml;bundle-version="0.7.0",
+ org.eclipse.ui.genericeditor;bundle-version="1.1"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-Vendor: Eclipse m2e
diff --git a/org.eclipse.m2e.editor.lemminx/build-indexer-jars.xml b/org.eclipse.m2e.editor.lemminx/build-indexer-jars.xml
new file mode 100644
index 0000000..1749a83
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/build-indexer-jars.xml
@@ -0,0 +1,20 @@
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+	<id>indexer-jars</id>
+	<includeBaseDirectory>false</includeBaseDirectory>
+	<baseDirectory></baseDirectory>
+	<formats>
+		<format>dir</format>
+	</formats>
+	<dependencySets>
+		<dependencySet>
+			<includes>
+				<include>org.apache.maven.indexer:*</include> <!-- Maven artifacts already shipped in org.eclipse.m2e.maven.runtiem -->
+				<include>org.apache.lucene:*</include> <!-- Maven artifacts already shipped in org.eclipse.m2e.maven.runtiem -->
+			</includes>
+			<useTransitiveDependencies>true</useTransitiveDependencies>
+			<!--useTransitiveFiltering>true</useTransitiveFiltering-->
+		</dependencySet>
+	</dependencySets>
+</assembly>
\ No newline at end of file
diff --git a/org.eclipse.m2e.editor.lemminx/build.properties b/org.eclipse.m2e.editor.lemminx/build.properties
new file mode 100644
index 0000000..7c89d1c
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = target/classes
+bin.includes = META-INF/,\
+               lemminx-maven.jar,\
+               indexer-jars/,\
+               plugin.xml,\
+               .
diff --git a/org.eclipse.m2e.editor.lemminx/indexer-jars/.gitignore b/org.eclipse.m2e.editor.lemminx/indexer-jars/.gitignore
new file mode 100644
index 0000000..f23b948
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/indexer-jars/.gitignore
@@ -0,0 +1 @@
+*.jar
\ No newline at end of file
diff --git a/org.eclipse.m2e.editor.lemminx/plugin.xml b/org.eclipse.m2e.editor.lemminx/plugin.xml
new file mode 100644
index 0000000..62b537f
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/plugin.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.wildwebdeveloper.xml.lemminxExtension">
+      <jar
+            path="lemminx-maven.jar">
+      </jar>
+      <classpathExtensionProvider
+            provider="org.eclipse.m2e.editor.lemminx.MavenRuntimeClasspathProvider">
+      </classpathExtensionProvider>
+   </extension>
+
+</plugin>
diff --git a/org.eclipse.m2e.editor.lemminx/pom.xml b/org.eclipse.m2e.editor.lemminx/pom.xml
new file mode 100644
index 0000000..56c666a
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+		<groupId>org.eclipse.m2e</groupId>
+		<artifactId>m2e-core</artifactId>
+		<version>1.16.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>org.eclipse.m2e.editor.lemminx</artifactId>
+	<packaging>eclipse-plugin</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.maven.indexer</groupId>
+			<artifactId>indexer-core</artifactId>
+			<version>6.0.0</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-clean-plugin</artifactId>
+				<configuration>
+					<filesets>
+						<fileset>
+							<directory>${basedir}</directory>
+							<includes>
+								<include>lemminx-maven*.jar</include>
+								<include>indexer-jars/*.jar</include>
+							</includes>
+						</fileset>
+					</filesets>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>get-lemminx-maven</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>copy</goal>
+						</goals>
+						<configuration>
+							<artifactItems>
+								<artifactItem>
+									<!-- This groupId/artifactId combination seems erroneous on GitHub Maven repos -->
+									<groupId>org.eclipse.lemminx</groupId>
+									<artifactId>lemminx-maven</artifactId>
+									<version>0.0.1-SNAPSHOT</version>
+									<outputDirectory>${basedir}</outputDirectory>
+									<destFileName>lemminx-maven.jar</destFileName>
+								</artifactItem>
+							</artifactItems>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals><goal>single</goal></goals>
+						<phase>generate-sources</phase>
+						<configuration>
+							<outputDirectory>${basedir}</outputDirectory>
+							<attach>false</attach>
+							<formats><format>dir</format></formats>
+							<descriptors><descriptor>build-indexer-jars.xml</descriptor></descriptors>
+							<finalName>indexer-jars</finalName>
+							<appendAssemblyId>false</appendAssemblyId>
+							<classifier></classifier>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+	<repositories>
+		<repository>
+			<id>lemminx-maven</id>
+			<url>https://repo.eclipse.org/content/repositories/lemminx/</url>
+			<snapshots><enabled>true</enabled></snapshots>
+			<releases><enabled>true</enabled></releases>
+		</repository>
+	</repositories>
+</project>
diff --git a/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/BundleResolver.java b/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/BundleResolver.java
new file mode 100644
index 0000000..771794b
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/BundleResolver.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2019-2020 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
+ *******************************************************************************/
+package org.eclipse.m2e.editor.lemminx;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BundleResolver {
+	protected static final Logger LOG = LoggerFactory.getLogger(BundleResolver.class);
+
+	private BundleResolver() {
+		// Utility class, not meant to be instantiated
+	}
+
+	public static Bundle getBundle(String bundleID) {
+		return Platform.getBundle(bundleID);
+	}
+
+	public static File getBundleResource(String bundleID, String resourceName) {
+		Bundle bundle = getBundle(bundleID);
+		File f = null;
+		try {
+			f = new java.io.File(FileLocator
+					.toFileURL(FileLocator.find(bundle, new Path(bundle.getResource(resourceName).getPath())))
+					.getPath());
+		} catch (IOException e) {
+			LOG.error(e.getMessage(), e);
+			return null;
+		}
+
+		return f;
+	}
+}
diff --git a/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/MavenRuntimeClasspathProvider.java b/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/MavenRuntimeClasspathProvider.java
new file mode 100644
index 0000000..6ff797e
--- /dev/null
+++ b/org.eclipse.m2e.editor.lemminx/src/org/eclipse/m2e/editor/lemminx/MavenRuntimeClasspathProvider.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2019-2020 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
+ *******************************************************************************/
+package org.eclipse.m2e.editor.lemminx;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wildwebdeveloper.xml.LemminxClasspathExtensionProvider;
+
+public class MavenRuntimeClasspathProvider implements LemminxClasspathExtensionProvider {
+
+	@Override
+	public List<File> get() {
+		List<File> mavenRuntimeJars = new ArrayList<>();
+		File jarDir = BundleResolver.getBundleResource("org.eclipse.m2e.maven.runtime", "/jars/");
+		for (File jar : jarDir.listFiles()) {
+			if (!jar.isDirectory()) {
+				mavenRuntimeJars.add(jar);
+			}
+		}
+		// Indexer jars
+		jarDir = BundleResolver.getBundleResource("org.eclipse.m2e.editor.lemminx", "/indexer-jars/");
+		for (File jar : jarDir.listFiles()) {
+			if (!jar.isDirectory()) {
+				mavenRuntimeJars.add(jar);
+			}
+		}
+		// Libraries that are also required and not included in org.eclipse.m2e.maven.runtime
+		try {
+			mavenRuntimeJars.add(FileLocator.getBundleFile(Platform.getBundle("javax.inject")));
+			mavenRuntimeJars.add(FileLocator.getBundleFile(Platform.getBundle("org.slf4j.api")));
+		} catch (IOException e) {
+			// TODO
+		}
+		return mavenRuntimeJars;
+	}
+}
diff --git a/org.eclipse.m2e.site/category.xml b/org.eclipse.m2e.site/category.xml
index c0342bf..83bb7e4 100644
--- a/org.eclipse.m2e.site/category.xml
+++ b/org.eclipse.m2e.site/category.xml
@@ -9,5 +9,8 @@
    <feature url="features/org.eclipse.m2e.logback.feature_0.0.0.jar" id="org.eclipse.m2e.logback.feature" version="0.0.0">
       <category name="m2e"/>
    </feature>
+   <bundle id="org.eclipse.m2e.editor.lemminx">
+      <category name="m2e"/>
+   </bundle>
    <category-def name="m2e" label="Maven Integration for Eclipse"/>
 </site>
diff --git a/pom.xml b/pom.xml
index ebd38c3..fe4647c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -89,6 +89,11 @@
       <layout>p2</layout>
       <url>https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository</url>
     </repository>
+    <repository>
+    <id>Wild Web Developer</id>
+    <layout>p2</layout>
+    <url>http://download.eclipse.org/wildwebdeveloper/snapshots</url>
+    </repository>
   </repositories>
   <!-- To use when building with Tycho Snapshots
   <pluginRepositories>
@@ -122,6 +127,7 @@
     <module>org.eclipse.m2e.binaryproject.ui</module>
     <module>org.eclipse.m2e.sourcelookup</module>
     <module>org.eclipse.m2e.sourcelookup.ui</module>
+    <module>org.eclipse.m2e.editor.lemminx</module>
 
     <!-- common test helpers -->
     <module>org.eclipse.m2e.tests.common</module>
@@ -140,6 +146,7 @@
     <module>org.eclipse.m2e.core.tests</module>
     <module>org.eclipse.m2e.importer.tests</module>
     <module>org.eclipse.m2e.binaryproject.tests</module>
+    <module>org.eclipse.m2e.editor.lemminx.tests</module>
   </modules>