package archmapper.main.codegenerator;
import java.io.ByteArrayInputStream;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jdt.ui.wizards.NewInterfaceWizardPage;
import org.eclipse.swt.widgets.Display;
import archmapper.main.conformance.MappingHelper;
import archmapper.main.exceptions.ArchMapperException;
import archmapper.main.model.archmapping.ClassDefinition;
public class CodeGenerationHelper {
/**
* Creates a new class. Uses the eclipse "new class"-Wizard for this purpose.
* Since the wizard has UI-elements and the code generation is not part of
* the UI-Thread, it is executed in a syncExec-Environment.
*
* @param pkg
* @param className
* @param superClass
* @param interfaces
* @param javaProject
*
* @return true, if a new class was generated. False, if the class already existed.
*/
public static boolean createClass(final String pkg, final String className,
final String superClass, final List<String> interfaces, final IJavaProject javaProject) {
try {
final IJavaElement clazz = javaProject.findElement(new Path(pkg + "."+ className + ".java"));
if (clazz != null) {
return false;
}
Display.getDefault().syncExec(new Runnable() {
public void run() {
try {
IPackageFragment pkgFrag = getOrCreatePackage(pkg, javaProject);
NewClassWizardPage newClassWizard = new NewClassWizardPage();
newClassWizard.setAddComments(false, false);
newClassWizard.setPackageFragment(pkgFrag, false);
newClassWizard.setMethodStubSelection(false, true, true, false);
newClassWizard.setTypeName(className, false);
if (superClass != null) {
newClassWizard.setSuperClass(superClass, false);
}
for (String interfc : interfaces) {
newClassWizard.addSuperInterface(interfc);
}
try {
newClassWizard.createType(null);
} catch (Exception e) {
throw new ArchMapperException("Error creating new class: "+ e.getMessage(), e);
}
} catch (JavaModelException e) {
throw new ArchMapperException(e);
}
}
});
} catch (JavaModelException e1) {
e1.printStackTrace();
}
return true;
}
/**
* Creates a new interface. Uses the eclipse "new interface"-Wizard for this purpose.
* Since the wizard has UI-elements and the code generation is not part of
* the UI-Thread, it is executed in a syncExec-Environment.
*
* @param pkg
* @param ifName
* @param superInterfaces
* @param javaProject
*/
public static void createInterface(final String pkg, final String ifName,
final List<String> superInterfaces, final IJavaProject javaProject) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
try {
IJavaElement iface = javaProject.findElement(new Path(pkg + "."+ ifName + ".java"));
if (iface == null) {
IPackageFragment pkgFrag = getOrCreatePackage(pkg, javaProject);
NewInterfaceWizardPage newIfWizard = new NewInterfaceWizardPage();
newIfWizard.setAddComments(false, false);
newIfWizard.setPackageFragment(pkgFrag, false);
newIfWizard.setTypeName(ifName, false);
for (String interfc : superInterfaces) {
newIfWizard.addSuperInterface(interfc);
}
try {
newIfWizard.createType(null);
} catch (Exception e) {
throw new ArchMapperException("Error creating new interface: "+ e.getMessage(), e);
}
}
} catch (JavaModelException e) {
throw new ArchMapperException(e);
}
}
});
}
public static void createFile(String pkg, String filename, String template, IJavaProject javaProject) {
try {
IPackageFragment fragment = getOrCreatePackage(pkg, javaProject);
IResource resource = fragment.getCorrespondingResource();
if (resource != null && resource instanceof IFolder) {
IFile file = ((IFolder) resource).getFile(filename);
if (!file.exists()) {
try {
file.create(new ByteArrayInputStream(template.getBytes()), true, null);
} catch (CoreException e) {
throw new ArchMapperException("Could not create file "+ file + ": "+ e.getMessage(), e);
}
}
}
} catch (JavaModelException e) {
throw new ArchMapperException("Error creating new file: "+ e.getMessage(), e);
}
}
private static IPackageFragment getOrCreatePackage(String pkg, IJavaProject javaProject) throws JavaModelException {
if (javaProject.getAllPackageFragmentRoots().length == 0) {
throw new ArchMapperException("The project does not have a package fragment root - create one!");
}
IPackageFragmentRoot packageRoot = javaProject.getAllPackageFragmentRoots()[0];
IJavaElement javaPkg = javaProject.findElement(new Path(pkg));
if (javaPkg == null) {
javaPkg = packageRoot.createPackageFragment(pkg, false, null);
}
return (IPackageFragment) javaPkg;
}
/**
* Generates an attribute in the given class with protected visibility and public
* getters and setters.
*
* @param classDef
* @param attrClass
* @param javaProject
* @param mappingHelper
*/
public static void generateAttributeForClass(ClassDefinition classDef, ClassDefinition attrClass, IJavaProject javaProject, MappingHelper mappingHelper) {
String qName = mappingHelper.getQualifiedClassname(classDef);
IJavaElement clazz;
try {
clazz = javaProject.findElement(new Path(qName +".java"));
if (clazz != null && clazz instanceof ICompilationUnit) {
ICompilationUnit compUnit = (ICompilationUnit) clazz;
IType type = compUnit.findPrimaryType();
if (type != null) {
String attrName = firstCharacterToLowerCase(attrClass.getClassName());
String attrPackage = mappingHelper.getPackageOfImplementationArtifact(attrClass);
IJavaElement sibling = null;
if (type.getChildren().length > 0) {
sibling = type.getChildren()[0];
}
if (!type.getField(attrName).exists()) {
type.createField("protected "+ attrClass.getClassName() + " "
+ attrName+ ";", sibling, false, null);
// add an import statement if necessary...
if (attrPackage != null && !attrPackage.equals("") &&
!attrPackage.equals(type.getPackageFragment().getElementName())) {
compUnit.createImport(attrPackage + "."+
attrClass.getClassName(), null, null);
}
String getter = "public "+ attrClass.getClassName() + " get"+
attrClass.getClassName() + "() {\n return "+ attrName+ ";"+
"\n}";
// Generate getters and setters...
type.createMethod(getter, null, false, null);
String setter = "public void set"+ attrClass.getClassName()+
"("+ attrClass.getClassName() + " " + attrName + ") {\n"+
" this."+ attrName + " = "+ attrName+ ";"+
"\n}";
type.createMethod(setter, null, false, null);
}
}
compUnit.save(null, true);
}
} catch (JavaModelException e) {
throw new ArchMapperException("Could not add an attribute to the class "+ qName+ ": " + e.getMessage(), e);
}
}
/**
* converts the first character of the given String to lower case. This can be
* used to convert class names to attribute names.
*
* @param str
* @return
*/
public static String firstCharacterToLowerCase(String str) {
return (""+ str.charAt(0)).toLowerCase() + str.substring(1);
}
}