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