Coverage Report - org.apache.camel.impl.converter.AnnotationTypeConverterLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
AnnotationTypeConverterLoader
83% 
100% 
0
 
 1  
 /**
 2  
  *
 3  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 4  
  * contributor license agreements.  See the NOTICE file distributed with
 5  
  * this work for additional information regarding copyright ownership.
 6  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 7  
  * (the "License"); you may not use this file except in compliance with
 8  
  * the License.  You may obtain a copy of the License at
 9  
  *
 10  
  * http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 package org.apache.camel.impl.converter;
 19  
 
 20  
 import org.apache.camel.Converter;
 21  
 import org.apache.camel.impl.CachingInjector;
 22  
 import org.apache.camel.util.ResolverUtil;
 23  
 import org.apache.camel.util.ObjectHelper;
 24  
 import org.apache.commons.logging.Log;
 25  
 import org.apache.commons.logging.LogFactory;
 26  
 
 27  
 import java.io.BufferedReader;
 28  
 import java.io.IOException;
 29  
 import java.io.InputStreamReader;
 30  
 import java.lang.reflect.Method;
 31  
 import static java.lang.reflect.Modifier.*;
 32  
 import java.net.URL;
 33  
 import java.util.Enumeration;
 34  
 import java.util.HashSet;
 35  
 import java.util.Set;
 36  
 import java.util.StringTokenizer;
 37  
 
 38  
 /**
 39  
  * A class which will auto-discover converter objects and methods to pre-load
 40  
  * the registry of converters on startup
 41  
  *
 42  
  * @version $Revision: 546860 $
 43  
  */
 44  58
 public class AnnotationTypeConverterLoader implements TypeConverterLoader {
 45  
     public static final String META_INF_SERVICES = "META-INF/services/org/apache/camel/TypeConverter";
 46  1
     private static final transient Log log = LogFactory.getLog(AnnotationTypeConverterLoader.class);
 47  58
     private ResolverUtil resolver = new ResolverUtil();
 48  58
     private Set<Class> visitedClasses = new HashSet<Class>();
 49  
 
 50  
     public void load(TypeConverterRegistry registry) throws Exception {
 51  34
         String[] packageNames = findPackageNames();
 52  34
         resolver.findAnnotated(Converter.class, packageNames);
 53  34
         Set<Class> classes = resolver.getClasses();
 54  34
         for (Class type : classes) {
 55  170
             if (log.isDebugEnabled()) {
 56  0
                 log.debug("Loading converter class: " + ObjectHelper.name(type));
 57  
             }
 58  170
             loadConverterMethods(registry, type);
 59  170
         }
 60  34
     }
 61  
 
 62  
     /**
 63  
      * Finds the names of the packages to search for on the classpath looking for text files on the classpath
 64  
      * at the  @{link #META_INF_SERVICES} location
 65  
      *
 66  
      * @return a collection of packages to search for
 67  
      * @throws IOException
 68  
      */
 69  
     protected String[] findPackageNames() throws IOException {
 70  34
         Set<String> packages = new HashSet<String>();
 71  34
         findPackages(packages, Thread.currentThread().getContextClassLoader());
 72  34
         findPackages(packages, getClass().getClassLoader());
 73  34
         return packages.toArray(new String[packages.size()]);
 74  
     }
 75  
 
 76  
     protected void findPackages(Set<String> packages, ClassLoader classLoader) throws IOException {
 77  68
         Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES);
 78  136
         while (resources.hasMoreElements()) {
 79  68
             URL url = resources.nextElement();
 80  68
             if (url != null) {
 81  68
                 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
 82  
                 try {
 83  
                     while (true) {
 84  1292
                         String line = reader.readLine();
 85  1292
                         if (line == null) {
 86  68
                             break;
 87  
                         }
 88  1224
                         line = line.trim();
 89  1224
                         if (line.startsWith("#") || line.length() == 0) {
 90  68
                             continue;
 91  
                         }
 92  68
                         tokenize(packages, line);
 93  68
                     }
 94  
                 }
 95  
                 finally {
 96  0
                     try {
 97  68
                         reader.close();
 98  
                     }
 99  0
                     catch (IOException e) {
 100  0
                         log.warn("Caught exception closing stream: " + e, e);
 101  68
                     }
 102  0
                 }
 103  
             }
 104  68
         }
 105  68
     }
 106  
 
 107  
     /**
 108  
      * Tokenizes the line from the META-IN/services file using commas and ignoring whitespace between packages
 109  
      */
 110  
     protected void tokenize(Set<String> packages, String line) {
 111  68
         StringTokenizer iter = new StringTokenizer(line, ",");
 112  136
         while (iter.hasMoreTokens()) {
 113  68
             String name = iter.nextToken().trim();
 114  68
             if (name.length() > 0) {
 115  68
                 packages.add(name);
 116  
             }
 117  68
         }
 118  68
     }
 119  
 
 120  
     /**
 121  
      * Loads all of the converter methods for the given type
 122  
      */
 123  
     protected void loadConverterMethods(TypeConverterRegistry registry, Class type) {
 124  170
         if (visitedClasses.contains(type)) {
 125  0
             return;
 126  
         }
 127  170
         visitedClasses.add(type);
 128  170
         Method[] methods = type.getDeclaredMethods();
 129  170
         CachingInjector injector = null;
 130  
 
 131  2448
         for (Method method : methods) {
 132  2278
             Converter annotation = method.getAnnotation(Converter.class);
 133  2278
             if (annotation != null) {
 134  1904
                 Class<?>[] parameterTypes = method.getParameterTypes();
 135  1904
                 if (parameterTypes == null || parameterTypes.length != 1) {
 136  0
                     log.warn("Ignoring bad converter on type: " + type.getName()
 137  
                             + " method: " + method + " as a converter method should have one parameter");
 138  0
                 }
 139  
                 else {
 140  1904
                     int modifiers = method.getModifiers();
 141  1904
                     if (isAbstract(modifiers) || !isPublic(modifiers)) {
 142  0
                         log.warn("Ignoring bad converter on type: " + type.getName()
 143  
                                 + " method: " + method + " as a converter method is not a public and concrete method");
 144  0
                     }
 145  
                     else {
 146  1904
                         Class toType = method.getReturnType();
 147  1904
                         if (toType.equals(Void.class)) {
 148  0
                             log.warn("Ignoring bad converter on type: " + type.getName()
 149  
                                     + " method: " + method + " as a converter method returns a void method");
 150  0
                         }
 151  
                         else {
 152  1904
                             Class fromType = parameterTypes[0];
 153  1904
                             if (isStatic(modifiers)) {
 154  1020
                                 registry.addTypeConverter(toType, fromType, new StaticMethodTypeConverter(method));
 155  1020
                             }
 156  
                             else {
 157  884
                                 if (injector == null) {
 158  34
                                     injector = new CachingInjector(registry, type);
 159  
                                 }
 160  884
                                 registry.addTypeConverter(toType, fromType, new InstanceMethodTypeConverter(injector, method));
 161  
                             }
 162  
                         }
 163  
                     }
 164  
                 }
 165  
             }
 166  
         }
 167  170
         Class superclass = type.getSuperclass();
 168  170
         if (superclass != null && !superclass.equals(Object.class)) {
 169  0
             loadConverterMethods(registry, superclass);
 170  
         }
 171  170
     }
 172  
 }