/** * */ package tml.vectorspace.operations; /** * @author Jorge * */ import java.io.*; import java.util.*; import java.util.jar.*; import java.util.regex.*; import org.apache.log4j.Logger; public class ClassDiscovery { private static Logger logger = Logger.getLogger(ClassDiscovery.class); static private String GetClassName_afterPackageAsPath( final String pFileName, final String pPkgAsPath) { final String CName = pFileName.substring(0, pFileName.length() - 6).replace('/', '.').replace('\\', '.'); final String CName_AfterPackageAsPath = CName.substring(pPkgAsPath.length()); return CName_AfterPackageAsPath; } static private String GetClassName_ofPackageAsPath( final String pFileName, final String pPkgAsPath) { final boolean aIsClass = pFileName.endsWith(".class"); if (!aIsClass) return null; final boolean aIsBelongToPackage = pFileName.startsWith(pPkgAsPath); if (!aIsBelongToPackage) return null; final String aClassName = ClassDiscovery.GetClassName_afterPackageAsPath(pFileName, pPkgAsPath); return aClassName; } static private File GetPackageFile( final String pPkgName, final File pPkgPath) { final String aPkgFileName = pPkgPath.getAbsoluteFile().toString() + '/' + pPkgName.replace('.', '/'); final File aPkgFile = new File(aPkgFileName); final boolean aIsExist = aPkgFile.exists(); final boolean aIsDirectory = aPkgFile.isDirectory(); final boolean aIsExist_asDirectory = aIsExist && aIsDirectory; if(!aIsExist_asDirectory) return null; return aPkgFile; } static private boolean Check_isJarFile(final File pFile) { final boolean aIsJarFile = pFile.toString().endsWith(".jar"); return aIsJarFile; } static private ArrayList<String> DiscoverClassNames_fromJarFile(final PkgInfo pPkgInfo) { final ArrayList<String> aClassNames = new ArrayList<String>(); try { final JarFile JF = new JarFile(pPkgInfo.PkgPath); final Enumeration<JarEntry> JEs = JF.entries(); while (JEs.hasMoreElements()) { final JarEntry aJE = JEs.nextElement(); final String aJEName = aJE.getName(); final String aSimpleName = GetClassName_ofPackageAsPath(aJEName, pPkgInfo.PkgAsPath); if (aSimpleName == null) continue; final String aClassName = pPkgInfo.PkgName + '.' + aSimpleName; aClassNames.add(aClassName); } JF.close(); } catch (IOException e) {} return aClassNames; } static private void DiscoverClassNames_fromDirectory( final String pAbsolutePackagePath, final String pPackageName, final File pPackageFolder, final ArrayList<String> pClassNames) { final File[] aFiles = pPackageFolder.listFiles(); for(File aFile : aFiles) { if (aFile.isDirectory()) { DiscoverClassNames_fromDirectory(pAbsolutePackagePath, pPackageName, aFile, pClassNames); continue; } final String aFileName = aFile.getAbsolutePath().substring(pAbsolutePackagePath.length() + 1); final boolean aIsClassFile = aFileName.endsWith(".class"); if (!aIsClassFile) continue; final String aSimpleName = aFileName.substring(0, aFileName.length() - 6).replace('/', '.').replace('\\', '.'); final String aClassName = pPackageName + '.' + aSimpleName; pClassNames.add(aClassName); } } static private ArrayList<String> DiscoverClassNames_fromDirectory(PkgInfo pPkgInfo) { final ArrayList<String> aClassNames = new ArrayList<String>(); final File aPkgFile = ClassDiscovery.GetPackageFile(pPkgInfo.PkgName, pPkgInfo.PkgPath); if (aPkgFile == null) return aClassNames; DiscoverClassNames_fromDirectory(aPkgFile.getAbsolutePath(), pPkgInfo.PkgName, aPkgFile, aClassNames); return aClassNames; } static public class PkgInfo { PkgInfo( final File pPkgPath, final String pPkgName, final String pPkgAsPath) { this.PkgPath = pPkgPath; this.PkgName = pPkgName; this.PkgAsPath = pPkgAsPath; } final File PkgPath; final String PkgName; final String PkgAsPath; } static public PkgInfo GetPackageInfoOf(Class<?> pClass) { File aPkgPath = null; String aPkgName = null; String aPkgAsPath = null; try { aPkgPath = new File(pClass.getProtectionDomain().getCodeSource().getLocation().toURI()); aPkgName = pClass.getPackage().getName(); aPkgAsPath = aPkgName.replace('.', '/') + '/'; } catch (Throwable e) { } if (aPkgPath == null) return null; final PkgInfo aPkgInfo = new PkgInfo(aPkgPath, aPkgName, aPkgAsPath); return aPkgInfo; } static public ArrayList<String> DiscoverClassNames_inPackage(final PkgInfo pPkgInfo) { if (pPkgInfo == null) return null; ArrayList<String> aClassNames = new ArrayList<String>(); if (pPkgInfo.PkgPath.isDirectory()) { aClassNames = ClassDiscovery.DiscoverClassNames_fromDirectory(pPkgInfo); } else if(pPkgInfo.PkgPath.isFile()) { boolean aIsJarFile = ClassDiscovery.Check_isJarFile(pPkgInfo.PkgPath); if (!aIsJarFile) return null; aClassNames = ClassDiscovery.DiscoverClassNames_fromJarFile(pPkgInfo); } return aClassNames; } /** * Returns an array of class in the same package as the the SeedClass * * @param pFilterName - Regular expression to match the desired classes' name (nullif no filtering needed) * @param pFilterClass - The super class of the desired classes (null if no filtering needed) * * @return - The array of matched classes, null if there is a problem. * * @author The rest - Nawaman http://nawaman.net * @author Package as Dir - Jon Peck http://jonpeck.com * (adapted from http://www.javaworld.com/javaworld/javatips/jw-javatip113.html) */ @SuppressWarnings("unchecked") static <T> Class<? extends T>[] DiscoverClasses( final Class<?> pSeedClass, final String pFilterName, final Class<T> pFilterClass) { final Pattern aClsNamePattern = (pFilterName == null) ? null : Pattern.compile(pFilterName); PkgInfo aPkgInfo = null; try { aPkgInfo = GetPackageInfoOf(pSeedClass); } catch (Throwable e) {} if (aPkgInfo == null) return null; final ArrayList<String> aClassNames = DiscoverClassNames_inPackage(aPkgInfo); if (aClassNames == null) return null; if (aClassNames.size() == 0) return null; final ArrayList<Class<?>> aClasses = new ArrayList<Class<?>>(); for(final String aClassName : aClassNames) { if ((aClsNamePattern != null) && !aClsNamePattern.matcher(aClassName).matches()) continue; // Get the class and filter it Class<?> aClass = null; try { aClass = Class.forName(aClassName); } catch (ClassNotFoundException e) { continue; } catch (NoClassDefFoundError e) { continue; } if((pFilterClass != null) && !pFilterClass.isAssignableFrom(aClass)) continue; if (pFilterClass != null) { if (!pFilterClass.isAssignableFrom(aClass)) continue; aClasses.add(aClass.asSubclass(pFilterClass)); } else { aClasses.add(aClass); } } // Collections.sort(aClasses, ClassComparator.Default); Class<? extends T>[] aClassesArray = aClasses.toArray((Class<? extends T>[]) (new Class[aClasses.size()])); return aClassesArray; } static public List<Operation<?>> availableOperations() { Class<?> aSeedClass = ClassDiscovery.class; final Class<?>[] aClasses = DiscoverClasses( aSeedClass, "^.*operations\\.\\w+$", AbstractOperation.class); List<Operation<?>> operations = new ArrayList<Operation<?>>(); for(Class<?> aClass : aClasses) { if(aClass.getName().contains("Abstract")) continue; Operation<?> op; try { op = (Operation<?>) aClass.newInstance(); operations.add(op); } catch (Exception e) { e.printStackTrace(); logger.error("Ignoring operation " + aClass + " " + e.getMessage()); } } return operations; } }