Coverage Report - org.mule.config.transformer.AbstractAnnotatedTransformerArgumentResolver
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractAnnotatedTransformerArgumentResolver
0%
0/38
0%
0/26
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.config.transformer;
 8  
 
 9  
 import org.mule.api.MuleContext;
 10  
 import org.mule.api.lifecycle.Disposable;
 11  
 import org.mule.api.transformer.DataType;
 12  
 import org.mule.transformer.types.CollectionDataType;
 13  
 import org.mule.util.annotation.AnnotationUtils;
 14  
 
 15  
 import java.io.IOException;
 16  
 import java.util.Set;
 17  
 import java.util.concurrent.CopyOnWriteArraySet;
 18  
 
 19  
 import org.apache.commons.logging.Log;
 20  
 import org.apache.commons.logging.LogFactory;
 21  
 
 22  
 /**
 23  
  * An abstract resolver that can be extend to resolve/create an object based on Annotated classes. These classes can be
 24  
  * scanned and used to create the context.  Typically this class will be used to create resolvers for binding frameworks
 25  
  * where the data type classes are annotated with binding information.
 26  
  */
 27  0
 public abstract class AbstractAnnotatedTransformerArgumentResolver implements TransformerArgumentResolver, Disposable
 28  
 {
 29  0
     public static final String[] ignoredPackages = {"java.", "javax.", "org.w3c.", "org.mule.transport.", "org.mule.module."};
 30  
 
 31  
     /**
 32  
      * logger used by this class
 33  
      */
 34  0
     protected transient final Log logger = LogFactory.getLog(getClass());
 35  
 
 36  
     //We cache the Json classes so we don't scan them each time a context is needed
 37  0
     private Set<Class> matchingClasses = new CopyOnWriteArraySet<Class>();
 38  
 
 39  
     //We also cache the classes that did not match so that we dont scan them again either
 40  0
     private Set<Class> nonMatchingClasses = new CopyOnWriteArraySet<Class>();
 41  
 
 42  
     public <T> T resolve(Class<T> type, DataType source, DataType result, MuleContext context) throws Exception
 43  
     {
 44  
         //Lets make sure this is the right resolver for the object type and that we haven't scanned these before
 45  
         //and determined they are not Json classes
 46  0
         if(!getArgumentClass().isAssignableFrom(type) || isNonMatching(source, result))
 47  
         {
 48  0
             return null;
 49  
         }
 50  
 
 51  0
         Class annotatedType = (result instanceof CollectionDataType ? ((CollectionDataType)result).getItemType() : result.getType());
 52  
 
 53  
         //Check the cache first
 54  0
         boolean isAnnotated = matchingClasses.contains(annotatedType);
 55  0
         if(!isAnnotated)
 56  
         {
 57  
             //then scan the class for annotations
 58  0
             isAnnotated = findAnnotation(annotatedType);
 59  
         }
 60  
 
 61  0
         if (!isAnnotated)
 62  
         {
 63  0
             annotatedType = source.getType();
 64  
             //Check the cache first
 65  0
             isAnnotated = matchingClasses.contains(annotatedType);
 66  0
             if(!isAnnotated)
 67  
             {
 68  
                 //then scan the class for annotations
 69  0
                 isAnnotated = AnnotationUtils.hasAnnotationWithPackage(getAnnotationsPackageName(), annotatedType);
 70  
             }
 71  
         }
 72  
 
 73  0
         Object argument = context.getRegistry().lookupObject(getArgumentClass());
 74  
 
 75  0
         if (!isAnnotated)
 76  
         {
 77  
             //We didn't find Json annotations anywhere, lets cache the classes so we don't need to scan again
 78  0
             nonMatchingClasses.add(source.getType());
 79  0
             nonMatchingClasses.add(result.getType());
 80  
 
 81  
             //Finally if there is an Object Mapper configured we should return it
 82  0
             return (T)argument;
 83  
         }
 84  
         else
 85  
         {
 86  0
             matchingClasses.add(annotatedType);
 87  
         }
 88  
 
 89  
 
 90  0
         if (argument == null)
 91  
         {
 92  0
             logger.info("No common Object of type '" + getArgumentClass() + "' configured, creating a local one for: " + source + ", " + result);
 93  0
             argument = createArgument(annotatedType, context);
 94  
         }
 95  0
         return (T)argument;
 96  
 
 97  
     }
 98  
 
 99  
     protected boolean findAnnotation(Class annotatedType) throws IOException
 100  
     {
 101  
         
 102  0
         if(annotatedType.getPackage()==null)
 103  
         {
 104  0
             return false;
 105  
         }
 106  
 
 107  0
         for (String ignoredPackage : ignoredPackages)
 108  
         {
 109  0
             if(annotatedType.getPackage().getName().startsWith(ignoredPackage))
 110  
             {
 111  0
                 return false;
 112  
             }
 113  
         }
 114  0
         return AnnotationUtils.hasAnnotationWithPackage(getAnnotationsPackageName(), annotatedType);
 115  
     }
 116  
 
 117  
     protected boolean isNonMatching(DataType source, DataType result)
 118  
     {
 119  0
         return nonMatchingClasses.contains(result.getType()) && nonMatchingClasses.contains(source.getType());
 120  
     }
 121  
 
 122  
     public void dispose()
 123  
     {
 124  0
         nonMatchingClasses.clear();
 125  0
         matchingClasses.clear();
 126  0
     }
 127  
 
 128  
     public Set<Class> getMatchingClasses()
 129  
     {
 130  0
         return matchingClasses;
 131  
     }
 132  
 
 133  
     public Set<Class> getNonMatchingClasses()
 134  
     {
 135  0
         return nonMatchingClasses;
 136  
     }
 137  
 
 138  
     /**
 139  
      * The object type that this resolver will discover or create
 140  
      * @return  The object type that this resolver will discover or create
 141  
      */
 142  
     protected abstract Class<?> getArgumentClass();
 143  
 
 144  
     /**
 145  
      * If the resolver cannot locate the required object of type {@link #getArgumentClass()} this method will be invoked
 146  
      * an instance of the object.
 147  
      *
 148  
      * @param annotatedType the annotated object that was matched
 149  
      * @param muleContext the current Mule context.
 150  
      * @return a new instance of the object being resolved.  This method may also retain a shared instance and possible add
 151  
      * configuration to the instance based on this invocation
 152  
      * @throws Exception if the object cannot be created
 153  
      */
 154  
     protected abstract Object createArgument(Class<?> annotatedType, MuleContext muleContext) throws Exception;
 155  
 
 156  
     /**
 157  
      * This resolver scans a class for annotations in this package.  Note this behaviour can be changed by overloading
 158  
      * the {@link #findAnnotation(Class)} method and search based on your own criteria
 159  
      * @return the package of the annotation(s) to scan for
 160  
      */
 161  
     protected abstract String getAnnotationsPackageName();
 162  
 }