DBVIEW
src/org/dbview/resources/SotfForeignKeyDetectorCatalog.java
00001 /*
00002         DbView - Graph Visualization
00003     Copyright (C) 2012  Denis BEURIVE
00004 
00005     This program is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 /**
00020  * @author Denis Beurive
00021  */
00022 
00023 package org.dbview.resources;
00024 
00025 import java.util.ArrayList;
00026 import java.util.Collections;
00027 import java.util.Enumeration;
00028 import java.util.Hashtable;
00029 import java.util.Iterator;
00030 import java.util.regex.Matcher;
00031 import java.util.regex.Pattern;
00032 import org.dbview.conf.Conf;
00033 import org.dbview.utils.JavaVm;
00034 
00035 
00036 /**
00037  * This class implements the catalogue of soft foreign key detectors.
00038  * @author Denis Beurive
00039  */
00040 public class SotfForeignKeyDetectorCatalog
00041 {
00042     /**
00043      * Name of the <i>property</i> that references the JAR file that contains the implementation of all soft foreign key detectors.
00044      * @remark This property is defined in the configuration file of the software.
00045      *         The software's configuration file is a "property file" (see file "resources.properties").
00046      */
00047     private static final String __FJ_RESOURCE_NAME = "sotfForeignKeyDetectors"; // __CONFPROP__
00048 
00049     /**
00050      * This hash table lists all available soft foreign key detectors.
00051      * <ul>
00052      *     <li>Key: The name of the soft foreign key detector.</li>
00053      *     <li>Value: The name of the package that contains the soft foreign key detector.</li>
00054      * </ul>
00055      */
00056     private Hashtable<String, String> __matchers = null;
00057 
00058     /**
00059      * Create the catalogue of soft foreign key detectors.
00060      * @throws Exception
00061      */
00062     public SotfForeignKeyDetectorCatalog() throws SotfForeignKeyDetectorException
00063     {
00064         ArrayList<String> jar_content = null;
00065         this.__matchers = new Hashtable<String, String>();
00066 
00067         // WARNING !!!!!
00068         //
00069         // There is a relation between the following line and the ANT script (build.xml):
00070         // <property name="dir.pkg.fk" value="org/dbview/addons/input/resources/fk"/>
00071         //
00072         Pattern p_matchers = Pattern.compile("^(.+\\.resources\\.softforeignkeydetectors)\\.([^\\.]+)\\.class$"); // __BUILD_CONF__
00073 
00074         // Load the JAR file that contains all (soft) foreign key detectors.
00075         try
00076         {
00077             jar_content = JavaVm.listJar(Conf.get(SotfForeignKeyDetectorCatalog.__FJ_RESOURCE_NAME));
00078         }
00079         catch (Exception e)
00080         {
00081             throw new SotfForeignKeyDetectorException("An error occurred during the initialization of the catalogue: " + e.getClass().getName() + ": " + e.getMessage() );
00082         }
00083 
00084         // Locate detectors.
00085         Iterator<String> i = jar_content.iterator();
00086         while (i.hasNext())
00087         {
00088             String entry = i.next().replaceAll("/|\\\\", ".");
00089             // System.out.println("> " + entry);
00090             Matcher m_matcher = p_matchers.matcher(entry);
00091 
00092             if (m_matcher.matches())
00093             {
00094                 // System.out.println("Matched!");
00095                 String matcher_package = m_matcher.group(1);
00096                 String matcher_name    = m_matcher.group(2);
00097                 // System.out.println(matcher_package + " - " + matcher_name);
00098 
00099                 // Make sure that the detector's name starts with an upper case letter.
00100                 if (! matcher_name.matches("^[A-Z].*$")) { throw new SotfForeignKeyDetectorException("A (soft) foreign key matcher must start with an upper case letter. Invalid name: " + matcher_name + "."); }
00101 
00102                 if (! this.__matchers.containsKey(matcher_name)) { this.__matchers.put(matcher_name, matcher_package); }
00103                 else
00104                 {
00105                     // This case should not happen, since a JAR contains distinct entries.
00106                     throw new SotfForeignKeyDetectorException("Unexpected error : The JAR that contains (soft) foreign key matchers presents duplicated entries.");
00107                 }
00108             }
00109         }
00110     }
00111 
00112     /**
00113      * This method returns the list of all available soft foreign key detectors.
00114      * @return The method returns the list of all available soft foreign key detectors.
00115      * @throws Exception
00116      */
00117     public Enumeration<String> getMatchers()
00118     {
00119         Enumeration<String> e = this.__matchers.keys();
00120         ArrayList<String> r   = new ArrayList<String>();
00121 
00122         while (e.hasMoreElements()) { r.add(e.nextElement()); }
00123 
00124         return Collections.enumeration(r);
00125     }
00126 
00127     /**
00128      * The method produces a string that represents the catalogue.
00129      *
00130      * @return The method returns a string that represents the catalogue.
00131      */
00132     @Override
00133     public String toString()
00134     {
00135         try
00136         {
00137             String r = "";
00138             Enumeration<String> matchers = this.getMatchers();
00139 
00140             while (matchers.hasMoreElements())
00141             {
00142                 String matcher_name = matchers.nextElement();
00143                 String package_name = this.__matchers.get(matcher_name);
00144 
00145                 r = r.concat("[Matcher] "   + matcher_name + System.getProperty("line.separator"));
00146                 r = r.concat("\tCLI name: " + SotfForeignKeyDetectorCatalog.toCli(matcher_name)) + System.getProperty("line.separator");
00147                 r = r.concat("\tPackage: "  + package_name + System.getProperty("line.separator"));
00148             }
00149 
00150             return r;
00151         }
00152         catch (Exception e)
00153         {
00154             return "Could not generate textual representation of the catalogue: " + e.getMessage();
00155         }
00156     }
00157 
00158     /**
00159      * This method returns an instance of a soft foreign key detector, identified by its <i>real</i> (as opposed to "CLI") name.
00160      * @param in_real_name The CLI name of the soft foreign key detector.
00161      * @return The method returns an instance of a soft foreign key detector, identified the given (real) name.
00162      * @throws SotfForeignKeyDetectorException
00163      */
00164     public AbstractSotfForeignKeyDetector getFkMatcherByName(String in_real_name) throws SotfForeignKeyDetectorException
00165     {
00166         String package_name = this.__matchers.get(in_real_name);
00167 
00168         if (null == package_name)
00169         { throw new SotfForeignKeyDetectorException("The soft foreign key detector \"" + in_real_name + "\" does not exist."); }
00170 
00171         String class_name   = package_name + "." + in_real_name;
00172 
00173         try
00174         {
00175             return (AbstractSotfForeignKeyDetector)Class.forName(class_name).newInstance();
00176         }
00177         catch (ExceptionInInitializerError e)
00178         {
00179             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00180         }
00181         catch (ClassNotFoundException e)
00182         {
00183             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00184         }
00185         catch (LinkageError e)
00186         {
00187             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00188         }
00189         catch (IllegalAccessException e)
00190         {
00191             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00192         }
00193         catch (InstantiationException e)
00194         {
00195             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00196         }
00197         catch (SecurityException e)
00198         {
00199             throw new SotfForeignKeyDetectorException("Unexpected error. This error should not happen, unless you modify the software. " + e.getClass().getName() + ": " + e.getMessage());
00200         }
00201     }
00202 
00203     /**
00204      * This method returns an instance of a soft foreign key detector, identified by its <i>CLI</i> (Command Line Interface) name.
00205      * @param in_cli_name The CLI name of the soft foreign key matcher.
00206      * @return The method returns an instance of a soft foreign key matcher, identified the given CLI name.
00207      * @throws SotfForeignKeyDetectorException
00208      */
00209     public AbstractSotfForeignKeyDetector getFkMatcherByCliName(String in_cli_name) throws SotfForeignKeyDetectorException
00210     {
00211         String real_name = SotfForeignKeyDetectorCatalog.fromCli(in_cli_name);
00212         return this.getFkMatcherByName(real_name);
00213     }
00214 
00215     /**
00216      * This method returns the description of a given soft foreign key detector, given its real name.
00217      * @param in_name Name of the soft foreign key detector.
00218      * @return The method returns the description of a given soft foreign key detector.
00219      * @throws SotfForeignKeyDetectorException
00220      */
00221     public String getFkMatcherDescriptionByName(String in_name) throws SotfForeignKeyDetectorException
00222     {
00223         AbstractSotfForeignKeyDetector m = this.getFkMatcherByName(in_name);
00224         return m.description();
00225     }
00226 
00227     /**
00228      * This method returns the description of a given soft foreign key detector, given its CLI name.
00229      * @param in_cli_name CLI name of the soft foreign key detector.
00230      * @return The method returns the description of a given soft foreign key detector.
00231      * @throws SotfForeignKeyDetectorException
00232      */
00233     public String getFkMatcherDescriptionByCliName(String in_cli_name) throws SotfForeignKeyDetectorException
00234     {
00235         return this.getFkMatcherDescriptionByName(SotfForeignKeyDetectorCatalog.fromCli(in_cli_name));
00236     }
00237 
00238     /**
00239      * This method returns the real name of a soft foreign key detector, given the CLI name of the detector.
00240      * @param in_cli_name CLI name of the detector.
00241      * @return The method returns the real name of a soft foreign key detector.
00242      */
00243     public static String fromCli(String in_cli_name)
00244     {
00245         return org.dbview.utils.Strings.dashToUpperCamelCase(in_cli_name);
00246     }
00247 
00248     /**
00249      * This method returns the CLI name of a soft foreign key detector, given the real name of the detector.
00250      * @param in_real_name Ream name of the detector.
00251      * @return The method returns the CLI name of a soft foreign key detector.
00252      */
00253     public static String toCli(String in_real_name)
00254     {
00255         return org.dbview.utils.Strings.upperCamelCaseToDash(in_real_name);
00256     }
00257 }