Package org.dmd.util.parsing

Source Code of org.dmd.util.parsing.ConfigFinder

//  ---------------------------------------------------------------------------
//  dark-matter-data
//  Copyright (c) 2010 dark-matter-data committers
//  ---------------------------------------------------------------------------
//  This program 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 3 of the License, or (at your
//  option) any later version.
//  This program 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 this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
//  ---------------------------------------------------------------------------
package org.dmd.util.parsing;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.dmd.util.exceptions.ResultException;

/**
* The ConfigFinder utility recursively hunts through the source directories of the
* current set of Eclipse projects your have on your build path, as well as any JAR
* files that end with a specific suffix (e.g. *DMSchema.jar) and finds configuration
* files that end with a specific suffix e.g. .dms .dmg etc.
* <P>
* Add the suffixes you're looking for by calling addSuffix(). You must provide at
* least one suffix, or the findConfigs() method will fail.
* <P>
* The ConfigFinder also understands the convention of versioning your configuration
* files by storing them in subfolders named v<#>dot<#>. For instance, for a versioned
* schema you might have schema/v0dot1, schema/v1dot23, schema/v11dot3dot1 which would
* represent schemas at version 0.1, 1.23 and 11.3.1 respectively.
* <P>
* NOTE: as indicated, the finder assumes that you're working in an Eclipse environment
* where you have a directory structure like: project/bin project/src. The finder will
* see the project/bin on the java.class.path and then try to find the src directory in
* the same location.
* <P>
* If your development environment doesn't conform to this arrangement, you can derive
* your own class, or, manually specify the source directories to search by priming the
* ConfigFinder with calls to addSourceDirectory().
*/
public class ConfigFinder {

  // The source paths that we're going to search
  ArrayList<String>  sourceDirs;
 
  // The suffixes that we're going to check for
  ArrayList<String>  suffixes;
 
  ArrayList<String>  jarPrefixes;
 
  // The individual configs that we've found
  ArrayList<ConfigLocation>  configs;
 
  // These are the class paths we searched
  ArrayList<String>  classPaths;
 
  // The configs grouped into versions
  TreeMap<String,ConfigVersion>  versions;
 
  String fsep;
 
  // The preferences file we attempt to read
  String   prefName;
  boolean  prefsAvailable;
 
  // The length of the longest schema name we found
  int  longest;
 
  boolean  debug;
 
  public ConfigFinder(){
    init();
    loadPreferences();
  }
 
  /**
   * Constructs a new ConfigFinder that will search the specified folders for
   * configurations.
   * @param srcdirs source directories that have been specified on the commandline.
   */
  public ConfigFinder(Iterator<String> srcdirs){
    init();
    while(srcdirs.hasNext()){
      sourceDirs.add(srcdirs.next());
    }
    prefsAvailable = true;
  }
 
  public void debug(boolean db){
    debug = db;
  }
 
  void debugMessage(String message){
    if (debug)
      System.out.println(message);
  }
 
  void init(){
    debugMessage("ConfigFinder.initializing()");
   
    sourceDirs     = new ArrayList<String>();
    suffixes     = new ArrayList<String>();
    jarPrefixes    = new ArrayList<String>();
    jarPrefixes.add("dark-matter-data");
    configs      = new ArrayList<ConfigLocation>();
    versions    = new TreeMap<String, ConfigVersion>();
    fsep       = File.separator;
    prefsAvailable   = false;
    classPaths     = new ArrayList<String>();
  }
 
  /**
   * @return The name of the file where additional source paths are indicated.
   */
  public String getPrefName(){
    return(prefName);
  }
 
  /**
   * Adds a suffix to hunt for. Generally of the form ".xxx".
   * @param s the suffix to hunt for.
   */
  public void addSuffix(String s){
    suffixes.add(s);
  }
 
  /**
   * Adds a jar prefix to hunt for. Any jar starting with the specified prefix will be
   * searched for configuration files.
   * @param e the JAR prefix to hunt for.
   */
  public void addJarPrefix(String e){
    jarPrefixes.add(e);
  }
 
  /**
   * Adds a source directory root to the set of paths that the finder will
   * traverse in search of schemas.
   * @param dir The source directory.
   */
  public void addSourceDirectory(String dir){
    sourceDirs.add(dir);
  }
 
  /**
   * Scans the class path (and an additional source directories) for files
   * ending with the suffixes you've specified.
   * @throws ResultException
   * @throws IOException 
   */
  public void findConfigs() throws ResultException, IOException {
    debugMessage("Finding configs:\n\n" + getSearchInfo() + "\n");
   
    if (suffixes.size() == 0){
      ResultException ex = new ResultException("You must specify at least one suffix to hunt for using the addSuffix() method");
      throw(ex);
    }
   
    for(String d : sourceDirs)
      findConfigsRecursive(new File(d));
   
    findConfigsOnClassPath();
   
    debugMessage("Config search complete: " + getSearchInfo() + "\n");   
  }
 
