All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avaje.ebeaninternal.server.util.ClassPathSearch Maven / Gradle / Ivy

/**
 * Copyright (C) 2006  Robin Bygrave
 * 
 * This file is part of Ebean.
 * 
 * Ebean is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *  
 * Ebean is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Ebean; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA  
 */
package com.avaje.ebeaninternal.server.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebeaninternal.api.ClassUtil;

/**
 * Can search the class path for classes using a ClassPathSearchMatcher. A
 * ClassPathSearch should only be used once in a single threaded manor. It is
 * not safe for multithreaded use.
 * 

* For example, used to find all the Entity beans and ScalarTypes for Ebean. *

*/ public class ClassPathSearch { private static final Logger logger = Logger.getLogger(ClassPathSearch.class.getName()); ClassLoader classLoader; Object[] classPaths; ClassPathSearchFilter filter; ClassPathSearchMatcher matcher; ArrayList> matchList = new ArrayList>(); HashSet jarHits = new HashSet(); HashSet packageHits = new HashSet(); ClassPathReader classPathReader = new DefaultClassPathReader(); public ClassPathSearch(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher) { this.classLoader = classLoader; this.filter = filter; this.matcher = matcher; initClassPaths(); } private void initClassPaths() { try { String cn = GlobalProperties.get("ebean.classpathreader", null); if (cn != null){ // use a user defined classPathReader logger.info("Using ["+cn+"] to read the searchable class path"); classPathReader = (ClassPathReader)ClassUtil.newInstance(cn, this.getClass()); } classPaths = classPathReader.readPath(classLoader); if (classPaths == null || classPaths.length == 0){ String msg = "ClassPath is EMPTY using ClassPathReader ["+classPathReader+"]"; logger.warning(msg); } boolean debug = GlobalProperties.getBoolean("ebean.debug.classpath", false); if (debug || logger.isLoggable(Level.FINER)) { String msg = "Classpath " + Arrays.toString(classPaths); logger.info(msg); } } catch (Exception e) { String msg = "Error trying to read the classpath entries"; throw new RuntimeException(msg, e); } } /** * Return the set of jars that contained classes that matched. */ public Set getJarHits() { return jarHits; } /** * Return the set of packages that contained classes that matched. */ public Set getPackageHits() { return packageHits; } /** * Register where matching classes where found. *

* Could use this info to speed up future searches. *

*/ private void registerHit(String jarFileName, Class cls) { if (jarFileName != null) { jarHits.add(jarFileName); } Package pkg = cls.getPackage(); if (pkg != null){ packageHits.add(pkg.getName()); } else { packageHits.add(""); } } /** * Searches the class path for all matching classes. */ public List> findClasses() throws ClassNotFoundException { if (classPaths == null || classPaths.length == 0){ // returning an empty list return matchList; } String charsetName = Charset.defaultCharset().name(); for (int h = 0; h < classPaths.length; h++) { String jarFileName = null; Enumeration files = null; JarFile module = null; // for each class path ... File classPath; if (URL.class.isInstance(classPaths[h])){ classPath = new File(((URL)classPaths[h]).getFile()); } else { classPath = new File(classPaths[h].toString()); } try { // URL Decode the path replacing %20 to space characters. String path = URLDecoder.decode(classPath.getAbsolutePath(), charsetName); classPath = new File(path); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } if (classPath.isDirectory()) { files = getDirectoryEnumeration(classPath); } else if (classPath.getName().endsWith(".jar")) { jarFileName = classPath.getName(); if (!filter.isSearchJar(jarFileName)) { // skip any jars not list in the filter continue; } try { // our resource is a jar module = new JarFile(classPath); files = module.entries(); } catch (MalformedURLException ex) { throw new ClassNotFoundException("Bad classpath. Error: ", ex); } catch (IOException ex) { String msg = "jar file '" + classPath.getAbsolutePath() + "' could not be instantiate from file path. Error: "; throw new ClassNotFoundException(msg, ex); } } else { // this is not expected String msg = "Error: expected classPath entry ["+classPath.getAbsolutePath() +"] to be a directory or a .jar file but it is not either of those?"; logger.log(Level.SEVERE, msg); } searchFiles(files, jarFileName); if (module != null) { try { // close the jar if it was used module.close(); } catch (IOException e) { String msg = "Error closing jar"; throw new ClassNotFoundException(msg, e); } } } if (matchList.isEmpty()){ String msg = "No Entities found in ClassPath using ClassPathReader [" +classPathReader+"] Classpath Searched[" + Arrays.toString(classPaths)+"]"; logger.warning(msg); } return matchList; } private Enumeration getDirectoryEnumeration(File classPath) { // list of file names (latter checked as Classes) ArrayList fileNameList = new ArrayList(); Set includePkgs = filter.getIncludePackages(); if (includePkgs.size() > 0) { // just search the relevant directories based on the // list of included packages Iterator it = includePkgs.iterator(); while (it.hasNext()) { String pkg = it.next(); String relPath = pkg.replace('.', '/'); File dir = new File(classPath, relPath); if (dir.exists()) { recursivelyListDir(fileNameList, dir, new StringBuilder(relPath)); } } } else { // get a recursive listing of this classpath recursivelyListDir(fileNameList, classPath, new StringBuilder()); } return Collections.enumeration(fileNameList); } private void searchFiles(Enumeration files, String jarFileName) { while (files != null && files.hasMoreElements()) { String fileName = files.nextElement().toString(); // we only want the class files if (fileName.endsWith(".class")) { String className = fileName.replace('/', '.').substring(0, fileName.length() - 6); int lastPeriod = className.lastIndexOf("."); String pckgName; if (lastPeriod > 0){ pckgName = className.substring(0, lastPeriod); } else { pckgName = ""; } if (!filter.isSearchPackage(pckgName)) { continue; } // get the class for our class name Class theClass = null; try { theClass = Class.forName(className, false, classLoader); if (matcher.isMatch(theClass)) { matchList.add(theClass); registerHit(jarFileName, theClass); } } catch (ClassNotFoundException e) { // expected to get this hence finer logger.finer("Error searching classpath" + e.getMessage()); continue; } catch (NoClassDefFoundError e) { // expected to get this hence finer logger.finer("Error searching classpath: " + e.getMessage()); continue; } } } } private void recursivelyListDir(List fileNameList, File dir, StringBuilder relativePath) { int prevLen; if (dir.isDirectory()) { File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { // store our original relative path string length prevLen = relativePath.length(); relativePath.append(prevLen == 0 ? "" : "/").append(files[i].getName()); recursivelyListDir(fileNameList, files[i], relativePath); // delete sub directory from our relative path relativePath.delete(prevLen, relativePath.length()); } } else { // add class fileName to the list fileNameList.add(relativePath.toString()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy