/* * Copyright 2012 PRODYNA AG * * Licensed under the Eclipse Public License (EPL), Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php or * http://www.nabucco.org/License.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.nabucco.framework.generator.compiler.transformation.java.common.reflection; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.nabucco.framework.generator.compiler.NabuccoCompilerSupport; import org.nabucco.framework.generator.compiler.transformation.common.collection.CollectionImplementationType; import org.nabucco.framework.generator.compiler.transformation.java.common.basetype.BasetypeFacade; import org.nabucco.framework.generator.compiler.transformation.java.visitor.NabuccoToJavaVisitorSupport; import org.nabucco.framework.generator.compiler.visitor.util.NabuccoPropertyKey; import org.nabucco.framework.generator.parser.model.multiplicity.NabuccoMultiplicityType; import org.nabucco.framework.generator.parser.model.multiplicity.NabuccoMultiplicityTypeMapper; import org.nabucco.framework.generator.parser.syntaxtree.BasetypeStatement; import org.nabucco.framework.generator.parser.syntaxtree.DatatypeDeclaration; import org.nabucco.framework.generator.parser.syntaxtree.DatatypeStatement; import org.nabucco.framework.generator.parser.syntaxtree.ExtensionDeclaration; import org.nabucco.framework.generator.parser.syntaxtree.MessageStatement; import org.nabucco.framework.generator.parser.syntaxtree.Node; import org.nabucco.framework.generator.parser.syntaxtree.NodeToken; import org.nabucco.framework.mda.model.java.JavaCompilationUnit; import org.nabucco.framework.mda.model.java.JavaModelException; import org.nabucco.framework.mda.model.java.ast.JavaAstType; import org.nabucco.framework.mda.model.java.ast.element.JavaAstElementFactory; import org.nabucco.framework.mda.model.java.ast.element.method.JavaAstMethodSignature; import org.nabucco.framework.mda.model.java.ast.produce.JavaAstModelProducer; /** * NabuccoToJavaReflectionFacade * * @author Nicolas Moser, PRODYNA AG */ public class NabuccoToJavaReflectionFacade { /** Signature for getProperties() method. */ static final JavaAstMethodSignature GET_PROPERTIES = new JavaAstMethodSignature("getProperties"); /** Signature for createPropertyContainer() method. */ static final JavaAstMethodSignature GET_PROPERTY_CONTAINER = new JavaAstMethodSignature("createPropertyContainer"); /** Signature for setProperty() method. */ static final JavaAstMethodSignature SET_PROPERTY = new JavaAstMethodSignature("setProperty", "NabuccoProperty"); /** Signature for setProperty() method. */ static final JavaAstMethodSignature GET_PROPERTY_DESCRIPTOR = new JavaAstMethodSignature("getPropertyDescriptor", "String"); /** Signature for setProperty() method. */ static final JavaAstMethodSignature GET_PROPERTY_DESCRIPTOR_LIST = new JavaAstMethodSignature( "getPropertyDescriptorList"); /** * Singleton instance. */ private static NabuccoToJavaReflectionFacade instance = new NabuccoToJavaReflectionFacade(); /** * Private constructor. */ private NabuccoToJavaReflectionFacade() { } /** * Singleton access. * * @return the NabuccoToJavaReflectionFacade instance. */ public static NabuccoToJavaReflectionFacade getInstance() { return instance; } /** * Create get/set properties methods for basetypes. * * @param basetype * nabucco basetype statement * @param unit * java compilation unit * * @throws JavaModelException * when the reflection methods cannot be created */ public void createReflectionMethods(BasetypeStatement basetype, JavaCompilationUnit unit) throws JavaModelException { if (!basetype.nodeOptional.present()) { return; } Node node = basetype.nodeOptional.node; if (!(node instanceof ExtensionDeclaration)) { return; } ExtensionDeclaration extension = (ExtensionDeclaration) node; String superType = ((NodeToken) extension.nodeChoice.choice).tokenImage; String simpleType = BasetypeFacade.mapToPrimitiveType(superType); this.handleSimpleGetProperties(unit); this.handleCreatePropertyContainer(simpleType, unit); this.handleStaticMethods(unit); } /** * Mofiy the static getPropertyDescriptor() methods. * * @param unit * the java unit * * @throws JavaModelException */ private void handleStaticMethods(JavaCompilationUnit unit) throws JavaModelException { JavaAstType factory = JavaAstElementFactory.getInstance().getJavaAstType(); TypeDeclaration type = unit.getType(); final TypeReference classTypeReference = JavaAstModelProducer.getInstance().createTypeReference( factory.getTypeName(type), false); AbstractMethodDeclaration[] methods = new AbstractMethodDeclaration[] { factory.getMethod(type, GET_PROPERTY_DESCRIPTOR), factory.getMethod(type, GET_PROPERTY_DESCRIPTOR_LIST) }; ASTVisitor alterClassLiteral = new ASTVisitor() { @Override public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) { classLiteral.type = classTypeReference; return super.visit(classLiteral, scope); } }; for (AbstractMethodDeclaration currentMethodDeclaration : methods) { for (Statement statement : currentMethodDeclaration.statements) { statement.traverse(alterClassLiteral, null); } } } /** * Modify the getPropertyContainer method. * * @param simpleType * the simple type name * @param unit * the java unit * * @throws JavaModelException */ private void handleCreatePropertyContainer(String simpleType, JavaCompilationUnit unit) throws JavaModelException { JavaAstElementFactory javaFactory = JavaAstElementFactory.getInstance(); JavaAstModelProducer producer = JavaAstModelProducer.getInstance(); TypeDeclaration type = unit.getType(); AbstractMethodDeclaration method = javaFactory.getJavaAstType().getMethod(type, GET_PROPERTY_CONTAINER); MessageSend putToMap = (MessageSend) method.statements[1]; MessageSend createSimpletypeCall = (MessageSend) putToMap.arguments[1]; createSimpletypeCall.arguments[1] = producer.createClassLiteralAccess(simpleType); } /** * Modify the getProperties method for simple types. * * @param unit * the java unit * * @throws JavaModelException */ private void handleSimpleGetProperties(JavaCompilationUnit unit) throws JavaModelException { JavaAstElementFactory javaFactory = JavaAstElementFactory.getInstance(); JavaAstModelProducer producer = JavaAstModelProducer.getInstance(); MethodDeclaration getProperties = (MethodDeclaration) javaFactory.getJavaAstType().getMethod(unit.getType(), GET_PROPERTIES); MessageSend addProperty = (MessageSend) getProperties.statements[1]; MessageSend allocation = (MessageSend) addProperty.arguments[0]; MessageSend innerCall = (MessageSend) allocation.receiver; innerCall.receiver = producer.createSingleNameReference(javaFactory.getJavaAstType() .getTypeName(unit.getType())); } /** * Create get/set properties methods for datatypes. * * @param datatype * nabucco datatype statement * @param qualifiedName * the qualified name * @param imports * the type imports * @param unit * java compilation unit * @param nabuccoExtension * the extended type if any or <code>null</code>. * @param properties * the parent properties * * @throws JavaModelException * when the reflection methods cannot be created */ public void createReflectionMethods(DatatypeStatement datatype, String qualifiedName, Set<String> imports, JavaCompilationUnit unit, String nabuccoExtension, Map<NabuccoPropertyKey, Node> properties) throws JavaModelException { NabuccoToJavaPropertiesVisitor visitor = new NabuccoToJavaPropertiesVisitor(qualifiedName, imports, nabuccoExtension, properties, CollectionImplementationType.NABUCCO); datatype.accept(visitor); // Skip if super-class is of same component! if (datatype.nodeOptional1.present()) { Node extension = datatype.nodeOptional1.node; if (extension instanceof ExtensionDeclaration) { ExtensionDeclaration extensionDeclaration = (ExtensionDeclaration) extension; String extensionType = ((NodeToken) extensionDeclaration.nodeChoice.choice).tokenImage; String pkg = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); String importString = NabuccoToJavaVisitorSupport.resolveImport(extensionType, pkg, imports); if (!NabuccoCompilerSupport.isOtherComponent(qualifiedName, importString)) { visitor.finish(unit); return; } } } // Inherited Datatype Declarations for (Entry<NabuccoPropertyKey, Node> entry : properties.entrySet()) { Node property = entry.getValue(); if (property instanceof DatatypeDeclaration) { DatatypeDeclaration datatypeProperty = (DatatypeDeclaration) property; if (datatypeProperty.nodeOptional.present()) { continue; } NabuccoMultiplicityType multiplicity = NabuccoMultiplicityTypeMapper.getInstance().mapToMultiplicity( datatypeProperty.nodeToken1.tokenImage); if (multiplicity.isMultiple()) { continue; } String importString = entry.getKey().getQualifiedType(); if (!NabuccoCompilerSupport.isOtherComponent(qualifiedName, importString)) { continue; } imports.add(importString); property.accept(visitor); } } visitor.finish(unit); } /** * Create get/set properties methods for messages. * * @param message * nabucco message statement * @param qualifiedName * the qualified name * @param imports * the type imports * @param unit * java compilation unit * * @throws JavaModelException * when the reflection methods cannot be created */ public void createReflectionMethods(MessageStatement message, String qualifiedName, Set<String> imports, JavaCompilationUnit unit) throws JavaModelException { NabuccoToJavaPropertiesVisitor visitor = new NabuccoToJavaPropertiesVisitor(qualifiedName, imports, null, null, CollectionImplementationType.NABUCCO); message.accept(visitor); handleStaticMethods(unit); visitor.finish(unit); } }