blob: 983af6cf740d28748169cb23fe3d4c5056ce557e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Vrije Universiteit Brussel.
* 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
*
* Contributors:
* Dennis Wagelaar, Vrije Universiteit Brussel - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.m2m.atl.emftvm.compiler;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.EMFPlugin;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.m2m.atl.common.ATLLogger;
import org.eclipse.m2m.atl.core.ATLCoreException;
import org.eclipse.m2m.atl.core.IModel;
import org.eclipse.m2m.atl.core.emf.EMFModel;
import org.eclipse.m2m.atl.core.emf.EMFModelFactory;
import org.eclipse.m2m.atl.core.emf.EMFReferenceModel;
import org.eclipse.m2m.atl.dsls.core.EMFTCSInjector;
import org.eclipse.m2m.atl.engine.parser.AtlParser;
/**
* Wraps the ATL parser.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class AtlResourceImpl extends ResourceImpl {
/**
* {@link IOException} with nested {@link Exception}.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public static class ATLIOException extends IOException {
private static final long serialVersionUID = -6673120460005697460L;
/**
* Creates a new {@link ATLIOException}.
*/
public ATLIOException() {
super();
}
/**
* Creates a new {@link ATLIOException}.
*
* @param message
* the error message
* @param cause
* the nested exception
*/
public ATLIOException(String message, Throwable cause) {
super(message);
initCause(cause);
}
/**
* Creates a new {@link ATLIOException}.
*
* @param message
* the error message
*/
public ATLIOException(String message) {
super(message);
}
/**
* Creates a new {@link ATLIOException}.
*
* @param cause
* the nested exception
*/
public ATLIOException(Throwable cause) {
super();
initCause(cause);
}
}
/**
* Wraps an {@link EMFModel} around this resource.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class EMFModelWrapper extends EMFModel {
/**
* Creates a new {@link EMFModelWrapper} around this resource.
*/
public EMFModelWrapper() {
super((EMFReferenceModel) parser.getAtlMetamodel(), (EMFModelFactory) parser.getModelFactory());
setResource(AtlResourceImpl.this);
}
}
protected final AtlParser parser = AtlParser.getDefault();
protected final EMFModelWrapper modelWrapper = new EMFModelWrapper();
protected final EMFModelFactory modelFactory = new EMFModelFactory();
private byte[] rawContent;
/**
* Creates a new {@link AtlResourceImpl}.
*/
public AtlResourceImpl() {
super();
setTrackingModification(true);
}
/**
* Creates a new {@link AtlResourceImpl} for <code>uri</code>.
*
* @param uri
* the resource's URI
*/
public AtlResourceImpl(URI uri) {
super(uri);
setTrackingModification(true);
}
/**
* Returns the raw concrete syntax for this resource.
*
* @return the rawContent
*/
protected byte[] getRawContent() {
return rawContent;
}
/**
* Sets the raw concrete syntax for this resource.
*
* @param rawContent
* the rawContent to set
*/
protected void setRawContent(byte[] rawContent) {
this.rawContent = rawContent;
}
/**
* Loads an ATL resource.
*
* @param inputStream
* the data source
* @param options
* options passed to the ATL parser
*/
@Override
protected void doLoad(final InputStream inputStream, final Map<?, ?> options) throws IOException {
// Cache original input
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final byte[] buf = new byte[1024];
int read;
while ((read = inputStream.read(buf)) > 0) {
bos.write(buf, 0, read);
}
setRawContent(bos.toByteArray());
// Parse model
final EMFTCSInjector ebnfi = new EMFTCSInjector();
final IModel pbs = modelFactory.newModel(parser.getProblemMetamodel());
final Map<Object, Object> params = new HashMap<Object, Object>();
params.put("name", "ATL");
params.put("problems", pbs);
if (options != null) {
params.putAll(options);
}
final Reader reader = new InputStreamReader(new ByteArrayInputStream(getRawContent()), getCharset());
ebnfi.inject(modelWrapper, reader, params);
// Report problems
int nbErrors = 0;
for (Iterator<? extends Object> i = pbs
.getElementsByType(parser.getProblemMetamodel().getMetaElementByName("Problem")).iterator(); i
.hasNext();) {
final EObject ame = (EObject) i.next();
final Enumerator severity = (Enumerator) ame.eGet(ame.eClass().getEStructuralFeature("severity"));
List<Diagnostic> list = null;
if (severity.getName().equals("error")) {
list = getErrors();
nbErrors++;
} else if (severity.getName().equals("warning")) {
list = getWarnings();
}
if (list != null) {
final String message = (String) ame.eGet(ame.eClass().getEStructuralFeature("description")); //$NON-NLS-1$
final String location = (String) ame.eGet(ame.eClass().getEStructuralFeature("location")); //$NON-NLS-1$
final String parts[] = location.split("-")[0].split(":");
final int line = Integer.parseInt(parts[0]);
final int column = Integer.parseInt(parts[1]);
list.add(new Diagnostic() {
public int getColumn() {
return column;
}
public int getLine() {
return line;
}
public String getLocation() {
return getURI().toString();
}
public String getMessage() {
return message;
}
@Override
public String toString() {
final StringBuffer buf = new StringBuffer(getMessage());
buf.append(" (");
buf.append(getLocation());
buf.append(':');
buf.append(getLine());
buf.append(')');
return buf.toString();
}
});
}
}
if (nbErrors == 0) {
getWarnings().clear(); // because the EMF editor fails when there
// are warnings
}
registerEPackages(modelWrapper.getReferenceModel().getResource());
}
/**
* Saves an ATL resource.
*
* @param outputStream
* the data destination
* @param options
* the options passed to the ATL extractor
*/
@Override
protected void doSave(final OutputStream outputStream, final Map<?, ?> options) throws IOException {
final byte[] rawContent = getRawContent();
if (!isModified() && rawContent != null) {
ATLLogger.fine("Content not modified - saving original content.");
outputStream.write(rawContent);
outputStream.close();
} else {
try {
parser.extract(modelWrapper, outputStream, options);
} catch (ATLCoreException e) {
throw new ATLIOException(e);
}
}
}
/**
* Registers any dynamic EPackage URIs in <code>res</code>.
*
* @param res
* the resource containing the EPackages
* @throws IOException
* if the nsURIs from EPackages from r are already registered by
* other EPackages
*/
protected void registerEPackages(final Resource res) throws IOException {
final ResourceSet rs = getResourceSet();
final Registry r = rs.getPackageRegistry();
for (EObject o : res.getContents()) {
if (o instanceof EPackage) {
EPackage p = (EPackage) o;
Object existing = r.get(p.getNsURI());
if (existing != null && existing != p) {
throw new IOException(String.format(
"EPackage with URI \"%s\" already registered by another EPackage instance", p.getNsURI()));
}
r.put(p.getNsURI(), p);
}
}
}
/**
* Returns the {@link Charset} to use for the current {@link URI}.
*
* @return the {@link Charset} to use for the current {@link URI}
* @throws IOException
*/
protected Charset getCharset() throws IOException {
final URI uri = getURI();
if (uri != null && uri.isPlatformResource() && EMFPlugin.IS_ECLIPSE_RUNNING) {
final IWorkspaceRoot wr = ResourcesPlugin.getWorkspace().getRoot();
final IResource r = wr.findMember(uri.toPlatformString(true));
if (r instanceof IFile) {
try {
return Charset.forName(((IFile) r).getCharset());
} catch (CoreException e) {
throw new ATLIOException(e);
}
}
}
return Charset.defaultCharset();
}
}