blob: f996eae653d2e0d638454640b213efb6e2ef50a1 [file] [log] [blame]
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.m2e.model.edit.pom.translators;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.m2e.model.edit.pom.Model;
import org.eclipse.m2e.model.edit.pom.PomFactory;
public class SSESyncResource extends ResourceImpl {
private static final Set<String> NO_EVENT_MODELS = new HashSet<String>();
private IDOMModel domModel;
private Model pomModel;
private Document doc;
public SSESyncResource() {
super();
}
public SSESyncResource(URI uri) {
super(uri);
}
@Override
public void load(Map<?, ?> options) throws IOException {
if(isLoaded()) {
return;
}
loadDOMModel();
setProcessEvents(false);
try {
pomModel = PomFactory.eINSTANCE.createModel();
doc = domModel.getDocument();
DocumentAdapter da = new DocumentAdapter();
if(doc.getDocumentElement() != null) {
createAdapterForRootNode(domModel.getDocument().getDocumentElement()).load();
} else {
pomModel.eAdapters().add(da);
}
((IDOMNode) doc).addAdapter(da);
this.getContents().add(pomModel);
this.setLoaded(true);
} finally {
setProcessEvents(true);
}
}
@Override
protected void doSave(OutputStream outputStream, Map<?, ?> options) throws IOException {
try {
domModel.save(outputStream);
} catch(CoreException e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
}
}
@Override
protected void doUnload() {
domModel.releaseFromEdit();
}
private void loadDOMModel() throws IOException {
IFile ifile = null;
if(uri.isPlatformResource()) {
String localPath = uri.toPlatformString(true);
ifile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(localPath);
} else if(uri.isFile()) {
String filePath = uri.toFileString();
File f = new File(filePath);
IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(f.getAbsoluteFile().toURI());
if(files.length > 0) {
ifile = files[0];
}
}
try {
IModelManager modelManager = StructuredModelManager.getModelManager();
if(ifile != null && ifile.exists()) {
domModel = (IDOMModel) modelManager.getExistingModelForEdit(ifile);
}
if(null == domModel) {
if(ifile != null && ifile.exists()) {
domModel = (IDOMModel) modelManager.getModelForEdit(ifile);
} else if(uri.isFile()) {
File f = new File(uri.toFileString());
FileInputStream is = new FileInputStream(f);
try {
domModel = (IDOMModel) modelManager.getModelForEdit(f.getAbsolutePath(), is, null);
} finally {
is.close();
}
}
// Had to comment this out, ExtensibleURIConverterImpl isn't available in Eclipse 3.3
// else {
// ExtensibleURIConverterImpl converter = new ExtensibleURIConverterImpl();
// InputStream is = converter.createInputStream(uri);
// domModel = (IDOMModel) modelManager.getModelForEdit(uri.toString(), is, null);
// is.close();
// }
}
} catch(CoreException e) {
// IOException can't wrap another exception before Java 6
if(e.getCause() != null && e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
} else {
throw new IOException(e.getMessage());
}
}
}
private ModelObjectAdapter createAdapterForRootNode(Element root) {
ModelObjectAdapter adapter = new ModelObjectAdapter(this, pomModel, root);
((IDOMElement) root).addAdapter(adapter);
pomModel.eAdapters().add(adapter);
return adapter;
}
boolean isProcessEvents() {
return !NO_EVENT_MODELS.contains(domModel.getId());
}
void setProcessEvents(boolean processEvents) {
if(processEvents) {
NO_EVENT_MODELS.remove(domModel.getId());
} else {
NO_EVENT_MODELS.add(domModel.getId());
}
}
private class DocumentAdapter implements INodeAdapter, Adapter {
private Notifier target;
public boolean isAdapterForType(Object type) {
return getClass().equals(type);
}
public void notifyChanged(Notification notification) {
if(isProcessEvents()) {
setProcessEvents(false);
try {
int type = notification.getEventType();
if(Notification.ADD == type || Notification.ADD_MANY == type || Notification.SET == type) {
if(null == doc.getDocumentElement()) {
Element newRoot = doc.createElementNS("http://maven.apache.org/POM/4.0.0", //$NON-NLS-1$
"project"); //$NON-NLS-1$
newRoot.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", //$NON-NLS-1$
"xsi:schemaLocation", //$NON-NLS-1$
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"); //$NON-NLS-1$
// I think this is just wrong...but can't find a
// better way.
newRoot.setAttribute("xmlns", //$NON-NLS-1$
"http://maven.apache.org/POM/4.0.0"); //$NON-NLS-1$
newRoot.setAttribute("xmlns:xsi", //$NON-NLS-1$
"http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$
doc.appendChild(newRoot);
pomModel.setModelVersion("4.0.0"); //$NON-NLS-1$
createAdapterForRootNode(newRoot).save();
} else {
Element root = doc.getDocumentElement();
createAdapterForRootNode(root).load();
}
DocumentAdapter existingDocAdapter = (DocumentAdapter) EcoreUtil.getExistingAdapter(pomModel,
DocumentAdapter.class);
if(null != existingDocAdapter) {
pomModel.eAdapters().remove(existingDocAdapter);
}
}
} finally {
setProcessEvents(true);
}
}
}
public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue,
Object newValue, int pos) {
if(isProcessEvents()) {
setProcessEvents(false);
try {
if(INodeNotifier.ADD == eventType) {
if(newValue instanceof Element) {
Element e = (Element) newValue;
if(doc.getDocumentElement().equals(e)) {
DocumentAdapter existingDocAdapter = (DocumentAdapter) EcoreUtil.getExistingAdapter(pomModel,
DocumentAdapter.class);
if(null != existingDocAdapter) {
pomModel.eAdapters().remove(existingDocAdapter);
}
createAdapterForRootNode(e).load();
}
}
} else if(INodeNotifier.REMOVE == eventType) {
if(changedFeature instanceof Element) {
ModelObjectAdapter existing = (ModelObjectAdapter) EcoreUtil.getExistingAdapter(pomModel,
ModelObjectAdapter.class);
if(existing != null) {
pomModel.eAdapters().remove(existing);
}
if(null == doc.getDocumentElement()) {
for(EStructuralFeature feature : pomModel.eClass().getEStructuralFeatures()) {
pomModel.eUnset(feature);
}
}
DocumentAdapter existingDocAdapter = (DocumentAdapter) EcoreUtil.getExistingAdapter(pomModel,
DocumentAdapter.class);
if(null == existingDocAdapter) {
pomModel.eAdapters().add(this);
}
}
}
} finally {
setProcessEvents(true);
}
}
}
public Notifier getTarget() {
return target;
}
public void setTarget(Notifier newTarget) {
this.target = newTarget;
}
}
}