Bug 563038 - Missing auto-update of configuration on pom change

Change-Id: Ica8b08a328854d05112163954cfe0619801ebc22
Signed-off-by: Mickael Istria <mistria@redhat.com>
diff --git a/org.eclipse.m2e.core.ui/META-INF/MANIFEST.MF b/org.eclipse.m2e.core.ui/META-INF/MANIFEST.MF
index 2594726..c4d5114 100644
--- a/org.eclipse.m2e.core.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.core.ui/META-INF/MANIFEST.MF
@@ -25,7 +25,7 @@
 Require-Bundle: org.eclipse.m2e.core;bundle-version="[1.16.0,1.17.0)",
  org.eclipse.core.resources;bundle-version="3.5.2",
  org.eclipse.core.runtime;bundle-version="3.5.0",
- org.eclipse.m2e.model.edit;bundle-version="[1.16.0,1.17.0)",
+ org.eclipse.m2e.model.edit;bundle-version="[1.16.0,1.17.0)";visibility:=reexport,
  org.eclipse.m2e.maven.runtime;bundle-version="[1.16.0,1.17.0)",
  org.eclipse.m2e.archetype.common;bundle-version="[1.16.0,1.17.0)",
  org.eclipse.m2e.maven.indexer;bundle-version="[1.16.0,1.17.0)",
@@ -36,8 +36,10 @@
  org.eclipse.core.expressions;bundle-version="3.4.101",
  org.eclipse.ui.forms;bundle-version="3.4.1",
  org.eclipse.jface.text,
+ org.eclipse.core.filebuffers,
  org.eclipse.ui
 Import-Package: org.eclipse.compare.rangedifferencer,
  org.eclipse.ltk.core.refactoring,
  org.slf4j;version="1.6.2"
+Service-Component: OSGI-INF/component.xml
 Automatic-Module-Name: org.eclipse.m2e.core.ui
diff --git a/org.eclipse.m2e.editor.xml/OSGI-INF/component.xml b/org.eclipse.m2e.core.ui/OSGI-INF/component.xml
similarity index 80%
rename from org.eclipse.m2e.editor.xml/OSGI-INF/component.xml
rename to org.eclipse.m2e.core.ui/OSGI-INF/component.xml
index b18976e..1e8f9b2 100644
--- a/org.eclipse.m2e.editor.xml/OSGI-INF/component.xml
+++ b/org.eclipse.m2e.core.ui/OSGI-INF/component.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.m2e.editor.xml.markerLocation">
-   <implementation class="org.eclipse.m2e.editor.xml.internal.MarkerLocationService"/>
+   <implementation class="org.eclipse.m2e.core.ui.internal.markers.MarkerLocationService"/>
    <service>
       <provide interface="org.eclipse.m2e.core.internal.markers.IMarkerLocationService"/>
       <provide interface="org.eclipse.m2e.core.internal.markers.IEditorMarkerService"/>
diff --git a/org.eclipse.m2e.core.ui/build.properties b/org.eclipse.m2e.core.ui/build.properties
index 8d39fb7..529d593 100644
--- a/org.eclipse.m2e.core.ui/build.properties
+++ b/org.eclipse.m2e.core.ui/build.properties
@@ -1,6 +1,7 @@
 source.. = src/
 output.. = target/classes/
 bin.includes = META-INF/,\
+               OSGI-INF/,\
                .,\
                plugin.xml,\
                plugin.properties,\
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/markers/MarkerLocationService.java
similarity index 98%
rename from org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java
rename to org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/markers/MarkerLocationService.java
index 91d7292..c61653a 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/MarkerLocationService.java
+++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/markers/MarkerLocationService.java
@@ -12,7 +12,7 @@
  *      Rob Newton - added warning preferences page for disabling warnings
  *******************************************************************************/
 
-package org.eclipse.m2e.editor.xml.internal;
+package org.eclipse.m2e.core.ui.internal.markers;
 
 import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.childEquals;
 import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.childMissingOrEqual;
