Package com.impetus.annovention

Source Code of com.impetus.annovention.Discoverer

/*
* Copyright 2010 Impetus Infotech.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.impetus.annovention;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;

import com.impetus.annovention.listener.ClassAnnotationDiscoveryListener;
import com.impetus.annovention.listener.FieldAnnotationDiscoveryListener;
import com.impetus.annovention.listener.MethodAnnotationDiscoveryListener;
import com.impetus.annovention.resource.ClassFileIterator;
import com.impetus.annovention.resource.JarFileIterator;
import com.impetus.annovention.resource.ResourceIterator;

/**
* Base annotation discoverer.
*
* @author animesh.kumar
*/
public abstract class Discoverer {
   
    /** map to hold ClassAnnotation listeners */
    private final Map<String, Set<ClassAnnotationDiscoveryListener>> classAnnotationListeners =
      new HashMap<String, Set<ClassAnnotationDiscoveryListener>>();
   
    /** map to hold FieldAnnotation listeners */
    private final Map<String, Set<FieldAnnotationDiscoveryListener>> fieldAnnotationListeners =
      new HashMap<String, Set<FieldAnnotationDiscoveryListener>>();
   
    /** map to hold MethodAnnotation listeners */
    private final Map<String, Set<MethodAnnotationDiscoveryListener>> methodAnnotationListeners =
      new HashMap<String, Set<MethodAnnotationDiscoveryListener>>();
   
    /**
     * Instantiates a new Discoverer.
     */
    public Discoverer() {
    }

    /**
     * Adds ClassAnnotationDiscoveryListener
     *
     * @param listener
     */
    public final void addAnnotationListener (ClassAnnotationDiscoveryListener listener) {
      addAnnotationListener (classAnnotationListeners, listener, listener.supportedAnnotations());
    }
   
    /**
     * Adds FieldAnnotationDiscoveryListener
     *
     * @param listener
     */
    public final void addAnnotationListener (FieldAnnotationDiscoveryListener listener) {
      addAnnotationListener (fieldAnnotationListeners, listener, listener.supportedAnnotations());
    }

    /**
     * Adds MethodAnnotationDiscoveryListener
     *
     * @param listener
     */
    public final void addAnnotationListener (MethodAnnotationDiscoveryListener listener) {
      addAnnotationListener (methodAnnotationListeners, listener, listener.supportedAnnotations());
    }
   
    /**
     * Helper class to find supported annotations of a listener and register them
     *
     * @param <L>
     * @param map
     * @param listener
     * @param annotations
     */
    private <L> void addAnnotationListener (Map<String, Set<L>> map, L listener, String... annotations) {
      // throw exception if the listener doesn't support any annotations. what's the point of
      // registering then?
      if (null == annotations || annotations.length == 0) {
        throw new IllegalArgumentException(listener.getClass() + " has no supporting Annotations. Check method supportedAnnotations");
      }
     
    for (String annotation : annotations) {
      Set<L> listeners = map.get(annotation);
      if (null == listeners) {
        listeners = new HashSet<L>();
        map.put(annotation, listeners);
      }
      listeners.add(listener);
    }
    }
   
    /**
     * Gets the filter implementation.
     *
     * @return the filter
     */
    public abstract Filter getFilter();

  /**
   * Finds resources to scan for
   *
   * @return
   */
  public abstract URL[] findResources(ClassLoader cl);
 
 
    /**
     * that's my buddy! this is where all the discovery starts.
     * @param cl
     */
    public final void discover(ClassLoader cl) {
        URL[] resources = findResources(cl);
        for (URL resource : resources) {
            try {
                ResourceIterator itr = getResourceIterator(resource, getFilter());
               
                InputStream is = null;
                while ((is = itr.next()) != null) {
                  // make a data input stream
                  DataInputStream dstream = new DataInputStream(new BufferedInputStream(is));
                    try {
                      // get java-assist class file
                      ClassFile classFile = new ClassFile(dstream);
                     
                      // discover class-level annotations
                      discoverAndIntimateForClassAnnotations (classFile);
                      // discover field annotations
                      discoverAndIntimateForFieldAnnotations (classFile);
                      // discover method annotations
                      discoverAndIntimateForMethodAnnotations(classFile);
                    } finally {
                       dstream.close();
                         is.close();
                    }
                }
            } catch (IOException e) {
              throw new RuntimeException(e);
            }
        }
    }
   
