blob: 08dd2b1f204745f8b00193d3f099a0401da51bea [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 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.sourcebuilder.type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.scout.commons.CompositeObject;
import org.eclipse.scout.commons.StringUtility;
import org.eclipse.scout.sdk.extensions.classidgenerators.ClassIdGenerators;
import org.eclipse.scout.sdk.extensions.runtime.classes.IRuntimeClasses;
import org.eclipse.scout.sdk.sourcebuilder.AbstractAnnotatableSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.annotation.AnnotationSourceBuilderFactory;
import org.eclipse.scout.sdk.sourcebuilder.annotation.IAnnotationSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.field.IFieldSourceBuilder;
import org.eclipse.scout.sdk.sourcebuilder.method.IMethodSourceBuilder;
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.TypeUtility;
/**
* <h3>{@link TypeSourceBuilder}</h3> ...
*
* @author Andreas Hoegger
* @since 3.10.0 07.03.2013
*/
public class TypeSourceBuilder extends AbstractAnnotatableSourceBuilder implements ITypeSourceBuilder {
private String m_superTypeSignature;
private String m_parentFullyQualifiedName;
private ITypeSourceBuilder m_parentSourceBuilder;
private final List<String> m_interfaceSignatures;
private final List<IFieldSourceBuilder> m_fieldSourceBuilders;
private final Map<CompositeObject, IFieldSourceBuilder> m_sortedFieldSourceBuilders;
private final List<IMethodSourceBuilder> m_methodSourceBuilders;
private final Map<CompositeObject, IMethodSourceBuilder> m_sortedMethodSourceBuilders;
private final List<ITypeSourceBuilder> m_typeSourceBuilders;
private final Map<CompositeObject, ITypeSourceBuilder> m_sortedTypeSourceBuilders;
/**
* @param elementName
* @param parentBuilder
*/
public TypeSourceBuilder(String elementName) {
super(elementName);
m_interfaceSignatures = new ArrayList<String>();
m_fieldSourceBuilders = new ArrayList<IFieldSourceBuilder>();
m_sortedFieldSourceBuilders = new TreeMap<CompositeObject, IFieldSourceBuilder>();
m_methodSourceBuilders = new ArrayList<IMethodSourceBuilder>();
m_sortedMethodSourceBuilders = new TreeMap<CompositeObject, IMethodSourceBuilder>();
m_typeSourceBuilders = new ArrayList<ITypeSourceBuilder>();
m_sortedTypeSourceBuilders = new TreeMap<CompositeObject, ITypeSourceBuilder>();
}
@Override
public void validate() throws IllegalArgumentException {
super.validate();
if (Flags.isInterface(getFlags()) && getSuperTypeSignature() != null) {
throw new IllegalArgumentException("An interface can not have a superclass.");
}
}
@Override
public void createSource(StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
super.createSource(source, lineDelimiter, ownerProject, validator);
createClassIdAnnotation(source, lineDelimiter, ownerProject, validator);
// type definition
source.append(Flags.toString(getFlags())).append(" ");
source.append(((getFlags() & Flags.AccInterface) != 0) ? ("interface ") : ("class "));
source.append(getElementName());
// add our own type name to the validator so that it cannot interfere with other types (e.g. in the jre) with the same name.
validator.getTypeName(SignatureCache.createTypeSignature(getFullyQualifiedName()));
// super type (extends)
if (!StringUtility.isNullOrEmpty(getSuperTypeSignature())) {
String superTypeRefName = SignatureUtility.getTypeReference(getSuperTypeSignature(), validator);
source.append(" extends ").append(superTypeRefName);
}
// interfaces
Iterator<String> interfaceSigIterator = getInterfaceSignatures().iterator();
if (interfaceSigIterator.hasNext()) {
source.append(((getFlags() & Flags.AccInterface) != 0) ? (" extends ") : (" implements "));
source.append(SignatureUtility.getTypeReference(interfaceSigIterator.next(), validator));
while (interfaceSigIterator.hasNext()) {
source.append(", ").append(SignatureUtility.getTypeReference(interfaceSigIterator.next(), validator));
}
}
source.append("{");
createTypeContent(source, lineDelimiter, ownerProject, validator);
source.append(lineDelimiter);
source.append("}");
}
protected void createClassIdAnnotation(StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
if (ClassIdGenerators.isAutomaticallyCreateClassIdAnnotation() && !StringUtility.isNullOrEmpty(getSuperTypeSignature())) {
IType iTypeWithClassId = TypeUtility.getType(IRuntimeClasses.ITypeWithClassId);
if (TypeUtility.exists(iTypeWithClassId)) {
IType superType = TypeUtility.getTypeBySignature(getSuperTypeSignature());
if (TypeUtility.exists(superType)) {
if (TypeUtility.getSuperTypeHierarchy(superType).contains(iTypeWithClassId)) {
IAnnotationSourceBuilder createClassIdAnnotation = AnnotationSourceBuilderFactory.createClassIdAnnotation(this);
createClassIdAnnotation.createSource(source, lineDelimiter, ownerProject, validator);
source.append(lineDelimiter);
}
}
}
}
}
/**
* @param sourceBuilder
* @param icu
* @param lineDelimiter
* @param validator
* @throws CoreException
*/
protected void createTypeContent(StringBuilder source, String lineDelimiter, IJavaProject ownerProject, IImportValidator validator) throws CoreException {
// fields
List<IFieldSourceBuilder> fieldSourceBuilders = getFieldSourceBuilders();
if (!fieldSourceBuilders.isEmpty()) {
source.append(lineDelimiter);
for (IFieldSourceBuilder builder : fieldSourceBuilders) {
if (builder != null) {
source.append(lineDelimiter);
builder.createSource(source, lineDelimiter, ownerProject, validator);
}
}
}
// methods
List<IMethodSourceBuilder> methodSourceBuilders = getMethodSourceBuilders();
if (!methodSourceBuilders.isEmpty()) {
source.append(lineDelimiter);
for (IMethodSourceBuilder op : methodSourceBuilders) {
if (op != null) {
source.append(lineDelimiter);
op.createSource(source, lineDelimiter, ownerProject, validator);
}
}
}
// inner types
List<ITypeSourceBuilder> innerTypes = getTypeSourceBuilder();
if (!innerTypes.isEmpty()) {
source.append(lineDelimiter);
for (ITypeSourceBuilder op : innerTypes) {
if (op != null) {
source.append(lineDelimiter);
op.createSource(source, lineDelimiter, ownerProject, validator);
}
}
}
}
@Override
public void setSuperTypeSignature(String superTypeSignature) {
m_superTypeSignature = superTypeSignature;
}
@Override
public String getSuperTypeSignature() {
return m_superTypeSignature;
}
@Override
public void addInterfaceSignature(String interfaceSignature) {
m_interfaceSignatures.add(interfaceSignature);
}
@Override
public boolean removeInterfaceSignature(String interfaceSignature) {
return m_interfaceSignatures.remove(interfaceSignature);
}
@Override
public void setInterfaceSignatures(String[] interfaceSignatures) {
m_interfaceSignatures.clear();
m_interfaceSignatures.addAll(Arrays.asList(interfaceSignatures));
}
@Override
public List<String> getInterfaceSignatures() {
return m_interfaceSignatures;
}
@Override
public void addFieldSourceBuilder(IFieldSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_sortedFieldSourceBuilders.isEmpty()) {
throw new IllegalStateException("This builder has already sorted field builder. A mix between sorted and unsorted field builders is not supported.");
}
m_fieldSourceBuilders.add(builder);
}
@Override
public void addSortedFieldSourceBuilder(CompositeObject sortKey, IFieldSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_fieldSourceBuilders.isEmpty()) {
throw new IllegalStateException("This builder has already unsorted field builder. A mix between sorted and unsorted field builders is not supported.");
}
m_sortedFieldSourceBuilders.put(sortKey, builder);
}
@Override
public boolean removeFieldSourceBuilder(IFieldSourceBuilder builder) {
boolean removed = m_fieldSourceBuilders.remove(builder);
if (!removed) {
Iterator<Entry<CompositeObject, IFieldSourceBuilder>> it = m_sortedFieldSourceBuilders.entrySet().iterator();
while (it.hasNext()) {
if (it.next().getValue().equals(builder)) {
it.remove();
return true;
}
}
return false;
}
return removed;
}
@Override
public List<IFieldSourceBuilder> getFieldSourceBuilders() {
List<IFieldSourceBuilder> ops = new ArrayList<IFieldSourceBuilder>();
ops.addAll(m_fieldSourceBuilders);
ops.addAll(m_sortedFieldSourceBuilders.values());
return Collections.unmodifiableList(ops);
}
@Override
public void addMethodSourceBuilder(IMethodSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_sortedMethodSourceBuilders.isEmpty()) {
throw new IllegalStateException("This source builder has already sorted method builders. A mix between sorted and unsorted method builders is not supported.");
}
m_methodSourceBuilders.add(builder);
}
@Override
public void addSortedMethodSourceBuilder(CompositeObject sortKey, IMethodSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_methodSourceBuilders.isEmpty()) {
throw new IllegalStateException("This source builder has already unsorted method builders. A mix between sorted and unsorted method builders is not supported.");
}
m_sortedMethodSourceBuilders.put(sortKey, builder);
}
@Override
public boolean removeMethodSourceBuilder(IMethodSourceBuilder builder) {
boolean removed = m_methodSourceBuilders.remove(builder);
if (!removed) {
Iterator<Entry<CompositeObject, IMethodSourceBuilder>> it = m_sortedMethodSourceBuilders.entrySet().iterator();
while (it.hasNext()) {
if (it.next().getValue().equals(builder)) {
it.remove();
return true;
}
}
return false;
}
return removed;
}
@Override
public List<IMethodSourceBuilder> getMethodSourceBuilders() {
List<IMethodSourceBuilder> builders = new ArrayList<IMethodSourceBuilder>();
builders.addAll(m_methodSourceBuilders);
builders.addAll(m_sortedMethodSourceBuilders.values());
return Collections.unmodifiableList(builders);
}
@Override
public void addTypeSourceBuilder(ITypeSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_sortedTypeSourceBuilders.isEmpty()) {
throw new IllegalStateException("This builder has already sorted inner type builders. A mix between sorted and unsorted inner type builders is not supported.");
}
m_typeSourceBuilders.add(builder);
builder.setParentTypeSourceBuilder(this);
}
@Override
public void addSortedTypeSourceBuilder(CompositeObject sortKey, ITypeSourceBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Source builder can not be null.");
}
if (!m_typeSourceBuilders.isEmpty()) {
throw new IllegalStateException("This builder has already unsorted inner type builders. A mix between sorted and unsorted inner type builders is not supported.");
}
m_sortedTypeSourceBuilders.put(sortKey, builder);
builder.setParentTypeSourceBuilder(this);
}
@Override
public boolean removeTypeSourceBuilder(ITypeSourceBuilder builder) {
boolean removed = m_typeSourceBuilders.remove(builder);
if (!removed) {
Iterator<Entry<CompositeObject, ITypeSourceBuilder>> it = m_sortedTypeSourceBuilders.entrySet().iterator();
while (it.hasNext()) {
if (it.next().getValue().equals(builder)) {
it.remove();
return true;
}
}
return false;
}
return removed;
}
@Override
public List<ITypeSourceBuilder> getTypeSourceBuilder() {
List<ITypeSourceBuilder> typeBuilders = new ArrayList<ITypeSourceBuilder>();
typeBuilders.addAll(m_typeSourceBuilders);
typeBuilders.addAll(m_sortedTypeSourceBuilders.values());
return Collections.unmodifiableList(typeBuilders);
}
@Override
public String getFullyQualifiedName() {
ITypeSourceBuilder parentSourceBuilder = getParentTypeSourceBuilder();
StringBuilder sb = null;
if (parentSourceBuilder != null) {
sb = new StringBuilder(parentSourceBuilder.getFullyQualifiedName());
}
else {
String pfqn = getParentFullyQualifiedName();
if (pfqn != null) {
sb = new StringBuilder(pfqn);
}
}
if (sb == null) {
return null;
}
return sb.append('.').append(getElementName()).toString();
}
@Override
public ITypeSourceBuilder getParentTypeSourceBuilder() {
return m_parentSourceBuilder;
}
@Override
public void setParentTypeSourceBuilder(ITypeSourceBuilder parentBuilder) {
m_parentSourceBuilder = parentBuilder;
}
@Override
public String getParentFullyQualifiedName() {
return m_parentFullyQualifiedName;
}
@Override
public void setParentFullyQualifiedName(String parentFullyQualifiedName) {
m_parentFullyQualifiedName = parentFullyQualifiedName;
}
}