@@ -68,14 +68,15 @@
 import org.eclipse.m2e.core.ui.internal.M2EUIPluginActivator;
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits;
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Matcher;
-import org.eclipse.m2e.editor.pom.NodeOperation;
-import org.eclipse.m2e.editor.pom.XmlUtils;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
+import org.eclipse.m2e.model.edit.pom.util.NodeOperation;
 
 
 /**
  * a service impl used by the core module to improve marker locations and addition of our own markers
  * 
  * @author mkleint
+ * @since 1.16
  */
 @SuppressWarnings("restriction")
 public class MarkerLocationService implements IMarkerLocationService, IEditorMarkerService {
diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/util/XmlUtils.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/util/XmlUtils.java
new file mode 100644
index 0000000..ea898ad
--- /dev/null
+++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/util/XmlUtils.java
@@ -0,0 +1,300 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2018 Sonatype, Inc. and others.
+ * All rights reserved. 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:
+ *      Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Stack;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IFile;
+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.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputSource;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.ui.internal.editing.PomEdits;
+import org.eclipse.m2e.model.edit.pom.util.NodeOperation;
+
+
+/**
+ * @author mkleint
+ */
+public class XmlUtils {
+  private static final Logger log = LoggerFactory.getLogger(XmlUtils.class);
+
+  public static Element findChild(Element parent, String name) {
+    return PomEdits.findChild(parent, name);
+  }
+
+  public static List<Element> findChilds(Element parent, String name) {
+    return PomEdits.findChilds(parent, name);
+  }
+
+  public static String getTextValue(Node element) {
+    return PomEdits.getTextValue(element);
+  }
+
+  /**
+   * finds exactly one (first) occurence of child element with the given name (eg. dependency) that fulfills conditions
+   * expressed by the Matchers (eg. groupId/artifactId match)
+   * 
+   * @param parent
+   * @param name
+   * @param matchers
+   * @return
+   */
+  public static Element findChild(Element parent, String name, PomEdits.Matcher... matchers) {
+    return PomEdits.findChild(parent, name, matchers);
+  }
+
+  /**
+   * what is this method supposed to do? for the sourceViewer find the associated file on disk and for that one find the
+   * IProject it belongs to. The required condition for the IProject instance is that project relative path of the file
+   * shall only be pom.xml (thus no nested, unopened maven pom). So that when
+   * MavenPlugin.getMavenProjectManager().getProject(prj); is called later on the instance, it actually returns the
+   * maven model facade for the pom.xml backing the sourceViewer.
+   * 
+   * @param sourceViewer
+   * @return
+   */
+  public static IProject extractProject(ITextViewer sourceViewer) {
+    ITextFileBuffer buf = FileBuffers.getTextFileBufferManager().getTextFileBuffer(sourceViewer.getDocument());
+    if(buf == null) {
+      //eg. for viewers of pom files in local repository
+      return null;
+    }
+    IFileStore folder = buf.getFileStore();
+    File file = new File(folder.toURI());
+    IPath path = Path.fromOSString(file.getAbsolutePath());
+    Stack<IFile> stack = new Stack<IFile>();
+    //here we need to find the most inner project to the path.
+    //we do so by shortening the path and remembering all the resources identified.
+    // at the end we pick the last one from the stack. is there a catch to it?
+    IFile ifile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
+    if(ifile != null) {
+      stack.push(ifile);
+    }
+    while(path.segmentCount() > 1) {
+      IResource ires = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
+      if(ires != null && ires instanceof IFile) {
+        stack.push((IFile) ires);
+      }
+      path = path.removeFirstSegments(1);
+    }
+    IFile res = stack.empty() ? null : stack.pop();
+    if(res != null) {
+      IProject prj = res.getProject();
+      //the project returned is in a way unrelated to nested child poms that don't have an opened project,
+      //in that case we pass along a wrong parent/aggregator
+      if(res.getProjectRelativePath().segmentCount() != 1) {
+        //if the project were the pom's project, the relative path would be just "pom.xml", if it's not just throw it out of the window..
+        prj = null;
+      }
+      return prj;
+    }
+    return null;
+  }
+
+  public static MavenProject extractMavenProject(ITextViewer sourceViewer) {
+    //look in the sourceViewer's cache only
+    if(sourceViewer instanceof IAdaptable) {
+      return ((IAdaptable) sourceViewer).getAdapter(MavenProject.class);
+    }
+    return null;
+  }
+
+  /**
+   * converts an InputLocation to a file path on the local disk, null if not available. still the input source's model
+   * value can be used further..
+   * 
+   * @param location
+   * @return
+   */
+  public static File fileForInputLocation(InputLocation location, MavenProject origin) {
+    InputSource source = location.getSource();
+    if(source != null) {
+      //MNGECLIPSE-2539 apparently if maven can't resolve the model from local storage,
+      //the location will be empty. not only applicable to local repo models but
+      //apparently also to models in workspace not reachable by relativePath 
+      String loc = source.getLocation();
+      File file = null;
+      if(loc != null) {
+        file = new File(loc);
+      } else {
+        //try to find pom by coordinates..
+        String modelId = source.getModelId();
+        if(origin.getModel().getId().equals(modelId) && origin.getFile() != null) {
+          return origin.getFile();
+        }
+        String[] splitStrings = modelId.split(":");
+        assert splitStrings.length == 3;
+        IMavenProjectFacade facade = MavenPlugin.getMavenProjectRegistry().getMavenProject(splitStrings[0],
+            splitStrings[1], splitStrings[2]);
+        if(facade != null) {
+          file = facade.getPomFile();
+        } else {
+          //if not in the workspace, try looking into the local repository.
+          IMaven maven = MavenPlugin.getMaven();
+          try {
+            String path = maven.getArtifactPath(maven.getLocalRepository(), splitStrings[0], splitStrings[1],
+                splitStrings[2], "pom", null);
+            if(path != null) {
+              file = new File(maven.getLocalRepositoryPath(), path);
+            }
+          } catch(CoreException e) {
+            log.error("Failed to calculate local repository path of artifact", e);
+          }
+        }
+      }
+      return file;
+    }
+    return null;
+  }
+
+  /**
+   * originally copied from org.eclipse.wst.xml.ui.internal.hyperlink.XMLHyperlinkDetector this method grabs the
+   * IDOMModel for the IDocument, performs the passed operation on the node at the offset and then releases the
+   * IDOMModel operation's Node value is also an instance of IndexedRegion
+   * 
+   * @param offset
+   */
+  public static void performOnCurrentElement(IDocument document, int offset, NodeOperation<Node> operation) {
+    assert document != null;
+    assert operation != null;
+    // get the current node at the offset (returns either: element,
+    // doctype, text)
+    IStructuredModel sModel = null;
+    try {
+      sModel = StructuredModelManager.getModelManager().getExistingModelForRead(document);
+      if(sModel != null) {
+        IndexedRegion inode = sModel.getIndexedRegion(offset);
+        if(inode == null) {
+          inode = sModel.getIndexedRegion(offset - 1);
+        }
+        if(inode instanceof Node) {
+          operation.process((Node) inode, sModel.getStructuredDocument());
+        }
+      }
+    } finally {
+      if(sModel != null) {
+        sModel.releaseFromRead();
+      }
+    }
+  }
+
+  /**
+   * this method grabs the IDOMModel for the IDocument, performs the passed operation on the root element of the
+   * document and then releases the IDOMModel root Element value is also an instance of IndexedRegion
+   * 
+   * @param doc
+   * @param operation
+   */
+  public static void performOnRootElement(IDocument doc, NodeOperation<Element> operation) {
+    assert doc != null;
+    assert operation != null;
+    IDOMModel domModel = null;
+    try {
+      domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+      if(domModel == null) {
+        throw new IllegalArgumentException("Document is not structured: " + doc);
+      }
+      IStructuredDocument document = domModel.getStructuredDocument();
+      Element root = domModel.getDocument().getDocumentElement();
+      operation.process(root, document);
+    } finally {
+      if(domModel != null) {
+        domModel.releaseFromRead();
+      }
+    }
+  }
+
+  public static void performOnRootElement(IFile resource, NodeOperation<Element> operation)
+      throws IOException, CoreException {
+    performOnRootElement(resource, operation, false);
+  }
+
+  public static void performOnRootElement(IFile resource, NodeOperation<Element> operation, boolean autoSave)
+      throws IOException, CoreException {
+    assert resource != null;
+    assert operation != null;
+    IDOMModel domModel = null;
+    try {
+      domModel = (IDOMModel) StructuredModelManager.getModelManager().getModelForRead(resource);
+      if(domModel == null) {
+        throw new IllegalArgumentException("Document is not structured: " + resource);
+      }
+      IStructuredDocument document = domModel.getStructuredDocument();
+      Element root = domModel.getDocument().getDocumentElement();
+      operation.process(root, document);
+
+      if(autoSave && domModel.getReferenceCountForEdit() == 0) {
+        domModel.save();
+      }
+
+    } finally {
+      if(domModel != null) {
+        domModel.releaseFromRead();
+      }
+    }
+  }
+
+  /*
+   * calculates the path of the node up in the hierarchy, example of result is project/build/plugins/plugin
+   * level parameter designates the number of parents to climb eg. for level 2 the result would be plugins/plugin
+   * level -1 means all the way to the top. 
+   */
+  public static String pathUp(Node node, int level) {
+    StringBuilder buf = new StringBuilder();
+    int current = level;
+    while(node != null && current > 0) {
+      if(node instanceof Element) {
+        if(buf.length() > 0) {
+          buf.insert(0, "/");
+        }
+        buf.insert(0, node.getNodeName());
+        current = current - 1;
+      }
+      node = node.getParentNode();
+    }
+    return buf.toString();
+  }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java
index 6040cde..68d1b83 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java
@@ -1022,6 +1022,7 @@
     }
   }
 