    /**
     * Discovers Class Annotations
     *
     * @param classFile
     */
    private void discoverAndIntimateForClassAnnotations (ClassFile classFile) {
      Set<Annotation> annotations = new HashSet<Annotation>();
     
    AnnotationsAttribute visible   = (AnnotationsAttribute) classFile.getAttribute(AnnotationsAttribute.visibleTag);
    AnnotationsAttribute invisible   = (AnnotationsAttribute) classFile.getAttribute(AnnotationsAttribute.invisibleTag);

    if (visible != null) {
      annotations.addAll(Arrays.asList(visible.getAnnotations()));
    }
    if (invisible != null) {
      annotations.addAll(Arrays.asList(invisible.getAnnotations()));
    }
   
    // now tell listeners
    for (Annotation annotation : annotations) {
      Set<ClassAnnotationDiscoveryListener> listeners = classAnnotationListeners.get(annotation.getTypeName());
      if (null == listeners) {
        continue;
      }

      for (ClassAnnotationDiscoveryListener listener : listeners) {
        listener.discovered(classFile.getName(), annotation.getTypeName());
      }
    }
    }
   
    /**
     * Discovers Field Annotations
     *
     * @param classFile
     */
    private void discoverAndIntimateForFieldAnnotations (ClassFile classFile) {
    @SuppressWarnings("unchecked")
    List<FieldInfo> fields = classFile.getFields();
    if (fields == null) {
      return;
    }
   
    for (FieldInfo fieldInfo : fields) {
      Set<Annotation> annotations = new HashSet<Annotation>();
     
      AnnotationsAttribute visible = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
      AnnotationsAttribute invisible = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.invisibleTag);

      if (visible != null) {
        annotations.addAll(Arrays.asList(visible.getAnnotations()));
      }
      if (invisible != null) {
        annotations.addAll(Arrays.asList(invisible.getAnnotations()));
      }
     
      // now tell listeners
      for (Annotation annotation : annotations) {
        Set<FieldAnnotationDiscoveryListener> listeners = fieldAnnotationListeners.get(annotation.getTypeName());
        if (null == listeners) {
          continue;
        }
       
        for (FieldAnnotationDiscoveryListener listener : listeners) {
          listener.discovered(classFile.getName(), fieldInfo.getName(), annotation.getTypeName());
        }
      }
    }
    }
   
    /**
     * Discovers Method Annotations
     *
     * @param classFile
     */
    private void discoverAndIntimateForMethodAnnotations(ClassFile classFile) {
      @SuppressWarnings("unchecked")
    List<MethodInfo> methods = classFile.getMethods();
    if (methods == null) {
      return;
    }
   
    for (MethodInfo methodInfo : methods) {
      Set<Annotation> annotations = new HashSet<Annotation>();
     
      AnnotationsAttribute visible   = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
      AnnotationsAttribute invisible   = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.invisibleTag);
     
      if (visible != null) {
        annotations.addAll(Arrays.asList(visible.getAnnotations()));
      }
      if (invisible != null) {
        annotations.addAll(Arrays.asList(invisible.getAnnotations()));
      }
     
      // now tell listeners
      for (Annotation annotation : annotations) {
        Set<MethodAnnotationDiscoveryListener> listeners = methodAnnotationListeners.get(annotation.getTypeName());
        if (null == listeners) {
          continue;
        }
       
        for (MethodAnnotationDiscoveryListener listener : listeners) {
          listener.discovered(classFile.getName(), methodInfo.getName(), methodInfo.getDescriptor(), annotation.getTypeName());
        }
      }
    } 
  }


    /**
     * Gets the Resource iterator for URL with Filter.
     *
     * @param url
     * @param filter
     * @return
     * @throws IOException
     */
    private ResourceIterator getResourceIterator(URL resource, Filter filter) throws IOException {
      URL url = resource;
      String urlString = url.toString();
        if (urlString.endsWith("!/")) {
          //It must be a jar file since it has the !/
            urlString = urlString.substring(4);
            urlString = urlString.substring(0, urlString.length() - 2);
            url = new URL(urlString);
            return new JarFileIterator(url.openStream(), filter);
        } else if (url.getProtocol().equals("file")) {
          String path = url.getPath();
          String newPath = path.replace((CharSequence)"%2520", " ");
          File f = new File(newPath);
            if (f.isDirectory()) {
                return new ClassFileIterator(f, filter);
            } else {
              throw new RuntimeException("bug, how is this not a directory="+f.getAbsolutePath());
            }
        } else {
            throw new IOException("Unable to understand protocol: " + resource.getProtocol());
        }
    }
}
TOP

Related Classes of com.impetus.annovention.Discoverer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.