org.gvnix.addon.gva.security.providers.safe.SafeSecurityProviderExtLoadWSS4JMetadata.java Source code

Java tutorial

Introduction

Here is the source code for org.gvnix.addon.gva.security.providers.safe.SafeSecurityProviderExtLoadWSS4JMetadata.java

Source

/*
 * gvNIX. Spring Roo based RAD tool for Generalitat Valenciana
 * Copyright (C) 2013 Generalitat Valenciana
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/copyleft/gpl.html>.
 */
package org.gvnix.addon.gva.security.providers.safe;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.gvnix.support.ItdBuilderHelper;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.ConstructorMetadata;
import org.springframework.roo.classpath.details.ConstructorMetadataBuilder;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.details.comments.AbstractComment;
import org.springframework.roo.classpath.details.comments.CommentStructure;
import org.springframework.roo.classpath.details.comments.JavadocComment;
import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.model.DataType;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;

/**
 * ITD generator for {@link GvNIXExtLoadWSS4JOutInterceptor} annotation.
 * 
 * @author gvNIX Team
 * @since 1.5
 */
public class SafeSecurityProviderExtLoadWSS4JMetadata extends AbstractItdTypeDetailsProvidingMetadataItem {

    private static final JavaType FAULT_EXCEPTION = new JavaType("org.apache.cxf.interceptor.Fault");

    private static final JavaType SOAP_MESSAGE_PARAM_TYPE = new JavaType("org.apache.cxf.binding.soap.SoapMessage");

    private static final JavaType SOAP_MESSAGE_PARAM_ARRAY_TYPE = new JavaType(
            SOAP_MESSAGE_PARAM_TYPE.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, null);

    private static final JavaSymbolName HANDLE_MESSAGE_METHOD = new JavaSymbolName("handleMessage");

    private static final JavaType JAVA_TYPE_STRING = new JavaType("java.lang.String");

    // Constants
    private static final String PROVIDES_TYPE_STRING = SafeSecurityProviderExtLoadWSS4JMetadata.class.getName();
    private static final String PROVIDES_TYPE = MetadataIdentificationUtils.create(PROVIDES_TYPE_STRING);
    private static final String TRACEABILITY = "traceabilityId";

    /**
     * Itd builder herlper
     */
    private ItdBuilderHelper helper;

    public SafeSecurityProviderExtLoadWSS4JMetadata(String identifier, JavaType aspectName,
            PhysicalTypeMetadata governorPhysicalTypeMetadata) {
        super(identifier, aspectName, governorPhysicalTypeMetadata);

        // Helper itd generation
        this.helper = new ItdBuilderHelper(this, governorPhysicalTypeMetadata,
                builder.getImportRegistrationResolver());

        // Adding Fields
        builder.addField(getField("LOGGER", "Logger.getLogger(ExtLoadWSS4JOutInterceptor.class)",
                new JavaType("org.apache.log4j.Logger"), Modifier.PRIVATE + Modifier.STATIC + Modifier.FINAL));
        builder.addField(getField(TRACEABILITY, null, JAVA_TYPE_STRING, Modifier.PRIVATE));

        // Creating constructors
        builder.addConstructor(getExtLoadWSS4JConst());
        builder.addConstructor(getExtLoadWSS4JConstWithParam());

        // Creating methods
        builder.addMethod(getSetterMethod(TRACEABILITY, JAVA_TYPE_STRING));
        builder.addMethod(getHandleMessageMethod());

        // Create a representation of the desired output ITD
        itdTypeDetails = builder.build();
    }

    /**
     * Generates constructor method without arguments
     */
    private ConstructorMetadataBuilder getExtLoadWSS4JConst() {

        // Search for an existing constructor
        final ConstructorMetadata existingExplicitConstructor = governorTypeDetails.getDeclaredConstructor(null);
        if (existingExplicitConstructor != null) {
            // Found an existing no-arg constructor on this class, so return it
            return new ConstructorMetadataBuilder(existingExplicitConstructor);
        }

        // Create the method body
        InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
        bodyBuilder.appendFormalLine("super();");

        // Use the ConstructorMetadataBuilder for easy creation of
        // MethodMetadata
        ConstructorMetadataBuilder consBuilder = new ConstructorMetadataBuilder(getId());
        // Set the modifier public to constructor
        consBuilder.setModifier(Modifier.PUBLIC);
        // Set the body to constructor
        consBuilder.setBodyBuilder(bodyBuilder);

        // return a ConstructorMetadataBuilder instance
        return consBuilder;
    }