+  @Override
   public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
     for(MavenProjectChangedEvent event : events) {
       try {
@@ -1058,7 +1059,7 @@
     }
   }
 
-  public ILifecycleMapping getLifecycleMapping(IMavenProjectFacade projectFacade) throws CoreException {
+  public ILifecycleMapping getLifecycleMapping(IMavenProjectFacade projectFacade) {
     if(projectFacade == null) {
       return null;
     }
diff --git a/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF b/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
index 586893b..9d2fac4 100644
--- a/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
@@ -35,6 +35,5 @@
 Bundle-ClassPath: .
 Bundle-Vendor: %Bundle-Vendor
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Service-Component: OSGI-INF/component.xml
 Import-Package: org.slf4j;version="1.6.2"
 Automatic-Module-Name: org.eclipse.m2e.editor.xml
diff --git a/org.eclipse.m2e.editor.xml/plugin.xml b/org.eclipse.m2e.editor.xml/plugin.xml
index 4ca6daf..4ed84de 100644
--- a/org.eclipse.m2e.editor.xml/plugin.xml
+++ b/org.eclipse.m2e.editor.xml/plugin.xml
@@ -23,13 +23,6 @@
 		value="XML_COMMENT_TEXT"
 		target="org.eclipse.m2e.core.pomFile" />
   </extension>
-  <extension point="org.eclipse.wst.sse.core.modelHandler">
-   	<modelHandler
-          associatedContentTypeId="org.eclipse.m2e.core.pomFile"
-          class="org.eclipse.m2e.editor.xml.PomModelHandler"
-          id="org.eclipse.m2e.core.pomFile.handler">
-   	</modelHandler>
-   </extension>
 	<extension
 		point="org.eclipse.ui.ide.markerResolution">
 		<markerResolutionGenerator
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java
index 4e0669b..87f0de9 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java
@@ -68,7 +68,7 @@
 import org.eclipse.m2e.core.ui.internal.dialogs.MavenRepositorySearchDialog;
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Operation;
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits.OperationTuple;
-import org.eclipse.m2e.editor.pom.XmlUtils;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 import org.eclipse.m2e.editor.xml.internal.Messages;
 
 
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertSPDXLicenseProposal.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertSPDXLicenseProposal.java
index ca09db5..669a10e 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertSPDXLicenseProposal.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertSPDXLicenseProposal.java
@@ -34,8 +34,8 @@
 import org.eclipse.m2e.core.MavenPlugin;
 import org.eclipse.m2e.core.project.IMavenProjectFacade;
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits.OperationTuple;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 import org.eclipse.m2e.editor.pom.PomTemplateContext;
-import org.eclipse.m2e.editor.pom.XmlUtils;
 import org.eclipse.m2e.editor.xml.internal.Messages;
 import org.eclipse.m2e.editor.xml.internal.dialogs.SPDXLicense;
 import org.eclipse.m2e.editor.xml.internal.dialogs.SelectSPDXLicenseDialog;
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java
index 2514fe9..46fbd3c 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java
@@ -59,9 +59,9 @@
 
 import org.eclipse.m2e.core.MavenPlugin;
 import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 import org.eclipse.m2e.editor.pom.PomTemplate;
 import org.eclipse.m2e.editor.pom.PomTemplateContext;
-import org.eclipse.m2e.editor.pom.XmlUtils;
 import org.eclipse.m2e.editor.xml.internal.Messages;
 
 
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java
index 6a96e51..d9e44b1 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java
@@ -25,7 +25,7 @@
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.wst.xml.ui.views.contentoutline.XMLContentOutlineConfiguration;
 
-import org.eclipse.m2e.editor.pom.XmlUtils;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 
 
 /**
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/AbstractPomProblemResolution.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/AbstractPomProblemResolution.java
index 814e28d..d423b18 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/AbstractPomProblemResolution.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/AbstractPomProblemResolution.java
@@ -32,8 +32,8 @@
 

 import org.eclipse.m2e.core.internal.IMavenConstants;

 import org.eclipse.m2e.core.ui.internal.markers.EditorAwareMavenProblemResolution;

-import org.eclipse.m2e.editor.pom.NodeOperation;

-import org.eclipse.m2e.editor.pom.XmlUtils;

+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;

+import org.eclipse.m2e.model.edit.pom.util.NodeOperation;

 

 

 @SuppressWarnings("restriction")

@@ -63,13 +63,15 @@
 

   @Override

   protected final void fix(IDocument document, List<IMarker> markers, IProgressMonitor monitor) {

-    XmlUtils.performOnRootElement(document, (NodeOperation<Element>) (node, structured) -> processFix(structured, node, markers));

+    XmlUtils.performOnRootElement(document,

+        (NodeOperation<Element>) (node, structured) -> processFix(structured, node, markers));

   }

 

   @Override

   protected final void fix(IResource resource, List<IMarker> markers, IProgressMonitor monitor) {

     try {

-      XmlUtils.performOnRootElement((IFile) resource, (node, structured) -> processFix(structured, node, markers), true);

+      XmlUtils.performOnRootElement((IFile) resource, (node, structured) -> processFix(structured, node, markers),

+          true);

     } catch(IOException e) {

       LOG.error("Error processing marker", e);

     } catch(CoreException e) {

@@ -99,7 +101,7 @@
         prevString = StringUtils.convertToHTMLContent(prevString);

         nextString = StringUtils.convertToHTMLContent(nextString);

         return "<html>...<br>" + prevString + /** "<del>" + currentLine + "</del>" + */ //$NON-NLS-0$

-        nextString + "...<html>"; //$NON-NLS-1$

+            nextString + "...<html>"; //$NON-NLS-1$

       } catch(BadLocationException e) {

         // TODO Auto-generated catch block

         e.printStackTrace();

diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/IdPartRemovalResolution.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/IdPartRemovalResolution.java
index 3a377d4..dc21b08 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/IdPartRemovalResolution.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/IdPartRemovalResolution.java
@@ -29,9 +29,9 @@
 import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;

 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;

 

-import org.eclipse.m2e.editor.pom.NodeOperation;

-import org.eclipse.m2e.editor.pom.XmlUtils;

+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;

 import org.eclipse.m2e.editor.xml.internal.Messages;

+import org.eclipse.m2e.model.edit.pom.util.NodeOperation;

 

 

 @SuppressWarnings("restriction")

diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/ManagedVersionRemovalResolution.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/ManagedVersionRemovalResolution.java
index e534d29..533623a 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/ManagedVersionRemovalResolution.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/markers/ManagedVersionRemovalResolution.java
@@ -29,9 +29,9 @@
 import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;

 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;

 

-import org.eclipse.m2e.editor.pom.NodeOperation;

-import org.eclipse.m2e.editor.pom.XmlUtils;

+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;

 import org.eclipse.m2e.editor.xml.internal.Messages;

+import org.eclipse.m2e.model.edit.pom.util.NodeOperation;

 

 

 @SuppressWarnings("restriction")

diff --git a/org.eclipse.m2e.editor/META-INF/MANIFEST.MF b/org.eclipse.m2e.editor/META-INF/MANIFEST.MF
index 703ab2d..01be1cf 100644
--- a/org.eclipse.m2e.editor/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.editor/META-INF/MANIFEST.MF
@@ -29,6 +29,7 @@
  org.eclipse.ui.genericeditor;bundle-version="1.1.500",
  org.eclipse.core.filesystem;bundle-version="1.7.500",
  org.eclipse.m2e.discovery;bundle-version="1.16.0",
+ org.eclipse.m2e.model.edit;bundle-version="1.16.0",
  com.google.guava;bundle-version="27.0.0"
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomHyperlinkDetector.java b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomHyperlinkDetector.java
index fa704f9..99bf297 100644
--- a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomHyperlinkDetector.java
+++ b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomHyperlinkDetector.java
@@ -71,6 +71,7 @@
 
 import org.eclipse.m2e.core.internal.IMavenConstants;
 import org.eclipse.m2e.core.ui.internal.actions.OpenPomAction;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 
 
 /**
diff --git a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTemplateContext.java b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTemplateContext.java
index ca93d1a..368f299 100644
--- a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTemplateContext.java
+++ b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTemplateContext.java
@@ -73,6 +73,7 @@
 import org.eclipse.m2e.core.ui.internal.search.util.ArtifactInfo;
 import org.eclipse.m2e.core.ui.internal.search.util.Packaging;
 import org.eclipse.m2e.core.ui.internal.search.util.SearchEngine;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 import org.eclipse.m2e.editor.MavenEditorImages;
 import org.eclipse.m2e.editor.internal.Messages;
 import org.eclipse.m2e.editor.mojo.IMojoParameterMetadataProvider;
diff --git a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTextHover.java b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTextHover.java
index 341b89d..0957658 100644
--- a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTextHover.java
+++ b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/PomTextHover.java
@@ -38,6 +38,7 @@
 import org.apache.maven.project.MavenProject;
 
 import org.eclipse.m2e.core.ui.internal.editing.PomEdits;
+import org.eclipse.m2e.core.ui.internal.util.XmlUtils;
 import org.eclipse.m2e.editor.internal.MarkerHoverControl;
 import org.eclipse.m2e.editor.pom.PomHyperlinkDetector.ExpressionRegion;
 import org.eclipse.m2e.editor.pom.PomHyperlinkDetector.ManagedArtifactRegion;
diff --git a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/XmlUtils.java b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/XmlUtils.java
index 9cb1fb9..8465d88 100644
--- a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/XmlUtils.java
+++ b/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/XmlUtils.java
@@ -1,299 +1,34 @@
 /*******************************************************************************
- * Copyright (c) 2008-2018 Sonatype, Inc. and others.
+ * Copyright (c) 2020 Red Hat, Inc.
  * All rights reserved. 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:
- *      Sonatype, Inc. - initial API and implementation
  *******************************************************************************/
 
 package org.eclipse.m2e.editor.pom;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Stack;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
 
-import org.eclipse.core.filebuffers.FileBuffers;
-import org.eclipse.core.filebuffers.ITextFileBuffer;
-import org.eclipse.core.filesystem.IFileStore;
-import org.eclipse.core.resources.IFile;
 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.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextViewer;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
-import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
-
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.InputSource;
-import org.apache.maven.project.MavenProject;
-
-import org.eclipse.m2e.core.MavenPlugin;
-import org.eclipse.m2e.core.embedder.IMaven;
-import org.eclipse.m2e.core.project.IMavenProjectFacade;
-import org.eclipse.m2e.core.ui.internal.editing.PomEdits;
 
 
 /**
- * @author mkleint
+ * Use {@link org.eclipse.m2e.core.ui.internal.util.XmlUtils} instead
+ *
+ * @deprecated
  */
+@Deprecated
 public class XmlUtils {
-  private static final Logger log = LoggerFactory.getLogger(XmlUtils.class);
+
+  public static IProject extractProject(ITextViewer viewer) {
+    return org.eclipse.m2e.core.ui.internal.util.XmlUtils.extractProject(viewer);
+  }
 
   public static Element findChild(Element parent, String name) {
-    return PomEdits.findChild(parent, name);
+    return org.eclipse.m2e.core.ui.internal.util.XmlUtils.findChild(parent, name);
   }
-
-  public static List<Element> findChilds(Element parent, String name) {
-    return PomEdits.findChilds(parent, name);
-  }
-
-  public static String getTextValue(Node element) {
-    return PomEdits.getTextValue(element);
-  }
-
-  /**
-   * finds exactly one (first) occurence of child element with the given name (eg. dependency) that fulfills conditions
-   * expressed by the Matchers (eg. groupId/artifactId match)
-   * 
-   * @param parent
-   * @param name
-   * @param matchers
-   * @return
-   */
-  public static Element findChild(Element parent, String name, PomEdits.Matcher... matchers) {
-    return PomEdits.findChild(parent, name, matchers);
-  }
-
-  /**
-   * what is this method supposed to do? for the sourceViewer find the associated file on disk and for that one find the
-   * IProject it belongs to. The required condition for the IProject instance is that project relative path of the file
-   * shall only be pom.xml (thus no nested, unopened maven pom). So that when
-   * MavenPlugin.getMavenProjectManager().getProject(prj); is called later on the instance, it actually returns the
-   * maven model facade for the pom.xml backing the sourceViewer.
-   * 
-   * @param sourceViewer
-   * @return
-   */
-  public static IProject extractProject(ITextViewer sourceViewer) {
-    ITextFileBuffer buf = FileBuffers.getTextFileBufferManager().getTextFileBuffer(sourceViewer.getDocument());
-    if(buf == null) {
-      //eg. for viewers of pom files in local repository
-      return null;
-    }
-    IFileStore folder = buf.getFileStore();
-    File file = new File(folder.toURI());
-    IPath path = Path.fromOSString(file.getAbsolutePath());
-    Stack<IFile> stack = new Stack<IFile>();
-    //here we need to find the most inner project to the path.
-    //we do so by shortening the path and remembering all the resources identified.
-    // at the end we pick the last one from the stack. is there a catch to it?
-    IFile ifile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
-    if(ifile != null) {
-      stack.push(ifile);
-    }
-    while(path.segmentCount() > 1) {
-      IResource ires = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
-      if(ires != null && ires instanceof IFile) {
-        stack.push((IFile) ires);
-      }
-      path = path.removeFirstSegments(1);
-    }
-    IFile res = stack.empty() ? null : stack.pop();
-    if(res != null) {
-      IProject prj = res.getProject();
-      //the project returned is in a way unrelated to nested child poms that don't have an opened project,
-      //in that case we pass along a wrong parent/aggregator
-      if(res.getProjectRelativePath().segmentCount() != 1) {
-        //if the project were the pom's project, the relative path would be just "pom.xml", if it's not just throw it out of the window..
-        prj = null;
-      }
-      return prj;
-    }
-    return null;
-  }
-
-  public static MavenProject extractMavenProject(ITextViewer sourceViewer) {
-    //look in the sourceViewer's cache only
-    if(sourceViewer instanceof IAdaptable) {
-      return ((IAdaptable) sourceViewer).getAdapter(MavenProject.class);
-    }
-    return null;
-  }
-
-  /**
-   * converts an InputLocation to a file path on the local disk, null if not available. still the input source's model
-   * value can be used further..
-   * 
-   * @param location
-   * @return
-   */
-  public static File fileForInputLocation(InputLocation location, MavenProject origin) {
-    InputSource source = location.getSource();
-    if(source != null) {
-      //MNGECLIPSE-2539 apparently if maven can't resolve the model from local storage,
-      //the location will be empty. not only applicable to local repo models but
-      //apparently also to models in workspace not reachable by relativePath 
-      String loc = source.getLocation();
-      File file = null;
-      if(loc != null) {
-        file = new File(loc);
-      } else {
-        //try to find pom by coordinates..
-        String modelId = source.getModelId();
-        if(origin.getModel().getId().equals(modelId) && origin.getFile() != null) {
-          return origin.getFile();
-        }
-        String[] splitStrings = modelId.split(":");
-        assert splitStrings.length == 3;
-        IMavenProjectFacade facade = MavenPlugin.getMavenProjectRegistry().getMavenProject(splitStrings[0],
-            splitStrings[1], splitStrings[2]);
-        if(facade != null) {
-          file = facade.getPomFile();
-        } else {
-          //if not in the workspace, try looking into the local repository.
-          IMaven maven = MavenPlugin.getMaven();
-          try {
-            String path = maven.getArtifactPath(maven.getLocalRepository(), splitStrings[0], splitStrings[1],
-                splitStrings[2], "pom", null);
-            if(path != null) {
-              file = new File(maven.getLocalRepositoryPath(), path);
-            }
-          } catch(CoreException e) {
-            log.error("Failed to calculate local repository path of artifact", e);
-          }
-        }
-      }
-      return file;
-    }
-    return null;
-  }
-
-  /**
-   * originally copied from org.eclipse.wst.xml.ui.internal.hyperlink.XMLHyperlinkDetector this method grabs the
-   * IDOMModel for the IDocument, performs the passed operation on the node at the offset and then releases the
-   * IDOMModel operation's Node value is also an instance of IndexedRegion
-   * 
-   * @param offset
-   */
-  public static void performOnCurrentElement(IDocument document, int offset, NodeOperation<Node> operation) {
-    assert document != null;
-    assert operation != null;
-    // get the current node at the offset (returns either: element,
-    // doctype, text)
-    IStructuredModel sModel = null;
-    try {
-      sModel = StructuredModelManager.getModelManager().getExistingModelForRead(document);
-      if(sModel != null) {
-        IndexedRegion inode = sModel.getIndexedRegion(offset);
-        if(inode == null) {
-          inode = sModel.getIndexedRegion(offset - 1);
-        }
-        if(inode instanceof Node) {
-          operation.process((Node) inode, sModel.getStructuredDocument());
-        }
-      }
-    } finally {
-      if(sModel != null) {
-        sModel.releaseFromRead();
-      }
-    }
-  }
-
-  /**
-   * this method grabs the IDOMModel for the IDocument, performs the passed operation on the root element of the
-   * document and then releases the IDOMModel root Element value is also an instance of IndexedRegion
-   * 
-   * @param doc
-   * @param operation
-   */
-  public static void performOnRootElement(IDocument doc, NodeOperation<Element> operation) {
-    assert doc != null;
-    assert operation != null;
-    IDOMModel domModel = null;
-    try {
-      domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
-      if(domModel == null) {
-        throw new IllegalArgumentException("Document is not structured: " + doc);
-      }
-      IStructuredDocument document = domModel.getStructuredDocument();
-      Element root = domModel.getDocument().getDocumentElement();
-      operation.process(root, document);
-    } finally {
-      if(domModel != null) {
-        domModel.releaseFromRead();
-      }
-    }
-  }
-
-  public static void performOnRootElement(IFile resource, NodeOperation<Element> operation)
-      throws IOException, CoreException {
-    performOnRootElement(resource, operation, false);
-  }
-
-  public static void performOnRootElement(IFile resource, NodeOperation<Element> operation, boolean autoSave)
-      throws IOException, CoreException {
-    assert resource != null;
-    assert operation != null;
-    IDOMModel domModel = null;
-    try {
-      domModel = (IDOMModel) StructuredModelManager.getModelManager().getModelForRead(resource);
-      if(domModel == null) {
-        throw new IllegalArgumentException("Document is not structured: " + resource);
-      }
-      IStructuredDocument document = domModel.getStructuredDocument();
-      Element root = domModel.getDocument().getDocumentElement();
-      operation.process(root, document);
-
-      if(autoSave && domModel.getReferenceCountForEdit() == 0) {
-        domModel.save();
-      }
-
-    } finally {
-      if(domModel != null) {
-        domModel.releaseFromRead();
-      }
-    }
-  }
-
-  /*
-   * calculates the path of the node up in the hierarchy, example of result is project/build/plugins/plugin
-   * level parameter designates the number of parents to climb eg. for level 2 the result would be plugins/plugin
-   * level -1 means all the way to the top. 
-   */
-  public static String pathUp(Node node, int level) {
-    StringBuilder buf = new StringBuilder();
-    int current = level;
-    while(node != null && current > 0) {
-      if(node instanceof Element) {
-        if(buf.length() > 0) {
-          buf.insert(0, "/");
-        }
-        buf.insert(0, node.getNodeName());
-        current = current - 1;
-      }
-      node = node.getParentNode();
-    }
-    return buf.toString();
-  }
-
 }
diff --git a/org.eclipse.m2e.jdt.tests/META-INF/MANIFEST.MF b/org.eclipse.m2e.jdt.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..43fbba1
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.m2e.jdt.tests;singleton:=true
+Bundle-Version: 1.16.0.qualifier
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.jdt.core,
+ org.eclipse.core.resources,
+ org.junit;bundle-version="4.12.0",
+ org.eclipse.m2e.jdt;bundle-version="1.16.0",
+ org.eclipse.m2e.tests.common;bundle-version="1.16.0",
+ org.eclipse.m2e.core;bundle-version="1.16.0",
+ org.eclipse.m2e.core.ui;bundle-version="1.16.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-Vendor: %Bundle-Vendor
+Automatic-Module-Name: org.eclipse.m2e.jdt.tests
diff --git a/org.eclipse.m2e.jdt.tests/about.html b/org.eclipse.m2e.jdt.tests/about.html
new file mode 100644
index 0000000..8eee37d
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/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>
diff --git a/org.eclipse.m2e.jdt.tests/build.properties b/org.eclipse.m2e.jdt.tests/build.properties
new file mode 100644
index 0000000..779cdf0
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/build.properties
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2008-2010 Sonatype, Inc.
+# All rights reserved. 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:
+#      Sonatype, Inc. - initial API and implementation
+#
+
+bin.includes = META-INF/,\
+               .,\
+               projects/,\
+               about.html
+jars.compile.order = .
+source.. = src/
+output.. = target/classes/
+src.includes = about.html
diff --git a/org.eclipse.m2e.jdt.tests/pom.xml b/org.eclipse.m2e.jdt.tests/pom.xml
new file mode 100644
index 0000000..ccc6b80
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright (c) 2020 Red Hat, Inc.
+  All rights reserved. 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
+-->
+<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.jdt.tests</artifactId>
+  <packaging>eclipse-test-plugin</packaging>
+
+</project>
diff --git a/org.eclipse.m2e.jdt.tests/projects/compilerSettings/pom.xml b/org.eclipse.m2e.jdt.tests/projects/compilerSettings/pom.xml
new file mode 100644
index 0000000..235c371
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/projects/compilerSettings/pom.xml
@@ -0,0 +1,25 @@
+<?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
+https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>foo.bar</groupId>
+	<artifactId>demo</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<build>
+		<pluginManagement>
+			<plugins>	
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-compiler-plugin</artifactId>
+					<version>3.8.1</version>
+					<configuration>
+						<source>1.8</source>
+						<target>1.8</target>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>
diff --git a/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/JavaConfigurationTest.java b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/JavaConfigurationTest.java
new file mode 100644
index 0000000..fd25cdb
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/JavaConfigurationTest.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Red Hat, Inc.
+ * All rights reserved. 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.jdt.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.junit.Test;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.preferences.MavenConfigurationImpl;
+import org.eclipse.m2e.tests.common.AbstractMavenProjectTestCase;
+
+
+public class JavaConfigurationTest extends AbstractMavenProjectTestCase {
+
+  @Test
+  public void testFileChangeUpdatesJDTSettings() throws CoreException, IOException, InterruptedException {
+    ((MavenConfigurationImpl) MavenPlugin.getMavenConfiguration()).setAutomaticallyUpdateConfiguration(true);
+    setAutoBuilding(true);
+    File pomFileFS = new File(FileLocator.toFileURL(getClass().getResource("/projects/compilerSettings/pom.xml")).getFile());
+    IProject project = importProject(pomFileFS.getAbsolutePath());
+    waitForJobsToComplete();
+    IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
+    assertEquals("1.8", javaProject.getOption(JavaCore.COMPILER_SOURCE, false));
+    IFile pomFileWS = project.getFile("pom.xml");
+    byte[] bytes = new byte[(int) pomFileFS.length()];
+    try (InputStream stream = pomFileWS.getContents()) {
+      stream.read(bytes);
+    }
+    String contents = new String(bytes);
+    contents = contents.replaceAll("1\\.8", "11");
+    pomFileWS.setContents(new ByteArrayInputStream(contents.getBytes()), true, false, null);
+    waitForJobsToComplete();
+    assertEquals("11", javaProject.getOption(JavaCore.COMPILER_SOURCE, false));
+  }
+}
diff --git a/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF b/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF
index 9d1b424..fccde0d 100644
--- a/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF
@@ -11,6 +11,7 @@
  org.eclipse.emf.ecore.xmi;visibility:=reexport,
  org.eclipse.emf.edit;visibility:=reexport,
  org.eclipse.emf.ecore.edit;visibility:=reexport,
+ org.eclipse.wst.common.uriresolver;visibility:=reexport,
  org.eclipse.wst.common.emf;visibility:=reexport,
  org.eclipse.wst.sse.core;visibility:=reexport,
  org.eclipse.wst.xml.core;visibility:=reexport
diff --git a/org.eclipse.m2e.model.edit/plugin.xml b/org.eclipse.m2e.model.edit/plugin.xml
index 958c5fc..7d60999 100644
--- a/org.eclipse.m2e.model.edit/plugin.xml
+++ b/org.eclipse.m2e.model.edit/plugin.xml
@@ -41,4 +41,13 @@
     </catalogContribution>
   </extension>
 
+  <extension
+        point="org.eclipse.wst.sse.core.modelHandler">
+     <modelHandler
+           associatedContentTypeId="org.eclipse.m2e.core.pomFile"
+           class="org.eclipse.m2e.model.edit.pom.PomModelHandler"
+           id="org.eclipse.m2e.core.pomFile.handler">
+     </modelHandler>
+  </extension>
+
 </plugin>
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java b/org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/PomModelHandler.java
similarity index 98%
rename from org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java
rename to org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/PomModelHandler.java
index 729926a..9318bf5 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java
+++ b/org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/PomModelHandler.java
@@ -11,7 +11,7 @@
  *      Sonatype, Inc. - initial API and implementation
  *******************************************************************************/
 
-package org.eclipse.m2e.editor.xml;
+package org.eclipse.m2e.model.edit.pom;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/NodeOperation.java b/org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/util/NodeOperation.java
similarity index 95%
rename from org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/NodeOperation.java
rename to org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/util/NodeOperation.java
index 9273793..19deca3 100644
--- a/org.eclipse.m2e.editor/src/org/eclipse/m2e/editor/pom/NodeOperation.java
+++ b/org.eclipse.m2e.model.edit/src/main/java/org/eclipse/m2e/model/edit/pom/util/NodeOperation.java
@@ -11,7 +11,7 @@
  *      Sonatype, Inc. - initial API and implementation
  *******************************************************************************/
 
-package org.eclipse.m2e.editor.pom;
+package org.eclipse.m2e.model.edit.pom.util;
 
 import org.w3c.dom.Node;
 
diff --git a/org.eclipse.m2e.tests.common/META-INF/MANIFEST.MF b/org.eclipse.m2e.tests.common/META-INF/MANIFEST.MF
index 0226437..7f3effc 100644
--- a/org.eclipse.m2e.tests.common/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.tests.common/META-INF/MANIFEST.MF
@@ -23,7 +23,7 @@
 Bundle-Vendor: %Bundle-Vendor
 MavenArtifact-GroupId: org.eclipse.m2e
 MavenArtifact-ArtifactId: org.eclipse.m2e.tests.common
-Export-Package: org.eclipse.m2e.tests.common;x-internal:=true
+Export-Package: org.eclipse.m2e.tests.common;x-friends:="org.eclipse.m2e.tests,org.eclipse.m2e.core.tests,org.eclipse.m2e.jdt.tests"
 Import-Package: javax.servlet;version="3.1.0",
  javax.servlet.http;version="3.1.0"
 Automatic-Module-Name: org.eclipse.m2e.tests.common
diff --git a/pom.xml b/pom.xml
index c872c59..683888a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -149,6 +149,7 @@
     <module>org.eclipse.m2e.importer.tests</module>
     <module>org.eclipse.m2e.binaryproject.tests</module>
     <module>org.eclipse.m2e.editor.lemminx.tests</module>
+	<module>org.eclipse.m2e.jdt.tests</module>
   </modules>