org.mule.config.transformer.AbstractAnnotatedTransformerArgumentResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.config.transformer.AbstractAnnotatedTransformerArgumentResolver.java

Source

/*
 * $Id$
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.config.transformer;

import org.mule.api.MuleContext;
import org.mule.api.lifecycle.Disposable;
import org.mule.api.transformer.DataType;
import org.mule.transformer.types.CollectionDataType;
import org.mule.util.annotation.AnnotationUtils;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * An abstract resolver that can be extend to resolve/create an object based on Annotated classes. These classes can be
 * scanned and used to create the context.  Typically this class will be used to create resolvers for binding frameworks
 * where the data type classes are annotated with binding information.
 */
public abstract class AbstractAnnotatedTransformerArgumentResolver
        implements TransformerArgumentResolver, Disposable {
    public static final String[] ignoredPackages = { "java.", "javax.", "org.w3c.", "org.mule.transport.",
            "org.mule.module." };

    /**
     * logger used by this class
     */
    protected transient final Log logger = LogFactory.getLog(getClass());

    //We cache the Json classes so we don't scan them each time a context is needed
    private Set<Class> matchingClasses = new CopyOnWriteArraySet<Class>();

    //We also cache the classes that did not match so that we dont scan them again either
    private Set<Class> nonMatchingClasses = new CopyOnWriteArraySet<Class>();

    public <T> T resolve(Class<T> type, DataType source, DataType result, MuleContext context) throws Exception {
        //Lets make sure this is the right resolver for the object type and that we haven't scanned these before
        //and determined they are not Json classes
        if (!getArgumentClass().isAssignableFrom(type) || isNonMatching(source, result)) {
            return null;
        }

        Class annotatedType = (result instanceof CollectionDataType ? ((CollectionDataType) result).getItemType()
                : result.getType());

        //Check the cache first
        boolean isAnnotated = matchingClasses.contains(annotatedType);
        if (!isAnnotated) {
            //then scan the class for annotations
            isAnnotated = findAnnotation(annotatedType);
        }

        if (!isAnnotated) {
            annotatedType = source.getType();
            //Check the cache first
            isAnnotated = matchingClasses.contains(annotatedType);
            if (!isAnnotated) {
                //then scan the class for annotations
                isAnnotated = AnnotationUtils.hasAnnotationWithPackage(getAnnotationsPackageName(), annotatedType);
            }
        }

        Object argument = context.getRegistry().lookupObject(getArgumentClass());

        if (!isAnnotated) {
            //We didn't find Json annotations anywhere, lets cache the classes so we don't need to scan again
            nonMatchingClasses.add(source.getType());
            nonMatchingClasses.add(result.getType());

            //Finally if there is an Object Mapper configured we should return it
            return (T) argument;
        } else {
            matchingClasses.add(annotatedType);
        }

        if (argument == null) {
            logger.info("No common Object of type '" + getArgumentClass()
                    + "' configured, creating a local one for: " + source + ", " + result);
            argument = createArgument(annotatedType, context);
        }
        return (T) argument;

    }

    protected boolean findAnnotation(Class annotatedType) throws IOException {

        if (annotatedType.getPackage() == null) {
            return false;
        }

        for (String ignoredPackage : ignoredPackages) {
            if (annotatedType.getPackage().getName().startsWith(ignoredPackage)) {
                return false;
            }
        }
        return AnnotationUtils.hasAnnotationWithPackage(getAnnotationsPackageName(), annotatedType);
    }

    protected boolean isNonMatching(DataType source, DataType result) {
        return nonMatchingClasses.contains(result.getType()) && nonMatchingClasses.contains(source.getType());
    }

    public void dispose() {
        nonMatchingClasses.clear();
        matchingClasses.clear();
    }

    public Set<Class> getMatchingClasses() {
        return matchingClasses;
    }

    public Set<Class> getNonMatchingClasses() {
        return nonMatchingClasses;
    }

    /**
     * The object type that this resolver will discover or create
     * @return  The object type that this resolver will discover or create
     */
    protected abstract Class<?> getArgumentClass();

    /**
     * If the resolver cannot locate the required object of type {@link #getArgumentClass()} this method will be invoked
     * an instance of the object.
     *
     * @param annotatedType the annotated object that was matched
     * @param muleContext the current Mule context.
     * @return a new instance of the object being resolved.  This method may also retain a shared instance and possible add
     * configuration to the instance based on this invocation
     * @throws Exception if the object cannot be created
     */
    protected abstract Object createArgument(Class<?> annotatedType, MuleContext muleContext) throws Exception;

    /**
     * This resolver scans a class for annotations in this package.  Note this behaviour can be changed by overloading
     * the {@link #findAnnotation(Class)} method and search based on your own criteria
     * @return the package of the annotation(s) to scan for
     */
    protected abstract String getAnnotationsPackageName();
}