  /**
   * Returns the versions of the specified config. If the config is specified in
   * a file named stuff.xxx, the config name will be "stuff" (without the
   * .xxx file extension).
   * @param cn The config name.
   * @return The ConfigVersion for the specified configuration.
   */
  public ConfigVersion getConfig(String cn){
    return(versions.get(cn));
  }
 
  public TreeMap<String,ConfigVersion> getVersions(){
    return(versions);
  }
 
  /**
   * @return An iterator over all the configs we found.
   */
  public Iterator<ConfigLocation> getLocations(){
    return(configs.iterator());
  }
 
  /**
   * @return the length of the longest config name.
   */
  public int getLongestName(){
    return(longest);
  }
 
  /**
   * Returns a description of where we searched for your config files.
   * @return A string indicating the source paths and class paths searched as well as the
   * suffixes and JAR endings we used.
   */
  public String getSearchInfo(){
    StringBuffer sb = new StringBuffer();
   
    if (prefName == null)
      sb.append("Source directory preferences from -srcdir option:\n");
    else
      sb.append("Source directory preferences: " + prefName + "\n");
   
    if (prefsAvailable){
      for(String f : sourceDirs){
        sb.append("    " + f + "\n");
      }
    }
    else
      sb.append("No preferences specified");
    sb.append("\n");
   
    sb.append("Checked the following locations on your class path:\n");
   
    for(String c : classPaths){
      sb.append("    " + c + "\n");
    }
   
    sb.append("\n");
   
    if (jarPrefixes.size() > 0){
      sb.append("    Checked JARs with the following prefixs:\n");
      for(String j : jarPrefixes){
        sb.append("    " + j + "\n");
      }
      sb.append("\n");
    }
   
    sb.append("For config files with the following suffixs:\n");
    for(String s : suffixes){
      sb.append("    " + s + "\n");
    }
   
    return(sb.toString());
  }
 
