Coverage Report - org.apache.giraph.utils.AnnotationUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
AnnotationUtils
0%
0/25
0%
0/6
2.688
AnnotationUtils$GeneralClassesIterator
0%
0/22
0%
0/6
2.688
AnnotationUtils$JarClassesIterator
0%
0/33
0%
0/14
2.688
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with 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  
 
 19  
 package org.apache.giraph.utils;
 20  
 
 21  
 import java.io.FileInputStream;
 22  
 import java.io.IOException;
 23  
 import java.lang.annotation.Annotation;
 24  
 import java.io.File;
 25  
 import java.util.ArrayList;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.NoSuchElementException;
 29  
 import java.util.jar.JarEntry;
 30  
 import java.util.jar.JarInputStream;
 31  
 
 32  
 /**
 33  
  * Helper class to deal with annotations in runtime.
 34  
  */
 35  0
 public class AnnotationUtils {
 36  
   /** Do not instantiate. */
 37  0
   private AnnotationUtils() {
 38  0
   }
 39  
 
 40  
   /**
 41  
    * Finds all classes within a package which are annotated with certain
 42  
    * annotation.
 43  
    *
 44  
    * @param annotation  Annotation which we are looking for
 45  
    * @param <T>         Annotation class
 46  
    * @param packageName Package in which to search
 47  
    * @return The list of annotated classes
 48  
    */
 49  
   public static <T extends Annotation> List<Class<?>> getAnnotatedClasses(
 50  
       Class<T> annotation, String packageName) {
 51  0
     ArrayList<Class<?>> ret = new ArrayList<Class<?>>();
 52  0
     for (Iterator<Class<?>> it = getClassesIterator(packageName);
 53  0
          it.hasNext();) {
 54  0
       Class<?> clazz = it.next();
 55  0
       if (clazz.getAnnotation(annotation) != null) {
 56  0
         ret.add(clazz);
 57  
       }
 58  0
     }
 59  0
     return ret;
 60  
   }
 61  
 
 62  
   /**
 63  
    * @param packageName Package through which to iterate
 64  
    * @return Iterator through the classes of this jar file (if executed from
 65  
    *         jar) or through the classes of org package (if .class file is
 66  
    *         executed)
 67  
    */
 68  
   public static Iterator<Class<?>> getClassesIterator(String packageName) {
 69  0
     if (isExecutedFromJar()) {
 70  
       try {
 71  0
         return new JarClassesIterator(packageName);
 72  0
       } catch (IOException e) {
 73  0
         throw new RuntimeException(e);
 74  
       }
 75  
     } else {
 76  0
       return new GeneralClassesIterator(packageName);
 77  
     }
 78  
   }
 79  
 
 80  
   /**
 81  
    * @return Whether or not the code is executed from jar file
 82  
    */
 83  
   private static boolean isExecutedFromJar() {
 84  0
     return AnnotationUtils.class.getResource("AnnotationUtils.class")
 85  0
         .getProtocol().equals("jar");
 86  
   }
 87  
 
 88  
   /**
 89  
    * To be used when {@link #isExecutedFromJar()}  is true.
 90  
    *
 91  
    * @return If executed from jar file returns the path to the jar
 92  
    *         (otherwise it will return the folder in which this .class file is
 93  
    *         located)
 94  
    */
 95  
   private static String getCurrentJar() {
 96  0
     return AnnotationUtils.class.getProtectionDomain().getCodeSource()
 97  0
         .getLocation().getFile();
 98  
   }
 99  
 
 100  
   /**
 101  
    * To be used when {@link #isExecutedFromJar()}  is true.
 102  
    * <p/>
 103  
    * Iterator through classes of this jar file.
 104  
    */
 105  0
   private static class JarClassesIterator implements Iterator<Class<?>> {
 106  
     /** Used to go through classes in current jar */
 107  
     private final JarInputStream jarIn;
 108  
     /** Are we positioned on the next class entry */
 109  
     private boolean entryLoaded;
 110  
     /** Next class entry */
 111  
     private JarEntry currentEntry;
 112  
     /** Folder in which to look */
 113  
     private final String path;
 114  
 
 115  
     /**
 116  
      * @param packageName Package through which to iterate
 117  
      * @throws IOException
 118  
      */
 119  0
     public JarClassesIterator(String packageName) throws IOException {
 120  0
       jarIn = new JarInputStream(new FileInputStream(new File(
 121  0
           getCurrentJar())));
 122  0
       entryLoaded = false;
 123  0
       currentEntry = null;
 124  0
       path = packageName.replace(".", File.separator);
 125  0
     }
 126  
 
 127  
     @Override
 128  
     public boolean hasNext() {
 129  0
       loadNextEntry();
 130  0
       return currentEntry != null;
 131  
     }
 132  
 
 133  
     @Override
 134  
     public Class<?> next() {
 135  0
       loadNextEntry();
 136  0
       if (currentEntry == null) {
 137  0
         throw new NoSuchElementException();
 138  
       }
 139  0
       entryLoaded = false;
 140  
 
 141  0
       String className = currentEntry.getName().replace(".class",
 142  0
           "").replace(File.separator, ".");
 143  0
       return loadClass(className);
 144  
     }
 145  
 
 146  
     /**
 147  
      * Sets position to next class entry
 148  
      */
 149  
     private void loadNextEntry() {
 150  0
       while (!entryLoaded) {
 151  
         try {
 152  0
           currentEntry = jarIn.getNextJarEntry();
 153  0
           if (currentEntry == null || (currentEntry.getName().endsWith(
 154  0
               ".class") && (currentEntry.getName().startsWith(path)))) {
 155  0
             entryLoaded = true;
 156  
           } else {
 157  0
             currentEntry = null;
 158  
           }
 159  0
         } catch (IOException e) {
 160  0
           throw new RuntimeException(e);
 161  0
         }
 162  
       }
 163  0
       if (currentEntry == null) {
 164  
         try {
 165  0
           jarIn.close();
 166  0
         } catch (IOException e) {
 167  0
           throw new RuntimeException(e);
 168  0
         }
 169  
       }
 170  0
     }
 171  
 
 172  
     @Override
 173  
     public void remove() {
 174  0
       throw new UnsupportedOperationException(
 175  
           "Can't remove from classes iterator");
 176  
     }
 177  
   }
 178  
 
 179  
   /**
 180  
    * To be used when {@link #isExecutedFromJar()}  is false.
 181  
    * <p/>
 182  
    * Iterator through classes of some package.
 183  
    */
 184  0
   private static class GeneralClassesIterator implements Iterator<Class<?>> {
 185  
     /** From which position in path the package name starts */
 186  
     private final int stringPosition;
 187  
     /** Recursive directory iterator */
 188  
     private final Iterator<File> iterator;
 189  
 
 190  
     /**
 191  
      * @param packageName Package through which to iterate
 192  
      */
 193  0
     public GeneralClassesIterator(String packageName) {
 194  0
       String mainPath = AnnotationUtils.class.getProtectionDomain()
 195  0
           .getCodeSource().getLocation().getFile();
 196  0
       String subPath = packageName.replace(".", File.separator);
 197  0
       File directory = new File(mainPath + subPath);
 198  0
       stringPosition = directory.getPath().length() - packageName.length();
 199  0
       List<File> files = new ArrayList<File>();
 200  0
       addAllClassFiles(directory, files);
 201  0
       iterator = files.iterator();
 202  0
     }
 203  
 
 204  
     /**
 205  
      * Recursively add all .class files from the directory to the list.
 206  
      *
 207  
      * @param directory Directory from which we are adding files
 208  
      * @param files List we add files to
 209  
      */
 210  
     @edu.umd.cs.findbugs.annotations.SuppressWarnings(
 211  
     "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
 212  
     private void addAllClassFiles(File directory, List<File> files) {
 213  0
       for (File file : directory.listFiles()) {
 214  0
         if (file.isDirectory()) {
 215  0
           addAllClassFiles(file, files);
 216  0
         } else if (file.getName().endsWith(".class")) {
 217  0
           files.add(file);
 218  
         }
 219  
       }
 220  0
     }
 221  
 
 222  
     @Override
 223  
     public boolean hasNext() {
 224  0
       return iterator.hasNext();
 225  
     }
 226  
 
 227  
     @Override
 228  
     public Class<?> next() {
 229  0
       String className = iterator.next().getPath().substring(stringPosition)
 230  0
           .replace(".class", "").replace(File.separator, ".");
 231  0
       return loadClass(className);
 232  
     }
 233  
 
 234  
     @Override
 235  
     public void remove() {
 236  0
       throw new UnsupportedOperationException(
 237  
           "Can't remove from classes iterator");
 238  
     }
 239  
   }
 240  
 
 241  
   /**
 242  
    * Loads the class with the specified name
 243  
    *
 244  
    * @param className Name of the class we are loading
 245  
    * @return Class with the specified name
 246  
    */
 247  
   private static Class<?> loadClass(String className) {
 248  
     try {
 249  0
       return Class.forName(className);
 250  0
     } catch (ClassNotFoundException e) {
 251  0
       throw new RuntimeException("Error loading class " + className, e);
 252  0
     } catch (NoClassDefFoundError e) {
 253  0
       throw new RuntimeException("Error loading class " + className, e);
 254  
     }
 255  
   }
 256  
 }