/*******************************************************************************
* Copyright (c) 2006-2013
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package de.devboost.emfcustomize;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.codegen.ecore.genmodel.GenClass;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
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.emftext.language.java.classifiers.Class;
import org.emftext.language.java.classifiers.ClassifiersFactory;
import org.emftext.language.java.classifiers.ConcreteClassifier;
import org.emftext.language.java.containers.CompilationUnit;
import org.emftext.language.java.containers.ContainersFactory;
import org.emftext.language.java.imports.ClassifierImport;
import org.emftext.language.java.imports.ImportsFactory;
import org.emftext.language.java.imports.PackageImport;
import org.emftext.language.java.instantiations.NewConstructorCall;
import org.emftext.language.java.modifiers.ModifiersFactory;
import org.emftext.language.java.types.ClassifierReference;
import org.emftext.language.java.types.NamespaceClassifierReference;
import org.emftext.language.java.types.Type;
import org.emftext.language.java.types.TypesFactory;
public class GeneratedFactoryRefactorer {
public static String CUSTOM_CLASS_SUFFIX = "Custom";
public static String CUSTOM_SUB_PACKAGE = "custom";
public static String FACTORY_CLASS_SUFFIX = "FactoryImpl";
public List<Resource> refactorFactory(URI genModelURI, URI baseURI, boolean createMissingCustomClasses, ResourceSet resourceSet) {
Resource resource = null;
try {
resource = resourceSet.getResource(genModelURI, true);
} catch (Exception e) {
e.printStackTrace();
}
if (resource == null) {
return Collections.emptyList();
}
if (resource.getContents().isEmpty()) {
return Collections.emptyList();
}
if (!(resource.getContents().get(0) instanceof GenModel)) {
return Collections.emptyList();
}
GenModel genModel = (GenModel) resource.getContents().get(0);
return refactorFactory(genModel, null, baseURI, createMissingCustomClasses);
}
public List<Resource> refactorFactory(GenModel genModel, GenClass genClass, URI baseURI, boolean createMissingCustomClasses) {
ResourceSet resourceSet = genModel.eResource().getResourceSet();
URI uri = null;
String modelDirectory = genModel.getModelDirectory();
if (genClass != null) {
GenPackage genPackage = genClass.getGenPackage();
String factoryClassName = genPackage.getQualifiedFactoryClassName();
String uriString = modelDirectory + "/" + factoryClassName.replaceAll("\\.", "/") + ".java";
uri = URI.createPlatformResourceURI(uriString, true);
} else {
// old impl
GenPackage genPackage = genModel.getGenPackages().get(0);
String baseFolder = "";
if (genPackage.getBasePackage() != null) {
baseFolder = genPackage.getBasePackage().replace('.', '/');
}
String factoryImplementationFile = modelDirectory + "/" +
baseFolder + "/" + genPackage.getEcorePackage().getName() + "/impl/" +
genPackage.getFactoryClassName() + ".java";
if (factoryImplementationFile.startsWith("/") && baseURI.toString().endsWith("/")) {
factoryImplementationFile = factoryImplementationFile.substring(1);
}
uri = URI.createURI(baseURI.toString() + factoryImplementationFile);
}
Resource factoryImplementation = null;
try {
factoryImplementation = resourceSet.getResource(uri, true);
} catch (Exception e) {
// TODO handle this exception more gracefully
e.printStackTrace();
}
if (factoryImplementation != null) {
return refactorFactory(factoryImplementation, createMissingCustomClasses);
}
return Collections.emptyList();
}
private List<Resource> refactorFactory(Resource factoryImplementation, boolean createMissingCustomClasses) {
boolean customPackageImported = false;
boolean customClassFound = false;
List<Resource> createdClasses = new ArrayList<Resource>();
for (Iterator<EObject> i = factoryImplementation.getAllContents(); i.hasNext();) {
EObject next = i.next();
if (next instanceof PackageImport) {
EList<String> namespaces = ((PackageImport) next).getNamespaces();
if (namespaces.get(namespaces.size() - 1).equals(CUSTOM_SUB_PACKAGE)) {
customPackageImported = true;
}
}
if (next instanceof NewConstructorCall) {
NewConstructorCall ncc = (NewConstructorCall) next;
Type instantiatedType = ncc.getType();
if (instantiatedType instanceof Class) {
Class instatiatedClass = (Class) instantiatedType;
if (instatiatedClass.getName().endsWith("Impl") && instatiatedClass.eResource() != factoryImplementation) {
String customClassName = instatiatedClass.getName(
).substring(0, instatiatedClass.getName().indexOf("Impl"));
customClassName = customClassName + CUSTOM_CLASS_SUFFIX;
List<String> customNameSegments = new BasicEList<String>(
instatiatedClass.getContainingCompilationUnit().getNamespaces());
customNameSegments.remove(customNameSegments.size() - 1);
customNameSegments.add(CUSTOM_SUB_PACKAGE);
if (!customPackageImported) {
PackageImport customPackageImport = ImportsFactory.eINSTANCE.createPackageImport();
customPackageImport.getNamespaces().addAll(customNameSegments);
ncc.getContainingCompilationUnit().getImports().add(customPackageImport);
customPackageImported = true;
}
customNameSegments.add(customClassName);
String fullName = null;
for(String namePart : customNameSegments) {
if (fullName == null) {
fullName = namePart;
} else {
fullName = fullName + "." + namePart;
}
}
ConcreteClassifier customClass = instatiatedClass.getConcreteClassifier(fullName);
if (customClass.eIsProxy()) {
if (createMissingCustomClasses) {
customClass = createInitialCustomClass(customNameSegments, instatiatedClass, factoryImplementation.getURI());
createdClasses.add(customClass.eResource());
} else {
customClass = null;
}
}
if (customClass != null) {
customClassFound = true;
EList<ClassifierReference> classifierReferenceChain = ((NamespaceClassifierReference) ncc.getTypeReference()).getClassifierReferences();
classifierReferenceChain.get(classifierReferenceChain.size() - 1).setTarget(customClass);
}
}
}
}
}
if (customClassFound) {
try {
factoryImplementation.save(null);
} catch (IOException e) {
e.printStackTrace();
}
}
return createdClasses;
}
public ConcreteClassifier createInitialCustomClass(
List<String> customNameSegments, Class generatedImplementation, URI relativeURI) {
ResourceSet resourceSet = generatedImplementation.eResource().getResourceSet();
URI javaClassURI = relativeURI.trimSegments(customNameSegments.size() + 1);
javaClassURI = javaClassURI.appendSegment("src");
javaClassURI = javaClassURI.appendSegments(
customNameSegments.toArray(new String[customNameSegments.size()])).appendFileExtension("java");
Resource customClassResource = resourceSet.createResource(javaClassURI);
CompilationUnit cu = generateCompilationUnit(customNameSegments);
customClassResource.getContents().add(cu);
prepareCompilationUnit(cu, generatedImplementation);
try {
customClassResource.save(null);
} catch (IOException e) {
e.printStackTrace();
}
return cu.getClassifiers().get(0);
}
public ConcreteClassifier createInitialCustomClass(GenClass genClass) {
GenModel genModel = genClass.getGenModel();
String modelPluginID = genModel.getModelPluginID();
String name = genClass.getName();
GenPackage genPackage = genClass.getGenPackage();
String qualifiedPackageName = genPackage.getQualifiedPackageName();
String path = genModel.getModelDirectory();
int indexEnd = path.indexOf(modelPluginID) + modelPluginID.length();
String srcFolder = path.substring(indexEnd + 1);
URI uri = null;
if("src".equals(srcFolder)){
uri = URI.createPlatformResourceURI(path, true);
} else {
uri = URI.createPlatformResourceURI("/" + modelPluginID, true).appendSegment("src");
}
List<String> segments = new ArrayList<String>();
for (String segment : qualifiedPackageName.split("\\.")) {
segments.add(segment);
}
segments.add(CUSTOM_SUB_PACKAGE);
String customClassName = name + CUSTOM_CLASS_SUFFIX;
segments.add(customClassName);
uri = uri.appendSegments(segments.toArray(new String[0])).appendFileExtension("java");
ResourceSet resourceSet = genClass.eResource().getResourceSet();
Resource customClassResource = resourceSet.createResource(uri);
CompilationUnit cu = generateCompilationUnit(segments);
customClassResource.getContents().add(cu);
String qualifiedSuperClassName = genClass.getQualifiedClassName();
URI superClassUri = URI.createPlatformResourceURI(path, true);
superClassUri = superClassUri.appendSegments(qualifiedSuperClassName.split("\\.")).appendFileExtension("java");
Resource superClassResource = resourceSet.getResource(superClassUri, true);
CompilationUnit scCompUnit = (CompilationUnit) superClassResource.getContents().get(0);
Class superClass = (Class) scCompUnit.getConcreteClassifier(qualifiedSuperClassName);
Class customClass = prepareCompilationUnit(cu, superClass);
try {
customClassResource.save(null);
} catch (IOException e) {
e.printStackTrace();
}
return customClass;
}
private Class prepareCompilationUnit(CompilationUnit cu, Class superClass) {
Class clazz = (Class) cu.getClassifiers().get(0);
ClassifierReference tr = TypesFactory.eINSTANCE.createClassifierReference();
tr.setTarget(superClass);
clazz.setExtends(tr);
ClassifierImport classifierImport = ImportsFactory.eINSTANCE.createClassifierImport();
classifierImport.getNamespaces().addAll(superClass.getContainingCompilationUnit().getNamespaces());
classifierImport.setClassifier(superClass);
cu.getImports().add(classifierImport);
return clazz;
}
private CompilationUnit generateCompilationUnit(List<String> fullName) {
CompilationUnit cu = ContainersFactory.eINSTANCE.createCompilationUnit();
cu.getNamespaces().addAll(fullName.subList(0, fullName.size() - 1));
Class clazz = ClassifiersFactory.eINSTANCE.createClass();
clazz.setName(fullName.get(fullName.size() - 1));
clazz.getAnnotationsAndModifiers().add(ModifiersFactory.eINSTANCE.createPublic());
cu.getClassifiers().add(clazz);
return cu;
}
}