  /**
   * This method will check to see if the user has created a sourcedirs.txt
   * in user_home/.darkmatter
   */
  void loadPreferences(){
   
    String userHome = System.getProperty("user.home");
    File darkMatterFolder = new File(userHome + fsep + ".darkmatter");
   
    debugMessage("loadPreferences() - " + userHome + fsep + ".darkmatter");
   
    // Create the preferences folder if it doesn't exist
    if (!darkMatterFolder.exists()){
      darkMatterFolder.mkdir();
    }
   
    prefName = userHome + fsep + ".darkmatter" + fsep + "sourcedirs.txt";
    File prefFile = new File(prefName);
   
    if (prefFile.exists()){
      prefsAvailable = true;
            try {
              LineNumberReader in = new LineNumberReader(new FileReader(prefName));
                String str;
                while ((str = in.readLine()) != null) {
                  String line = str.trim();
                 
                  if (line.startsWith("//"))
                    continue;
                 
//                  if (line.endsWith(".jar"))
//                    jarPrefixes.add(line);
//                  else
                    sourceDirs.add(line);
                }
               
        in.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
 
  /**
   * Recursively descends through the directory structure looking for files
   * that end with any of the suffixes that have been specified.
   * @param d The directory to search.
   * @throws ResultException
   * @throws IOException
   */
  void findConfigsRecursive(File dir) throws ResultException, IOException {
    if (dir.exists()){
      String[] files = dir.list();
     
      for(String f : files){
        for (String suffix : suffixes){
//          DebugInfo.debug("Checking suffix: " + suffix + " against " + f);         
          if (f.endsWith(suffix)){
            if (f.startsWith("meta"))
              continue;
           
            ConfigLocation newLocation = new ConfigLocation(f, dir.getCanonicalPath(), suffix);
           
            addConfig(newLocation);
           
            if (newLocation.getConfigName().length() > longest)
              longest = newLocation.getConfigName().length();
          }
          else{
            String fullname = dir.getAbsolutePath() + File.separator + f;
            File curr = new File(fullname);
            if (curr.isDirectory())
              findConfigsRecursive(curr);
          }
        }
      }
    }
    else{
      ResultException ex = new ResultException();
      ex.addError("Specified source directory doesn't exist: " + dir.getCanonicalPath());
      throw(ex);
    }
  }
 
  /**
   * Attempts to add the new location. If the version clashes with an existing version,
   * we pitch an exception.
   * @param cl The new location.
   * @throws ResultException
   */
  void addConfig(ConfigLocation cl) throws ResultException {
//    DebugInfo.debug("*** Adding config: " + cl.getConfigName());
   
    ConfigVersion cv = versions.get(cl.getConfigName());
   
    if (cv == null){
      cv = new ConfigVersion();
      versions.put(cl.getConfigName(), cv);
    }
    else{
      ConfigLocation existing = cv.getLatestVersion();
     
      if (!cl.getConfigParentDirectory().equals(existing.getConfigParentDirectory())){
        System.out.println("\nClashing config names: " + cl.configName);
        System.out.println("    " + existing.getConfigParentDirectory());
        System.out.println("    " + cl.getConfigParentDirectory() + "\n");
      }
    }
   
    cv.addVersion(cl);
   
    // Just add that puppy
//    DebugInfo.debug("Found config\n\n" + cl.toString());
    debugMessage("found config: " + cl.getConfigName());
    configs.add(cl);
  }
 
//  /**
//   * @return A listing of the schemas we've found.
//   */
//  public String getSchemaListing(){
//    StringBuffer sb = new StringBuffer();
//   
//    for(ConfigLocation dsl : configs.values()){
//      sb.append(dsl.getConfigName() + " -- " + dsl.getDirectory() + "\n");
//    }
//    return(sb.toString());
//  }
 
  /**
   * This method checks the current class path for /bin directories (that, in Eclipse,
   * give us a hint as to where the /src directories are) and JAR files whose names end
   * with a JAR ending you've specified. Such JARs are assumed to contain files with .xxx
   * file extensions. This mechanism allows you to easily import configs defined elsewhere,
   * in other projects you have open or exported in JARs from other sources.
   * @throws IOException 
   * @throws ResultException
   */
  void findConfigsOnClassPath() throws IOException, ResultException {
   
//    String[] paths = System.getProperty("java.class.path").split(";");
    String[] paths = System.getProperty("java.class.path").split(File.pathSeparator);
   
    debugMessage("findConfigsOnClassPath()");
    for(String f : paths){
     
      debugMessage("    checking: " + f);
      if ((jarPrefixes.size() > 0) && f.endsWith(".jar")){
        debugMessage("\n    we have a jar - adding to classPaths");
        classPaths.add(f);
       
        for(String jarPrefix : jarPrefixes){
          debugMessage("    checking against prefix: " + jarPrefix);
          String jarName = "";
         
          int lastSlash = f.lastIndexOf(File.separator);
          if (lastSlash != -1)
            jarName = f.substring(lastSlash+1);
          debugMessage("    jar name: " + jarName);
         
          if (jarName.startsWith(jarPrefix)){
            debugMessage("findConfigsOnClassPath() - jar starts with prefix " + f);
            // We have a JAR of interest - an example might look like:
            // file:F:\AASoftDev\workspace\dark-matter-data\extjars\exampleDMSchema.jar
            JarFile jar = new JarFile(f);         
                for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements();)
                {
                    String jarEntry = ((JarEntry)entries.nextElement()).getName();
                   
                    for(String suffix : suffixes){
                      if (jarEntry.endsWith(suffix)){
                        // The jarEntry might appear as follows: /com/example/schema/example.dms
                        // AND NOTE THAT THE FILE SEPERATORS ARE FORWARD SLASHES, NOT SYSTEM DEPENDENT!!!
                        lastSlash = jarEntry.lastIndexOf("/");
                        String schemaName = jarEntry.substring(lastSlash+1);
                        String path = jarEntry.substring(0,lastSlash);
                       
                  debugMessage("    jarEntry ends with suffix " + jarEntry);
//                  DebugInfo.debug(f);
//                        DebugInfo.debug(jarEntry);

                        ConfigLocation newLocation = new ConfigLocation(f, schemaName, path, suffix);
                 
                  addConfig(newLocation);
                 
                  if (newLocation.getConfigName().length() > longest)
                    longest = newLocation.getConfigName().length();
                      }
                    }
                }
          }
        }
      }
      else if (f.endsWith(File.separator + "bin")){
        // NOTE: we no longer add this stuff because we're generally going to run as a tool out of a jar
        // and need to be explicitly told where to look for config files. Leaving this stuff in could
        // cause problems with clashing configs.
       
//        // We may have a project's bin directory here, which would mean that
//        // the src should be in a parallel directory
//        int lastSlash = f.lastIndexOf(File.separatorChar);
//        String prefix = f.substring(0,lastSlash);
//       
//        File src = new File(prefix + File.separator + "src");
//       
//        if (src.exists()){
//          findConfigsRecursive(src);
//        }
      }
     
    }
   
  }
}
TOP

Related Classes of org.dmd.util.parsing.ConfigFinder

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.