blob: a10384229940eb2cd34e80dd8933b93acb3f2c93 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package org.eclipse.scout.sdk.internal.workspace.dto;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.scout.commons.CompositeObject;
import org.eclipse.scout.commons.annotations.ColumnData.SdkColumnCommand;
import org.eclipse.scout.sdk.extensions.runtime.classes.IRuntimeClasses;
import org.eclipse.scout.sdk.extensions.runtime.classes.RuntimeClasses;
import org.eclipse.scout.sdk.internal.ScoutSdk;
import org.eclipse.scout.sdk.sourcebuilder.SortedMemberKeyFactory;
import org.eclipse.scout.sdk.sourcebuilder.field.FieldSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.field.FieldSourceBuilderFactory;
import org.eclipse.scout.sdk.sourcebuilder.field.IFieldSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.method.IMethodBodySourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.method.IMethodSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.method.MethodSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.method.MethodSourceBuilderFactory;
import org.eclipse.scout.sdk.sourcebuilder.type.ITypeSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.type.TypeSourceBuilder;
import org.eclipse.scout.sdk.util.ScoutUtility;
import org.eclipse.scout.sdk.util.internal.sigcache.SignatureCache;
import org.eclipse.scout.sdk.util.signature.IImportValidator;
import org.eclipse.scout.sdk.util.signature.SignatureUtility;
import org.eclipse.scout.sdk.util.type.FieldFilters;
import org.eclipse.scout.sdk.util.type.IMethodFilter;
import org.eclipse.scout.sdk.util.type.ITypeFilter;
import org.eclipse.scout.sdk.util.type.MethodParameter;
import org.eclipse.scout.sdk.util.type.TypeFilters;
import org.eclipse.scout.sdk.util.type.TypeUtility;
import org.eclipse.scout.sdk.util.typecache.ITypeHierarchy;
import org.eclipse.scout.sdk.workspace.type.ScoutTypeComparators;
import org.eclipse.scout.sdk.workspace.type.ScoutTypeUtility;
import org.eclipse.scout.sdk.workspace.type.config.PropertyMethodSourceUtility;
/**
* <h3>{@link AbstractTableBeanSourceBuilder}</h3>
*
* @author Andreas Hoegger
* @since 3.10.0 27.08.2013
*/
public abstract class AbstractTableBeanSourceBuilder extends AbstractTableSourceBuilder {
protected final static int ROW_DATA_FIELD_FLAGS = Flags.AccPublic | Flags.AccFinal | Flags.AccStatic;
/**
* @param elementName
*/
public AbstractTableBeanSourceBuilder(IType modelType, String elementName, boolean setup, IProgressMonitor monitor) {
super(modelType, elementName, setup, monitor);
}
@Override
protected void createContent(IProgressMonitor monitor) {
super.createContent(monitor);
try {
IType table = DtoUtility.findTable(getModelType(), getLocalTypeHierarchy());
if (TypeUtility.exists(table)) {
visitTableBean(table, getLocalTypeHierarchy(), monitor);
}
else {
addAbstractMethodImplementations();
}
}
catch (CoreException e) {
ScoutSdk.logError("could not build form data for '" + getModelType().getFullyQualifiedName() + "'.", e);
}
}
protected IType[] getColumns(IType table, IType rowDataSuperType, final ITypeHierarchy fieldHierarchy, IProgressMonitor monitor) throws JavaModelException {
// collect all columns that exist in the table and all of its super classes
TreeSet<IType> allColumnsUpTheHierarchy = new TreeSet<IType>(ScoutTypeComparators.getOrderAnnotationComparator());
ITypeFilter filter = TypeFilters.getMultiTypeFilter(TypeFilters.getSubtypeFilter(TypeUtility.getType(RuntimeClasses.IColumn)), new ITypeFilter() {
@Override
public boolean accept(IType type) {
SdkColumnCommand command = ScoutTypeUtility.findColumnDataSdkColumnCommand(type, fieldHierarchy);
return command == null || command == SdkColumnCommand.CREATE;
}
});
IType curTableType = table;
do {
IType[] columns = TypeUtility.getInnerTypes(curTableType, filter);
for (IType column : columns) {
allColumnsUpTheHierarchy.add(column);
}
curTableType = fieldHierarchy.getSuperclass(curTableType);
if (monitor.isCanceled()) {
return null;
}
}
while (TypeUtility.exists(curTableType));
// collect all columns that exist in the row data and all of its super classes
HashSet<String> usedColumnBeanNames = new HashSet<String>();
IType currentRowDataSuperType = rowDataSuperType;
ITypeHierarchy rowDataHierarchy = TypeUtility.getSuperTypeHierarchy(rowDataSuperType);
if (!RuntimeClasses.AbstractTableRowData.equals(currentRowDataSuperType.getFullyQualifiedName())) {
do {
IField[] columnFields = TypeUtility.getFields(currentRowDataSuperType, FieldFilters.getFlagsFilter(ROW_DATA_FIELD_FLAGS));
for (IField column : columnFields) {
Object val = TypeUtility.getFieldConstant(column);
if (val instanceof String) {
usedColumnBeanNames.add(val.toString());
}
}
currentRowDataSuperType = rowDataHierarchy.getSuperclass(currentRowDataSuperType);
if (monitor.isCanceled()) {
return null;
}
}
while (TypeUtility.exists(currentRowDataSuperType) && !RuntimeClasses.AbstractTableRowData.equals(currentRowDataSuperType.getFullyQualifiedName()));
}
// filter the already existing columns out
Iterator<IType> allColumnsIterator = allColumnsUpTheHierarchy.iterator();
while (allColumnsIterator.hasNext()) {
IType col = allColumnsIterator.next();
String beanName = getColumnBeanName(col);
if (usedColumnBeanNames.contains(beanName)) {
// the current column is already in a row data of our parent -> we don't need it for us: remove
allColumnsIterator.remove();
}
if (monitor.isCanceled()) {
return null;
}
}
return allColumnsUpTheHierarchy.toArray(new IType[allColumnsUpTheHierarchy.size()]);
}
protected String getColumnBeanName(IType column) {
return ScoutUtility.ensureStartWithLowerCase(ScoutUtility.removeFieldSuffix(column.getElementName()));
}
protected void visitTableBean(IType table, ITypeHierarchy fieldHierarchy, IProgressMonitor monitor) throws CoreException {
// row data super type
String rowDataSuperClassSig = getTableRowDataSuperClassSignature(table);
IType rowDataSuperClassType = TypeUtility.getTypeBySignature(rowDataSuperClassSig);
// row data class name
String rowDataName = getElementName().replaceAll("(PageData|FieldData|Data)$", "") + "RowData";
ITypeSourceBuilder tableRowDataBuilder = new TypeSourceBuilder(rowDataName);
// row data class flags
int flags = Flags.AccPublic | Flags.AccStatic;
boolean isAbstract = Flags.isAbstract(table.getFlags()) || Flags.isAbstract(getModelType().getFlags());
if (isAbstract) {
flags |= Flags.AccAbstract;
}
tableRowDataBuilder.setFlags(flags);
tableRowDataBuilder.setSuperTypeSignature(rowDataSuperClassSig);
// serialVersionUidBuilder
IFieldSourceBuilder serialVersionUidBuilder = FieldSourceBuilderFactory.createSerialVersionUidBuilder();
tableRowDataBuilder.addSortedFieldSourceBuilder(SortedMemberKeyFactory.createFieldSerialVersionUidKey(serialVersionUidBuilder), serialVersionUidBuilder);
// constructor
IMethodSourceBuilder constructorBuilder = MethodSourceBuilderFactory.createConstructorSourceBuilder(rowDataName);
tableRowDataBuilder.addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodConstructorKey(constructorBuilder), constructorBuilder);
if (monitor.isCanceled()) {
return;
}
// get all columns
IType[] columns = getColumns(table, rowDataSuperClassType, fieldHierarchy, monitor);
if (monitor.isCanceled()) {
return;
}
// visit columns
for (int i = 0; i < columns.length; i++) {
IType column = columns[i];
String columnBeanName = getColumnBeanName(column);
String constantColName = columnBeanName;
if (ScoutUtility.isReservedJavaKeyword(constantColName)) {
constantColName += "_";
}
IFieldSourceBuilder constantFieldBuilder = new FieldSourceBuilder(constantColName);
constantFieldBuilder.setFlags(ROW_DATA_FIELD_FLAGS);
constantFieldBuilder.setSignature(SignatureCache.createTypeSignature(String.class.getName()));
constantFieldBuilder.setValue("\"" + columnBeanName + "\"");
tableRowDataBuilder.addSortedFieldSourceBuilder(new CompositeObject(SortedMemberKeyFactory.FIELD_CONSTANT + 1, i, columnBeanName), constantFieldBuilder);
// member
IFieldSourceBuilder memberFieldBuilder = new FieldSourceBuilder("m_" + columnBeanName);
memberFieldBuilder.setFlags(Flags.AccPrivate);
memberFieldBuilder.setSignature(getColumnSignature(column, TypeUtility.getSuperTypeHierarchy(column)));
tableRowDataBuilder.addSortedFieldSourceBuilder(new CompositeObject(SortedMemberKeyFactory.FIELD_MEMBER + 1, i, columnBeanName), memberFieldBuilder);
// getter
IMethodSourceBuilder getterBuilder = MethodSourceBuilderFactory.createGetter(memberFieldBuilder);
tableRowDataBuilder.addSortedMethodSourceBuilder(new CompositeObject(SortedMemberKeyFactory.METHOD_PROPERTY_ACCESS, i, 1, getterBuilder), getterBuilder);
// setter
IMethodSourceBuilder setterBuilder = MethodSourceBuilderFactory.createSetter(memberFieldBuilder);
tableRowDataBuilder.addSortedMethodSourceBuilder(new CompositeObject(SortedMemberKeyFactory.METHOD_PROPERTY_ACCESS, i, 2, setterBuilder), setterBuilder);
if (monitor.isCanceled()) {
return;
}
}
addSortedTypeSourceBuilder(SortedMemberKeyFactory.createTypeTableKey(tableRowDataBuilder), tableRowDataBuilder);
// row access methods
final String tableRowSignature = Signature.createTypeSignature(tableRowDataBuilder.getElementName(), false);
// getRows
IMethodSourceBuilder getRowsMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "getRows", new IMethodFilter() {
@Override
public boolean accept(IMethod candidate) throws CoreException {
return candidate.getReturnType().contains(IRuntimeClasses.AbstractTableRowData);
}
});
getRowsMethodBuilder.setReturnTypeSignature(Signature.createArraySignature(tableRowSignature, 1));
getRowsMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return (").append(SignatureUtility.getTypeReference(Signature.createArraySignature(tableRowSignature, 1), validator)).append(") super.getRows();");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(getRowsMethodBuilder), getRowsMethodBuilder);
// setRows
IMethodSourceBuilder setRowsMethodBuilder = new MethodSourceBuilder("setRows");
setRowsMethodBuilder.setFlags(Flags.AccPublic);
setRowsMethodBuilder.setReturnTypeSignature(Signature.SIG_VOID);
setRowsMethodBuilder.addParameter(new MethodParameter("rows", Signature.createArraySignature(tableRowSignature, 1)));
setRowsMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("super.setRows(rows);");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(setRowsMethodBuilder), setRowsMethodBuilder);
// addRow
final String addRowMethodName = "addRow";
IMethodSourceBuilder addRowMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "addRow", new IMethodFilter() {
@Override
public boolean accept(IMethod candidate) throws CoreException {
return candidate.getParameters().length == 0 && candidate.getReturnType().contains(IRuntimeClasses.AbstractTableRowData);
}
});
addRowMethodBuilder.setReturnTypeSignature(tableRowSignature);
addRowMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return (").append(SignatureUtility.getTypeReference(tableRowSignature, validator)).append(") super.addRow();");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(addRowMethodBuilder), addRowMethodBuilder);
if (monitor.isCanceled()) {
return;
}
// addRow(int state)
IMethodSourceBuilder addRowWithStateMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "addRow", new IMethodFilter() {
@Override
public boolean accept(IMethod candidate) throws CoreException {
if (addRowMethodName.equals(candidate.getElementName())) {
return candidate.getParameters().length == 1;
}
return false;
}
});
addRowWithStateMethodBuilder.setReturnTypeSignature(tableRowSignature);
addRowWithStateMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return (").append(SignatureUtility.getTypeReference(tableRowSignature, validator)).append(") super.addRow(");
source.append(methodBuilder.getParameters().get(0).getName()).append(");");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(addRowWithStateMethodBuilder), addRowWithStateMethodBuilder);
// rowAt
IMethodSourceBuilder rowAtMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "rowAt");
rowAtMethodBuilder.setReturnTypeSignature(tableRowSignature);
rowAtMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return (").append(SignatureUtility.getTypeReference(tableRowSignature, validator)).append(") super.rowAt(").append(methodBuilder.getParameters().get(0).getName()).append(");");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(rowAtMethodBuilder), rowAtMethodBuilder);
// createRow
IMethodSourceBuilder createRowMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "createRow");
createRowMethodBuilder.setReturnTypeSignature(tableRowSignature);
if (isAbstract) {
createRowMethodBuilder.setFlags(createRowMethodBuilder.getFlags() | Flags.AccAbstract);
}
else {
createRowMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return new ").append(SignatureUtility.getTypeReference(tableRowSignature, validator)).append("();");
}
});
}
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(createRowMethodBuilder), createRowMethodBuilder);
// getRowType
IMethodSourceBuilder getRowTypeMethodBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "getRowType");
getRowTypeMethodBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return ").append(SignatureUtility.getTypeReference(tableRowSignature, validator)).append(".class;");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(getRowTypeMethodBuilder), getRowTypeMethodBuilder);
}
private String getTableRowDataSuperClassSignature(IType table) throws CoreException {
if (!SignatureCache.createTypeSignature(IRuntimeClasses.AbstractTablePageData).equals(getSuperTypeSignature())) {
// use the row data in the super page data.
IType superType = TypeUtility.getTypeBySignature(getSuperTypeSignature());
IType[] rowData = superType.getTypes(); // can only be a row data
if (rowData.length > 0) {
return SignatureCache.createTypeSignature(rowData[0].getFullyQualifiedName());
}
}
return SignatureCache.createTypeSignature(IRuntimeClasses.AbstractTableRowData);
}
/**
* Gets the row data type that is used within the given table data.
*
* @param tableData
* the table data that contains the row data. the type must exist.
* @return the type that is referenced in the
* org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldBeanData#getRowType() method of
* the given table data.
* @throws CoreException
*/
protected IType getTableRowDataType(IType tableData) throws CoreException {
IMethod getRowTypeMethod = ScoutTypeUtility.getMethod(tableData, "getRowType");
return PropertyMethodSourceUtility.parseReturnParameterClass(PropertyMethodSourceUtility.getMethodReturnValue(getRowTypeMethod), getRowTypeMethod);
}
protected void addAbstractMethodImplementations() throws CoreException {
// createRow
IMethodSourceBuilder createRowSourceBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "createRow");
createRowSourceBuilder.setReturnTypeSignature(SignatureCache.createTypeSignature(RuntimeClasses.AbstractTableRowData));
createRowSourceBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return new ").append(SignatureUtility.getTypeReference(SignatureCache.createTypeSignature(RuntimeClasses.AbstractTableRowData), validator));
source.append("(){").append(lineDelimiter).append("private static final long serialVersionUID = 1L;").append(lineDelimiter).append("};");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(createRowSourceBuilder), createRowSourceBuilder);
IMethodSourceBuilder getRowTypeSourceBuilder = MethodSourceBuilderFactory.createOverrideMethodSourceBuilder(this, "getRowType");
getRowTypeSourceBuilder.setReturnTypeSignature(SignatureCache.createTypeSignature(Class.class.getName() + "<? extends " + RuntimeClasses.AbstractTableRowData + ">"));
getRowTypeSourceBuilder.setMethodBodySourceBuilder(new IMethodBodySourceBuilder() {
@Override
public void createSource(IMethodSourceBuilder methodBuilder, StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
source.append("return ").append(SignatureUtility.getTypeReference(SignatureCache.createTypeSignature(RuntimeClasses.AbstractTableRowData), validator)).append(".class;");
}
});
addSortedMethodSourceBuilder(SortedMemberKeyFactory.createMethodAnyKey(getRowTypeSourceBuilder), getRowTypeSourceBuilder);
}
}