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