    /**
     * Generates constructor method with arguments
     */
    private ConstructorMetadataBuilder getExtLoadWSS4JConstWithParam() {

        // Define method parameter types
        List<JavaType> parameterTypes = new ArrayList<JavaType>();
        parameterTypes.add(new JavaType("java.util.Map", 0, DataType.TYPE, null,
                Arrays.asList(JavaType.STRING, JavaType.OBJECT)));

        // Search for an existing constructor
        final ConstructorMetadata existingExplicitConstructor = governorTypeDetails
                .getDeclaredConstructor(parameterTypes);
        if (existingExplicitConstructor != null) {
            // Found an existing constructor on this class with this params, so
            // return it
            return new ConstructorMetadataBuilder(existingExplicitConstructor);
        }

        // Create the method body
        InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
        bodyBuilder.appendFormalLine("super(props);");

        // Use the ConstructorMetadataBuilder for easy creation of
        // MethodMetadata
        ConstructorMetadataBuilder consBuilder = new ConstructorMetadataBuilder(getId());
        // Set parameters
        consBuilder.addParameter("props", parameterTypes.get(0));
        // Set the modifier public to constructor
        consBuilder.setModifier(Modifier.PUBLIC);
        // Set the body to constructor
        consBuilder.setBodyBuilder(bodyBuilder);

        // return a ConstructorMetadataBuilder instance
        return consBuilder;
    }

    /**
     * Generates handleMessage method with SoapMessage argument
     */
    private MethodMetadata getHandleMessageMethod() {
        // Define method parameter types
        List<AnnotatedJavaType> parameterTypes = AnnotatedJavaType
                .convertFromJavaTypes(SOAP_MESSAGE_PARAM_ARRAY_TYPE);

        // Check if a method with the same signature already exists in the
        // target type
        final MethodMetadata method = methodExists(HANDLE_MESSAGE_METHOD, parameterTypes);
        if (method != null) {
            // If it already exists, just return the method and omit its
            // generation via the ITD
            return method;
        }

        // Define method annotations
        List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();

        // Create reference to override annotation
        AnnotationMetadataBuilder overrideAnnotation = new AnnotationMetadataBuilder();
        overrideAnnotation.setAnnotationType(new JavaType("java.lang.Override"));

        // Define method throws types
        List<JavaType> throwsTypes = new ArrayList<JavaType>();
        throwsTypes.add(FAULT_EXCEPTION);

        // Define method parameter names
        List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
        parameterNames.add(new JavaSymbolName("mc"));

        // Create the method body
        InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
        buildHandleMessageMethodBody(bodyBuilder);

        // Use the MethodMetadataBuilder for easy creation of MethodMetadata
        MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC,
                HANDLE_MESSAGE_METHOD, JavaType.VOID_PRIMITIVE, parameterTypes, parameterNames, bodyBuilder);
        methodBuilder.setAnnotations(annotations);
        methodBuilder.setThrowsTypes(throwsTypes);

        // Add javadoc
        List<AbstractComment> listComments = new ArrayList<AbstractComment>();
        CommentStructure comStruct = new CommentStructure();
        JavadocComment jvDocCom = new JavadocComment();
        StringBuilder strB = new StringBuilder("Add property Id_trazabilidad");
        strB.append(" head to SOAP message \n\n@param mc SoapMessage where add");
        strB.append(" traceability head");
        jvDocCom.setComment(strB.toString());
        listComments.add(jvDocCom);
        comStruct.setBeginComments(listComments);
        methodBuilder.setCommentStructure(comStruct);

