/*******************************************************************************
* Copyright (c) 2012 Michael Vorburger (http://www.vorburger.ch).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package ch.vorburger.xtext.xml;
import java.io.IOException;
import java.util.Map;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticException;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.resource.SaveOptions;
import com.google.inject.Inject;
/**
* EMF I/O Utils.
* Helpers for loading & saving EMF models as XML & DSL.
*
* The XML loading doesn't do much useful validation - the idea is that
* something else will validate the EMF model afterwards - such as an Xtext
* Resource serialization and validation rules. You would typically use the
* Export Model > XML Schema (non XMI) on the .genmodel to obtain a suitable XSD
* to illustrate how your XML has to look like for this.
*
* @author Michael Vorburger
*/
public class EIO {
protected @Inject ResourceSet resourceSet;
/**
* Saves EMF object, as XML or DSL, depending on the extension of the URI.
* The object is cloned before it is saved, because the purpose of this
* utility is to allow conversion between XML <-> DSL, without changing the
* original. If you don't need that, you would simply use
* <code>object.eResource().save(null)</code> instead.
*/
public void cloneAndSave(URI uri, EObject object) throws IOException {
Resource resource = resourceSet.createResource(uri);
if (resource == null)
throw new IOException("EMF resourceSet.getResource() => null, probably no matching resource factory is registered, for URI: " + uri.toString());
EObject clonedObject = EcoreUtil3.cloneWithProxiesIfContained(object);
resource.getContents().add(clonedObject);
// Don't Validate, but Format (which is the exact opposite of the default save options) :
Map<?, ?> saveOptions = SaveOptions.newBuilder().noValidation().format().getOptions().toOptionsMap();
resource.save(saveOptions);
// Because our special NameProvider do some Magic (name:/ Proxy URI handling), it is probably safest if we unload the resource so it gets cleanly reloaded on next access?
resource.unload();
}
public Resource loadResource(URI uri) throws IOException, DiagnosticException {
// NOTE: For the XtextResourceSet classpath resolving URIs, must use getResource() instead of a createResource() followed by a resource.load(resource.getResourceSet().getLoadOptions());
Resource resource = resourceSet.getResource(uri, true);
if (resource == null)
throw new IOException("EMF resourceSet.getResource() => null, probably no matching resource factory is registered, for URI: " + uri.toString());
if (!resource.getErrors().isEmpty()) {
Diagnostic diagnostic = EcoreUtil.computeDiagnostic(resource, false /* do not includeWarnings */);
throw new DiagnosticExceptionWithURIAndToString(diagnostic, uri);
}
return resource;
}
@SuppressWarnings("unchecked")
public <T extends EObject> T load(URI uri, Class<T> klazz) throws IOException, DiagnosticException {
return (T) load(uri);
}
public EObject load(URI uri) throws IOException, DiagnosticException {
Resource resource = loadResource(uri);
if (resource != null && !resource.getContents().isEmpty())
return resource.getContents().get(0);
else
throw new IllegalArgumentException("Loading failed, resource == null, or no contents: " + uri.toString());
}
}