Package org.hibernate.ejb.packaging

Source Code of org.hibernate.ejb.packaging.AbstractJarVisitor

package org.hibernate.ejb.packaging;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Parse a JAR of any form (zip file, exploded directory, ...)
* apply a set of filters (File filter, Class filter, Package filter)
* and return the appropriate matching sets of elements
*
*
* @author Emmanuel Bernard
*/
//TODO shortcut when filters are null or empty
public abstract class AbstractJarVisitor implements JarVisitor {
  private final Logger log = LoggerFactory.getLogger( AbstractJarVisitor.class );
  protected String unqualifiedJarName;
  protected URL jarUrl;
  protected boolean done = false;
  private List<Filter> filters = new ArrayList<Filter>();
  private Set<FileFilter> fileFilters = new HashSet<FileFilter>();
  private Set<JavaElementFilter> classFilters = new HashSet<JavaElementFilter>();
  private Set<JavaElementFilter> packageFilters = new HashSet<JavaElementFilter>();
  private Set[] entries;



  /**
   * Build a jar visitor from its jar string path
   */
  private AbstractJarVisitor(String jarPath) {
    URL jarUrl;
    try {
      //is it an url
      jarUrl = new URL( jarPath );
    }
    catch (MalformedURLException e) {
      try {
        //consider it as a file path
        jarUrl = new URL( "file:" + jarPath );
      }
      catch (MalformedURLException ee) {
        throw new IllegalArgumentException( "Unable to find jar:" + jarPath, ee );
      }
    }
    this.jarUrl = jarUrl;
    unqualify();
  }

  protected AbstractJarVisitor(String fileName, Filter[] filters) {
    this( fileName );
    initFilters( filters );
  }

  private void initFilters(Filter[] filters) {
    for ( Filter filter : filters ) {
      if ( filter instanceof FileFilter ) {
        fileFilters.add( (FileFilter) filter );
      }
      else if ( filter instanceof ClassFilter ) {
        classFilters.add( (ClassFilter) filter );
      }
      else if ( filter instanceof PackageFilter ) {
        packageFilters.add( (PackageFilter) filter );
      }
      else {
        throw new AssertionError( "Unknown filter type: " + filter.getClass().getName() );
      }
      this.filters.add( filter );
    }
    int size = this.filters.size();
    this.entries = new Set[ size ];
    for ( int index = 0; index < size ; index++ ) {
      this.entries[index] = new HashSet<Entry>();
    }
  }

  protected AbstractJarVisitor(URL url, Filter[] filters) {
    this( url );
    initFilters( filters );
  }

  private AbstractJarVisitor(URL url) {
    jarUrl = url;
    unqualify();
  }

  protected void unqualify() {
    //FIXME weak algorithm subject to AOOBE
    String fileName = jarUrl.getFile();
    int exclamation = fileName.lastIndexOf( "!" );
    if (exclamation != -1) fileName = fileName.substring( 0, exclamation );
    int slash = fileName.lastIndexOf( "/" );
    if ( slash != -1 ) {
      fileName = fileName.substring(
          fileName.lastIndexOf( "/" ) + 1,
          fileName.length()
      );
    }
    if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
      fileName = fileName.substring( 0, fileName.length() - 4 );
    }
    unqualifiedJarName = fileName;
    log.debug( "Searching mapped entities in jar/par: {}", jarUrl );
  }

  /**
   * Get the unqualified Jar name (ie wo path and wo extension)
   */
  public String getUnqualifiedJarName() {
    return unqualifiedJarName;
  }

  public Filter[] getFilters() {
    return filters.toArray( new Filter[ filters.size() ] );
  }

  /**
   * Return the matching entries for each filter in the same order the filter where passed
   *
   * @return array of Set of JarVisitor.Entry
   * @throws IOException if something went wrong
   */
  public Set[] getMatchingEntries() throws IOException {
    if ( !done ) {
      //avoid url access and so on
      if ( filters.size() > 0 ) doProcessElements();
      done = true;
    }
    return entries;
  }

  protected abstract void doProcessElements() throws IOException;

  //TODO avoid 2 input stream when not needed
  protected final void addElement(String entryName, InputStream is, InputStream secondIs) throws IOException {
    int entryNameLength = entryName.length();
    if ( entryName.endsWith( "package-info.class" ) ) {
      String name;
      if ( entryNameLength == "package-info.class".length() ) {
        name = "";
      }
      else {
        name = entryName.substring( 0, entryNameLength - ".package-info.class".length() ).replace( '/', '.' );
      }
      executeJavaElementFilter( name, packageFilters, is, secondIs );
    }
    else if ( entryName.endsWith( ".class" ) ) {
      String name = entryName.substring( 0, entryNameLength - ".class".length() ).replace( '/', '.' );
      log.debug( "Filtering: {}", name );
      executeJavaElementFilter( name, classFilters, is, secondIs );
    }
    else {
      String name = entryName;
      boolean accepted = false;
      for ( FileFilter filter : fileFilters ) {
        if ( filter.accept( name ) ) {
          accepted = true;
          InputStream localIs;
          if ( filter.getStream() ) {
            localIs = secondIs;
          }
          else {
            localIs = null;
            secondIs.close();
          }
          is.close();
          log.debug( "File Filter matched for {}", name );
          Entry entry = new Entry( name, localIs );
          int index = this.filters.indexOf( filter );
          this.entries[index].add( entry );
        }
      }
      if (!accepted) {
        //not accepted free resources
        is.close();
        secondIs.close();
      }
    }
  }

  private void executeJavaElementFilter(
      String name, Set<JavaElementFilter> filters, InputStream is, InputStream secondIs
  ) throws IOException {
    boolean accepted = false;
    for ( JavaElementFilter filter : filters ) {
      if ( filter.accept( name ) ) {
        //FIXME cannot currently have a class filtered twice but matching once
        // need to copy the is
        boolean match = checkAnnotationMatching( is, filter );
        if ( match ) {
          accepted = true;
          InputStream localIs;
          if ( filter.getStream() ) {
            localIs = secondIs;
          }
          else {
            localIs = null;
            secondIs.close();
          }
          log.debug( "Java element filter matched for {}", name );
          Entry entry = new Entry( name, localIs );
          int index = this.filters.indexOf( filter );
          this.entries[index].add( entry );
          break; //we matched
        }
      }
    }
    if (!accepted) {
      is.close();
      secondIs.close();
    }
  }

  private boolean checkAnnotationMatching(InputStream is, JavaElementFilter filter) throws IOException {
    if ( filter.getAnnotations().length == 0 ) {
      is.close();
      return true;
    }
    DataInputStream dstream = new DataInputStream( is );
    ClassFile cf = null;

    try {
      cf = new ClassFile( dstream );
    }
    finally {
      dstream.close();
      is.close();
    }
    boolean match = false;
    AnnotationsAttribute visible = (AnnotationsAttribute) cf.getAttribute( AnnotationsAttribute.visibleTag );
    if ( visible != null ) {
      for ( Class annotation : filter.getAnnotations() ) {
        match = visible.getAnnotation( annotation.getName() ) != null;
        if ( match ) break;
      }
    }
    return match;
  }
}
TOP

Related Classes of org.hibernate.ejb.packaging.AbstractJarVisitor

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.