/*******************************************************************************
* Copyright (c) 2012 BMW Car IT and others.
* 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 org.jnario.compiler;
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import static java.util.Arrays.asList;
import static org.eclipse.xtext.EcoreUtil2.getContainerOfType;
import static org.eclipse.xtext.util.Strings.concat;
import static org.eclipse.xtext.util.Strings.emptyIfNull;
import static org.eclipse.xtext.util.Strings.isEmpty;
import static org.eclipse.xtext.util.Strings.split;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
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.jdt.core.compiler.batch.BatchCompiler;
import org.eclipse.xtend.core.compiler.batch.XtendBatchCompiler;
import org.eclipse.xtend.core.jvmmodel.IXtendJvmAssociations;
import org.eclipse.xtend.core.xtend.XtendFile;
import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.common.types.access.impl.ClasspathTypeProvider;
import org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.generator.JavaIoFileSystemAccess;
import org.eclipse.xtext.mwe.NameBasedFilter;
import org.eclipse.xtext.mwe.PathTraverser;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.parser.IEncodingProvider;
import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.eclipse.xtext.resource.impl.ResourceSetBasedResourceDescriptions;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.IResourceValidator;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider;
import org.eclipse.xtext.xbase.compiler.JvmModelGenerator;
import org.eclipse.xtext.xbase.file.ProjectConfig;
import org.eclipse.xtext.xbase.file.RuntimeWorkspaceConfigProvider;
import org.eclipse.xtext.xbase.file.WorkspaceConfig;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
/**
* @author Sebastian - Initial contribution and API
*/
public abstract class JnarioBatchCompiler extends XtendBatchCompiler {
@Inject
private IEncodingProvider.Runtime encodingProvider;
private final Logger log = Logger.getLogger(getClass());
@Inject
private JvmModelGenerator generator;
@Inject
private IGeneratorConfigProvider generatorConfigprovider;
@Inject
private IXtendJvmAssociations xtendJvmAssociations;
@Override
protected File createStubs(ResourceSet resourceSet) {
File outputDirectory = createTempDir("stubs");
JavaIoFileSystemAccess fileSystemAccess = javaIoFileSystemAccessProvider
.get();
fileSystemAccess.setOutputPath(outputDirectory.toString());
List<EObject> objectsWithClasses = getObjectsWithClasses(jnarioResources(resourceSet));
for (EObject eObject : objectsWithClasses) {
StringBuilder classSignatureBuilder = new StringBuilder();
String packageName = getPackageName(eObject);
if (!Strings.isEmpty(packageName)) {
classSignatureBuilder.append("package " + packageName + ";");
classSignatureBuilder.append("\n");
}
classSignatureBuilder.append("public class "
+ getClassName(eObject) + "{}");
String javaFileName = getJavaFileName(eObject);
if (log.isDebugEnabled()) {
log.debug("create java stub '" + javaFileName + "'");
}
fileSystemAccess.generateFile(javaFileName,
classSignatureBuilder.toString());
}
return outputDirectory;
}
@Override
protected void generateJavaFiles(ResourceSet resourceSet) {
JavaIoFileSystemAccess javaIoFileSystemAccess = javaIoFileSystemAccessProvider
.get();
javaIoFileSystemAccess.setOutputPath(outputPath);
javaIoFileSystemAccess.setWriteTrace(writeTraceFiles);
for (Resource resource : jnarioResources(resourceSet)) {
XtendFile file = filter(resource.getContents(), XtendFile.class)
.iterator().next();
for (XtendTypeDeclaration xtendClass : file.getXtendTypes()) {
String packageName = toPath(getPackageName(xtendClass));
for (JvmGenericType type : filter(resource.getContents(),
JvmGenericType.class)) {
CharSequence generatedType = generator.generateType(type,
generatorConfigprovider.get(xtendClass));
String fileName = packageName + type.getSimpleName()
+ ".java";
javaIoFileSystemAccess
.generateFile(fileName, generatedType);
}
}
}
List<EObject> objectsWithClasses = getObjectsWithClasses(jnarioResources(resourceSet));
if (log.isInfoEnabled()) {
int size = Iterables.size(objectsWithClasses);
if (size == 0) {
log.info("No sources to compile in '" + sourcePath + "'");
} else {
log.info("Compiling " + size + " source "
+ (size == 1 ? "file" : "files") + " to " + outputPath);
}
}
for (EObject eObject : objectsWithClasses) {
Iterable<JvmDeclaredType> jvmGenericTypes = Iterables.filter(
xtendJvmAssociations.getJvmElements(eObject),
JvmDeclaredType.class);
for (JvmDeclaredType jvmType : jvmGenericTypes) {
CharSequence generatedType = generator.generateType(jvmType,
generatorConfigprovider.get(eObject));
String javaFileName = getJavaFileName(eObject);
if (log.isDebugEnabled()) {
log.debug("write '" + outputPath + File.separator
+ javaFileName + "'");
}
javaIoFileSystemAccess
.generateFile(javaFileName, generatedType);
}
}
}
@Override
protected List<Issue> validate(ResourceSet resourceSet) {
List<Issue> issues = Lists.newArrayList();
List<Resource> resources = newArrayList(resourceSet.getResources());
for (Resource resource : resources) {
if (fileExtensionProvider
.isValid(resource.getURI().fileExtension())) {
IResourceServiceProvider resourceServiceProvider = ((XtextResource) resource)
.getResourceServiceProvider();
IResourceValidator resourceValidator = resourceServiceProvider
.getResourceValidator();
List<Issue> result = resourceValidator.validate(resource,
CheckMode.ALL, null);
addAll(issues, result);
}
}
return issues;
}
protected Iterable<Resource> jnarioResources(ResourceSet resourceSet) {
return newArrayList(filter(resourceSet.getResources(),
new Predicate<Resource>() {
public boolean apply(Resource resource) {
return fileExtensionProvider.isValid(resource.getURI()
.fileExtension());
}
}));
}
protected String getJavaFileName(EObject obj) {
String packageName = getPackageName(obj);
String javaClassName = getClassName(obj) + ".java";
return toPath(packageName) + javaClassName;
}
private String toPath(String packageName) {
if (packageName == null) {
return "";
}
return packageName.replaceAll("\\.", "/") + "/";
}
protected String getPackageName(EObject obj) {
return getContainerOfType(obj, XtendFile.class).getPackage();
}
protected abstract String getClassName(EObject eObject);
protected List<EObject> getObjectsWithClasses(Iterable<Resource> resources) {
List<EObject> result = newArrayList();
for (Resource resource : resources) {
addObjectsWithClasses(resource, result);
}
return result;
}
protected abstract void addObjectsWithClasses(Resource resource,
List<EObject> result);
protected ResourceSet loadXtendFiles(final ResourceSet resourceSet) {
encodingProvider.setDefaultEncoding(getFileEncoding());
final NameBasedFilter nameBasedFilter = new NameBasedFilter();
nameBasedFilter.setExtension(fileExtensionProvider.getPrimaryFileExtension());
PathTraverser pathTraverser = new PathTraverser();
List<String> sourcePathDirectories = getSourcePathDirectories();
Multimap<String, URI> pathes = pathTraverser.resolvePathes(sourcePathDirectories, new Predicate<URI>() {
public boolean apply(URI input) {
boolean matches = nameBasedFilter.matches(input);
return matches;
}
});
for (String src : pathes.keySet()) {
URI baseDir = URI.createFileURI(src+"/");
String identifier = Joiner.on("_").join(baseDir.segments());
for (URI uri : pathes.get(src)) {
if (log.isDebugEnabled()) {
log.debug("load xtend file '" + uri + "'");
}
resourceSet.getResource(uri, true);
}
}
return resourceSet;
}
}