        return methodBuilder.build(); // Build and return a MethodMetadata
        // instance
    }

    /**
     * Builds body method for <code>handleMessage</code> method. <br>
     * 
     * @param bodyBuilder
     */
    private void buildHandleMessageMethodBody(InvocableMemberBodyBuilder bodyBuilder) {
        // DocumentBuilder builder = null;
        bodyBuilder.appendFormalLine(String.format("%s builder = null;",
                helper.getFinalTypeName(new JavaType("javax.xml.parsers.DocumentBuilder"))));

        bodyBuilder.appendFormalLine("try {");
        bodyBuilder.indent();

        // builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        bodyBuilder.appendFormalLine(String.format("builder = %s.newInstance().newDocumentBuilder();",
                helper.getFinalTypeName(new JavaType("javax.xml.parsers.DocumentBuilderFactory"))));

        // Document doc = builder.newDocument();
        bodyBuilder.appendFormalLine(String.format("%s doc = builder.newDocument();",
                helper.getFinalTypeName(new JavaType("org.w3c.dom.Document"))));
        // Element idTrazabilidad = doc.createElement("Id_trazabilidad");
        bodyBuilder.appendFormalLine(String.format("%s idTrazabilidad = doc.createElement(\"Id_trazabilidad\");",
                helper.getFinalTypeName(new JavaType("org.w3c.dom.Element"))));

        bodyBuilder.appendFormalLine("idTrazabilidad.setAttribute(\"xmlns\",");
        bodyBuilder.indent();
        bodyBuilder.appendFormalLine("\"http://dgti.gva.es/interoperabilidad\");\n");
        bodyBuilder.indentRemove();

        // Calendar nowDate = Calendar.getInstance();
        bodyBuilder.appendFormalLine(String.format("%s nowDate = Calendar.getInstance();",
                helper.getFinalTypeName(new JavaType("java.util.Calendar"))));

        // SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        bodyBuilder.appendFormalLine(String.format("%s format = new SimpleDateFormat(\"yyyyMMddHHmmssSSS\");",
                helper.getFinalTypeName(new JavaType("java.text.SimpleDateFormat"))));

        bodyBuilder.appendFormalLine("String nowDateString = format.format(nowDate.getTime());\n");

        bodyBuilder.appendFormalLine("idTrazabilidad.appendChild(doc.createTextNode(this.traceabilityId");
        bodyBuilder.indent();
        bodyBuilder.appendFormalLine(".concat(nowDateString)));");
        bodyBuilder.indentRemove();

        // QName qnameIdTrazabilidad = new QName("Id_trazabilidad");
        bodyBuilder.appendFormalLine(String.format("%s qnameIdTrazabilidad = new QName(\"Id_trazabilidad\");\n",
                helper.getFinalTypeName(new JavaType("javax.xml.namespace.QName"))));

        // Header header = new Header(qnameIdTrazabilidad, idTrazabilidad);
        bodyBuilder.appendFormalLine(String.format("%s header = new Header(qnameIdTrazabilidad, idTrazabilidad);",
                helper.getFinalTypeName(new JavaType("org.apache.cxf.headers.Header"))));

        bodyBuilder.appendFormalLine("mc.getHeaders().add(header);");

        // close try
        bodyBuilder.indentRemove();
        bodyBuilder.appendFormalLine("}");

        // catch
        bodyBuilder.appendFormalLine(String.format("catch (%s ex) {",
                helper.getFinalTypeName(new JavaType("javax.xml.parsers.ParserConfigurationException"))));
        bodyBuilder.indent();
        // put exception message in log
        bodyBuilder.appendFormalLine("LOGGER.warn(ex.getLocalizedMessage(), ex);");

        // close catch
        bodyBuilder.indentRemove();
        bodyBuilder.appendFormalLine("}\n");
        // return
        bodyBuilder.appendFormalLine("super.handleMessage(mc);");
    }

    /**
     * Checks if method exists by name and parameters
     * 
     * @param methodName Name of the method
     * @param paramTypes List of the parameters included in the method
     * @return the method if exists, null otherwise
     */
    private MethodMetadata methodExists(JavaSymbolName methodName, List<AnnotatedJavaType> paramTypes) {
        return MemberFindingUtils.getDeclaredMethod(governorTypeDetails, methodName,
                AnnotatedJavaType.convertFromAnnotatedJavaTypes(paramTypes));
    }

    /**
     * Gets all setters methods. <br>
     * 
     * @return
     */
    private MethodMetadata getSetterMethod(String propertyName, JavaType parameterType) {
        // Define method parameter types
        List<AnnotatedJavaType> parameterTypes = AnnotatedJavaType.convertFromJavaTypes(parameterType);

        // Check if a method with the same signature already exists in the
        // target type
        JavaSymbolName propertyMethodName = new JavaSymbolName(
                "set".concat(Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1)));
        final MethodMetadata method = methodExists(propertyMethodName, parameterTypes);

        if (method != null) {
            // If it already exists, just return the method and omit its
            // generation via the ITD
            return method;
        }

        // Define method annotations
        List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();

        // Define method throws types
        List<JavaType> throwsTypes = new ArrayList<JavaType>();

        // Define method parameter names
        List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
        parameterNames.add(new JavaSymbolName(propertyName));

        // Create the method body
        InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
        buildSetterMethodBody(bodyBuilder, propertyName);

        // Use the MethodMetadataBuilder for easy creation of MethodMetadata
        MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC,
                propertyMethodName, JavaType.VOID_PRIMITIVE, parameterTypes, parameterNames, bodyBuilder);
        methodBuilder.setAnnotations(annotations);
        methodBuilder.setThrowsTypes(throwsTypes);

        return methodBuilder.build(); // Build and return a MethodMetadata
        // instance
    }

    /**
     * Builds body method for all setters methods. <br>
     * 
     * @param bodyBuilder
     */
    private void buildSetterMethodBody(InvocableMemberBodyBuilder bodyBuilder, String propertyName) {
        bodyBuilder.appendFormalLine("this.".concat(propertyName).concat(" = ").concat(propertyName).concat(";"));

    }

    public String toString() {
        final ToStringBuilder builder = new ToStringBuilder(this);
        builder.append("identifier", getId());
        builder.append("valid", valid);
        builder.append("aspectName", aspectName);
        builder.append("destinationType", destination);
        builder.append("governor", governorPhysicalTypeMetadata.getId());
        builder.append("itdTypeDetails", itdTypeDetails);
        return builder.toString();
    }

    /**
     * Create metadata for a field definition.
     * 
     * @return a FieldMetadata object
     */
    private FieldMetadata getField(String name, String value, JavaType javaType, int modifier) {
        JavaSymbolName curName = new JavaSymbolName(name);
        String initializer = value;
        FieldMetadata field = getOrCreateField(curName, javaType, initializer, modifier, null);
        return field;
    }

    /**
     * Gets or creates a field based on parameters.<br>
     * First try to get a suitable field (by name and type). If not found create
     * a new one (adding a counter to name if it's needed)
     * 
     * @param fielName
     * @param fieldType
     * @param initializer (String representation)
     * @param modifier See {@link Modifier}
     * @param annotations optional (can be null)
     * @return
     */
    private FieldMetadata getOrCreateField(JavaSymbolName fielName, JavaType fieldType, String initializer,
            int modifier, List<AnnotationMetadataBuilder> annotations) {
        JavaSymbolName curName = fielName;

        // Check if field exist
        FieldMetadata currentField = governorTypeDetails.getDeclaredField(curName);
        if (currentField != null) {
            if (!currentField.getFieldType().equals(fieldType)) {
                // No compatible field: look for new name
                currentField = null;
                JavaSymbolName newName = curName;
                int i = 1;
                while (governorTypeDetails.getDeclaredField(newName) != null) {
                    newName = new JavaSymbolName(curName.getSymbolName().concat(StringUtils.repeat('_', i)));
                    i++;
                }
                curName = newName;
            }
        }
        if (currentField == null) {
            // create field
            if (annotations == null) {
                annotations = new ArrayList<AnnotationMetadataBuilder>(0);
            }
            // Using the FieldMetadataBuilder to create the field
            // definition.
            final FieldMetadataBuilder fieldBuilder = new FieldMetadataBuilder(getId(), modifier, annotations,
                    curName, // Field
                    fieldType); // Field type
            fieldBuilder.setFieldInitializer(initializer);
            currentField = fieldBuilder.build(); // Build and return a
            // FieldMetadata
            // instance
        }
        return currentField;

    }

    public static final String getMetadataIdentiferType() {
        return PROVIDES_TYPE;
    }

    public static final String createIdentifier(JavaType javaType, LogicalPath path) {
        return PhysicalTypeIdentifierNamingUtils.createIdentifier(PROVIDES_TYPE_STRING, javaType, path);
    }

    public static final JavaType getJavaType(String metadataIdentificationString) {
        return PhysicalTypeIdentifierNamingUtils.getJavaType(PROVIDES_TYPE_STRING, metadataIdentificationString);
    }

    public static final LogicalPath getPath(String metadataIdentificationString) {
        return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING, metadataIdentificationString);
    }

    public static boolean isValid(String metadataIdentificationString) {
        return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING, metadataIdentificationString);
    }
}