/**
* Optimus, framework for Model Transformation
*
* Copyright (C) 2013 Worldline or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.atos.optimus.m2m.javaxmi.operation.accesses;
import java.util.Iterator;
import net.atos.optimus.m2m.javaxmi.operation.annotations.builders.AnnotationTypeDeclarationBuilder;
import net.atos.optimus.m2m.javaxmi.operation.annotations.builders.UnresolvedAnnotationDeclarationBuilder;
import net.atos.optimus.m2m.javaxmi.operation.classes.UnresolvedClassDeclarationBuilder;
import net.atos.optimus.m2m.javaxmi.operation.elements.Element;
import net.atos.optimus.m2m.javaxmi.operation.interfaces.UnresolvedInterfaceDeclarationBuilder;
import net.atos.optimus.m2m.javaxmi.operation.packages.JavaPackage;
import net.atos.optimus.m2m.javaxmi.operation.packages.PackageHelper;
import net.atos.optimus.m2m.javaxmi.operation.types.ArrayTypeBuilder;
import net.atos.optimus.m2m.javaxmi.operation.types.PrimitiveTypeBuilder;
import net.atos.optimus.m2m.javaxmi.operation.types.UnresolvedTypeBuilder;
import net.atos.optimus.m2m.javaxmi.operation.types.WildCardTypeBuilder;
import net.atos.optimus.m2m.javaxmi.operation.util.ASTElementFinder;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration;
import org.eclipse.gmt.modisco.java.AnnotationTypeDeclaration;
import org.eclipse.gmt.modisco.java.Model;
import org.eclipse.gmt.modisco.java.ParameterizedType;
import org.eclipse.gmt.modisco.java.Type;
import org.eclipse.gmt.modisco.java.TypeAccess;
import org.eclipse.gmt.modisco.java.UnresolvedAnnotationDeclaration;
/**
* The purpose of such class is to help with the creation of type accesses
*
* @author tnachtergaele <nachtergaele.thomas@gmail.com>
*
*
*/
public class TypeAccessHelper {
/** String constant : entry character of an array */
public static final String ARRAY_ENTRY = "[";
/** String constant : exit character of an array */
public static final String ARRAY_EXIT = "]";
/** String constant : entry character of a parameterized type */
public static final String PARAMETRIZED_ENTRY = "<";
/** String constant : separator of a parameterized type */
public static final String PARAMETRIZED_SEPARATOR = ",";
/** String constant : the wild card character */
public static final String WILD_CARD = "?";
/** The Java keyword for class extension */
public static final String EXTENSION = "extends";
/** The Java keyword for generalization */
public static final String GENERALIZATION = "super";
/** String constant : separator of package chunks */
public static final String PACKAGE_SEPARATOR = ".";
/**
* Private constructor
*
*/
private TypeAccessHelper() {
}
/**
* Create a type access associated to a class
*
* @param className
* the class name which we want a type access.
* @return the created type access associated to the specified class name.
*/
public static TypeAccess createClassTypeAccess(String className) {
if (className.contains(TypeAccessHelper.PARAMETRIZED_ENTRY)) {
return TypeAccessHelper.createParameterizedType(
TypeAccessHelper.createClassTypeAccess(className.substring(0,
className.indexOf(TypeAccessHelper.PARAMETRIZED_ENTRY))), className);
}
return TypeAccessBuilder.builder()
.setType(UnresolvedClassDeclarationBuilder.builder().setName(className).build()).build();
}
/**
* Create a type access associated to an interface
*
* @param interfaceName
* the interface name which we want a type access.
* @return the created type access associated to the specified interface
* name.
*/
public static TypeAccess createInterfaceTypeAccess(String interfaceName) {
if (interfaceName.contains(TypeAccessHelper.PARAMETRIZED_ENTRY)) {
return TypeAccessHelper.createParameterizedType(
TypeAccessHelper.createInterfaceTypeAccess(interfaceName.substring(0,
interfaceName.indexOf(TypeAccessHelper.PARAMETRIZED_ENTRY))), interfaceName);
}
return TypeAccessBuilder.builder()
.setType(UnresolvedInterfaceDeclarationBuilder.builder().setName(interfaceName).build()).build();
}
/**
* Create a type access associated to an exception
*
* @param exceptionName
* the exception name which we want a type access.
* @return the created type access associated to the specified exception
* name.
*/
public static TypeAccess createExceptionTypeAccess(String exceptionName) {
if (exceptionName.contains(TypeAccessHelper.PARAMETRIZED_ENTRY)) {
return TypeAccessHelper.createParameterizedType(
TypeAccessHelper.createExceptionTypeAccess(exceptionName.substring(0,
exceptionName.indexOf(TypeAccessHelper.PARAMETRIZED_ENTRY))), exceptionName);
}
return TypeAccessBuilder.builder().setType(PrimitiveTypeBuilder.builder().setName(exceptionName).build())
.build();
}
/**
* Create a type access associated to an annotation
*
* @param element
* the element which we associate the annotation.
* @param packageName
* the name of the package of the element.
* @param annotationName
* the name of the annotation.
* @return the created type access associated to the specified annotation
* name.
*/
public static TypeAccess createAnnotationTypeAccess(Element<?> element, String packageName, String annotationName) {
Model model = ASTElementFinder.findModel(element.getDelegate());
JavaPackage javaPackage = PackageHelper.createPackage(model, packageName);
AnnotationTypeDeclaration generatedAnnotation = null;
Iterator<AbstractTypeDeclaration> declarationIterator = javaPackage.getDelegate().getOwnedElements().iterator();
while (declarationIterator.hasNext() && generatedAnnotation == null) {
AbstractTypeDeclaration next = declarationIterator.next();
if (next instanceof AnnotationTypeDeclaration && annotationName.equals(next.getName())) {
generatedAnnotation = (AnnotationTypeDeclaration) next;
}
}
if (generatedAnnotation == null) {
return TypeAccessBuilder
.builder()
.setType(
AnnotationTypeDeclarationBuilder.builder().setName(annotationName)
.setPackage(javaPackage.getDelegate()).setProxy(true).build()).build();
}
return TypeAccessBuilder.builder().setType(generatedAnnotation).build();
}
/**
* Create a type access associated to an orphan annotation
*
* @param element
* the element which we associate the orphan annotation.
* @param fullyQualifiedName
* the full qualified name of the orphan annotation.
* @return the created type access associated to the specified orphan
* annotation name.
*/
public static TypeAccess createOrphanAnnotationTypeAccess(Element<?> element, String fullyQualifiedName) {
Model model = element == null ? null : ASTElementFinder.findModel(element.getDelegate());
UnresolvedAnnotationDeclaration annotation = null;
if (model != null) {
Iterator<Type> iterator = model.getOrphanTypes().iterator();
while (iterator.hasNext() && annotation == null) {
Type orphanType = iterator.next();
if (orphanType instanceof UnresolvedAnnotationDeclaration
&& fullyQualifiedName.equals(orphanType.getName())) {
annotation = (UnresolvedAnnotationDeclaration) orphanType;
}
}
}
if (annotation == null) {
annotation = UnresolvedAnnotationDeclarationBuilder.builder().setName(fullyQualifiedName).build();
if (model != null) {
model.getOrphanTypes().add(annotation);
}
}
return TypeAccessBuilder.builder().setType(annotation).build();
}
/**
* Create a type associated to a class or an interface
*
* @param typeName
* the type name which we want a type access.
* @return the created type access associated to the specified type name.
*/
public static TypeAccess createTypeAccess(String typeName) {
typeName = typeName.trim();
if (typeName.contains(TypeAccessHelper.ARRAY_ENTRY)) {
return TypeAccessHelper.createArrayType(
TypeAccessHelper.createTypeAccess(typeName.substring(0,
typeName.indexOf(TypeAccessHelper.ARRAY_ENTRY))), typeName);
}
if (typeName.contains(TypeAccessHelper.PARAMETRIZED_ENTRY)) {
return TypeAccessHelper.createParameterizedType(
TypeAccessHelper.createTypeAccess(typeName.substring(0,
typeName.indexOf(TypeAccessHelper.PARAMETRIZED_ENTRY))), typeName);
}
if (Character.isLowerCase(typeName.charAt(0)) && !typeName.contains(TypeAccessHelper.PACKAGE_SEPARATOR)) {
return TypeAccessBuilder.builder().setType(PrimitiveTypeBuilder.builder().setName(typeName).build())
.build();
}
return TypeAccessBuilder.builder().setType(UnresolvedTypeBuilder.builder().setName(typeName).build()).build();
}
/**
* Create an array type
*
* @param mainType
* the main type of the array type.
* @param name
* the name of the array type.
* @return the created type access associated to the specified array type.
*/
protected static TypeAccess createArrayType(TypeAccess mainType, String name) {
int dimensions = 0;
int index = 0;
while ((index = name.indexOf(TypeAccessHelper.ARRAY_EXIT, index + 1)) != -1) {
dimensions++;
}
return TypeAccessBuilder.builder()
.setType(ArrayTypeBuilder.builder().setDimensions(dimensions).setElementType(mainType).build()).build();
}
/**
* Create a parameterized type
*
* @param mainType
* the main type of the parameterized type.
* @param name
* the name of the parameterized type.
* @return the created type access associated to the specified parameterized
* type.
*/
protected static TypeAccess createParameterizedType(TypeAccess mainType, String name) {
String[] arguments = name.substring(name.indexOf(TypeAccessHelper.PARAMETRIZED_ENTRY) + 1, name.length() - 1)
.split(TypeAccessHelper.PARAMETRIZED_SEPARATOR);
ParameterizedType parameterizedType = ParameterizedTypeBuilder.builder().setType(mainType).setName(name)
.build();
EList<TypeAccess> argumentsList = parameterizedType.getTypeArguments();
for (String argument : arguments) {
argumentsList.add(TypeAccessHelper.createTypeParametrizedArgument(argument));
}
return TypeAccessBuilder.builder().setType(parameterizedType).build();
}
/**
* Create type for an argument of a parameterized type
*
* @param argument
* the argument of the parameterized type in one string.
* @return the created type for the specified argument of a parameterized
* type.
*/
protected static TypeAccess createTypeParametrizedArgument(String argument) {
String[] argumentParts = argument.trim().split("\\s+");
if (argumentParts.length >= 3) {
if (TypeAccessHelper.WILD_CARD.equals(argumentParts[0])) {
return TypeAccessBuilder
.builder()
.setType(
WildCardTypeBuilder.builder()
.setUpperBound(TypeAccessHelper.EXTENSION.equals(argumentParts[1]))
.setBound(TypeAccessHelper.createClassTypeAccess(argumentParts[2])).build())
.build();
}
return TypeAccessHelper.createClassTypeAccess(argumentParts[0]);
}
if (TypeAccessHelper.WILD_CARD.equals(argumentParts[0])) {
TypeAccessBuilder.builder().setType(WildCardTypeBuilder.builder().build()).build();
}
return TypeAccessHelper.createClassTypeAccess(argumentParts[0]);
}
}