DBVIEW
src/org/dbview/runtime/actions/Actions.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.runtime.actions;
00024 
00025 import java.util.ArrayList;
00026 import java.util.Enumeration;
00027 import java.util.Hashtable;
00028 import java.util.Iterator;
00029 import java.util.List;
00030 import java.io.*;
00031 import org.jdom.Element;
00032 import org.dbview.adapter.AbstractCli;
00033 import org.dbview.adapter.AbstractDescription;
00034 import org.dbview.adapter.CliParameter;
00035 import org.dbview.db.structure.*;
00036 import org.dbview.input_addons.*;
00037 import org.dbview.output_addons.*;
00038 import org.dbview.resources.*;
00039 import org.dbview.utils.Strings;
00040 import org.jgrapht.GraphPath;
00041 import org.jgrapht.UndirectedGraph;
00042 import org.jgrapht.alg.KShortestPaths;
00043 
00044 /**
00045  * This class implements all action defined by the command line interface.
00046  *
00047  * @author Denis Beurive
00048  */
00049 
00050 public class Actions
00051 {
00052 
00053     /**
00054      * This method lists all input targets.
00055      *
00056      * @throws Exception
00057      */
00058     public static void listInputTargets() throws Exception
00059     {
00060         InputCatalog catalog = new InputCatalog();
00061         Enumeration<String> e = catalog.getTargets();
00062         while (e.hasMoreElements())
00063         {
00064             System.out.println("\t" + e.nextElement());
00065         }
00066     }
00067 
00068     /**
00069      * This method lists all foreign key matchers.
00070      * @throws Exception
00071      */
00072     public static void listFkMatchers() throws Exception
00073     {
00074         SotfForeignKeyDetectorCatalog catalogue = new SotfForeignKeyDetectorCatalog();
00075         Enumeration<String> e = catalogue.getMatchers();
00076         while (e.hasMoreElements())
00077         {
00078             String matcher_name = e.nextElement();
00079             String desc = catalogue.getFkMatcherDescriptionByName(matcher_name);
00080             System.out.println("\t" + SotfForeignKeyDetectorCatalog.toCli(matcher_name));
00081             System.out.println(org.dbview.utils.Strings.indent("\t", desc));
00082             System.out.println();
00083         }
00084         System.out.println("Please note that, if you don't find the soft foreign key detector that you need, you can easily create a new one, and add it to the list. Only very basic knowledge in Java is required for this operation. Basically, you write one class, and you reccompile the software (usng the provided ANT specification). That's it. Look at the online documentation for an example.");
00085 
00086         System.out.println();
00087     }
00088 
00089     /**
00090      * This method prints the help for a specific input add-on.
00091      * @param in_args This hash table contains the parameters required for printing the help for a specific input add-on.
00092      *        Keys are:
00093      *        <ul>
00094      *          <li>name; Name of the input add-on.</li>
00095      *        </ul>
00096      *
00097      * @throws Exception
00098      */
00099     public static void helpInputAddOn(Hashtable<String, Object> in_args) throws Exception
00100     {
00101         String add_on_name = (String)in_args.get("name");
00102 
00103         InputCatalog catalog = new InputCatalog();
00104         AbstractDescription description = (AbstractDescription) catalog.getAdaptor(add_on_name, "Description");
00105         AbstractCli cli = (AbstractCli) catalog.getAdaptor(add_on_name, "Cli");
00106 
00107         System.out.println(description.brief());
00108         ArrayList<CliParameter> opt = cli.getOptions();
00109         System.out.println("Parameters:");
00110         for (CliParameter param : opt)
00111         {
00112             System.out.println("\t" + param.parameter + " (" + (param.mandatory ? "mandatory" : "optional") + ")");
00113             // System.out.println("\ttype:\t\t" +
00114             // CliParameterTypes.toString(param.type));
00115             // System.out.println("\tmandatory:\t" + (param.mandatory ? "TRUE" :
00116             // "FALSE"));
00117             // System.out.println("\tdescription:\t" + param.description);
00118             // System.out.println();
00119         }
00120     }
00121 
00122     /**
00123      * This method prints the help for a specific output target.
00124      * @param in_args This hash table contains the parameters required for printing the help for a specific output add-on.
00125      *        Keys are:
00126      *        <ul>
00127      *          <li>name: Name of the output add-on.
00128      *        </ul>
00129      *
00130      * @throws Exception
00131      */
00132     public static void helpOutputAddOn(Hashtable<String, Object> in_args) throws Exception
00133     {
00134         String add_on_name = (String)in_args.get("name");
00135 
00136         OutputCatalog catalog = new OutputCatalog();
00137         AbstractDescription description = (AbstractDescription) catalog.getAdaptor(add_on_name, "Description");
00138         AbstractCli cli = (AbstractCli) catalog.getAdaptor(add_on_name, "Cli");
00139 
00140         System.out.println(description.brief());
00141         ArrayList<CliParameter> opt = cli.getOptions();
00142         System.out.println("Parameters:");
00143         for (CliParameter param : opt)
00144         {
00145             System.out.println("\t" + param.parameter + " (" + (param.mandatory ? "mandatory" : "optional") + ")");
00146             // System.out.println("\ttype:\t\t" +
00147             // CliParameterTypes.toString(param.type));
00148             // System.out.println("\tmandatory:\t" + (param.mandatory ? "TRUE" :
00149             // "FALSE"));
00150             // System.out.println("\tdescription:\t" + param.description);
00151             // System.out.println();
00152         }
00153     }
00154 
00155     /**
00156      * This method lists all output targets.
00157      *
00158      * @throws Exception
00159      */
00160     public static void listOutputTargets() throws Exception
00161     {
00162         OutputCatalog catalog = new OutputCatalog();
00163         Enumeration<String> e = catalog.getTargets();
00164         while (e.hasMoreElements())
00165         {
00166             System.out.println("\t" + OutputCatalog.toCli(e.nextElement()));
00167         }
00168     }
00169 
00170     /**
00171      * This method adds a new profile to the repository.
00172      *
00173      * @param in_args This hash table contains the parameters required for updating a profile.
00174      *        Keys are:
00175      *        <ul>
00176      *          <li>name: Name of the new profile to add.</li>
00177      *          <li>input-target: Profile's target.</li>
00178      *          <li>input-target-configuration: XML document, generated by the CLI parser, that represents the profile.</li>
00179      *        </ul>
00180      *
00181      * @throws Exception
00182      */
00183     public static void addProfile(Hashtable<String, Object> in_args) throws Exception
00184     {
00185         String profile_name   = (String)in_args.get("name");
00186         String target_name    = (String)in_args.get("input-target");
00187         Element configuration = (Element)in_args.get("input-target-configuration");
00188 
00189         InputCatalog catalog = new InputCatalog();
00190         AbstractConfiguration profile = (AbstractConfiguration) catalog.getAdaptor(target_name, "Configuration");
00191         profile.fromXml(configuration, target_name, profile_name);
00192         // System.out.println(profile.printToXml());
00193         ProfilesRepository.add(profile);
00194     }
00195 
00196     /**
00197      * This method removes a profile from the repository.
00198      * @param in_args This hash table contains the parameters required for updating a profile.
00199      *        Keys are:
00200      *        <ul>
00201      *          <li>name: Name of the profile to remove.</li>
00202      *        </ul>
00203 
00204      * @throws Exception
00205      */
00206     // public static void removeProfile(String in_profile_name) throws Exception
00207     public static void removeProfile(Hashtable<String, Object> in_args) throws Exception
00208     {
00209         String profile_name = (String)in_args.get("name");
00210         ProfilesRepository.remove(profile_name);
00211     }
00212 
00213     /**
00214      * This method removes a profile from the repository.
00215      * @param in_args This hash table contains the parameters required for updating a profile.
00216      *        Keys are:
00217      *        <ul>
00218      *          <li>name: Name of the profile to upddate.</li>
00219      *          <li>target: Name of the profile's target.</li>
00220      *          <li>new_configuration: XML document, generated by the CLI parser, that represents the new profile.</li>
00221      *          <li>old_configuration: XML document, generated by the CLI parser, that represents the old profile.</li>
00222      *        </ul>
00223      *
00224      * @throws Exception
00225      */
00226     public static void updateProfile(Hashtable<String, Object> in_args) throws Exception
00227 
00228     {
00229         String profile_name       = (String)in_args.get("name");
00230         String target_name        = (String)in_args.get("target");
00231         Element new_configuration = (Element)in_args.get("new_configuration");
00232         Element old_configuration = (Element)in_args.get("old_configuration");
00233 
00234         // try { System.out.println("New profile:");
00235         // System.out.println(org.dbview.utils.Jdom.print(in_new_configuration));
00236         // System.out.println("Old profile:");
00237         // System.out.println(org.dbview.utils.Jdom.print(in_old_configuration));
00238         // } catch (Exception e) { }
00239 
00240         // Build the new version of the profile...
00241         Element old_data = old_configuration.getChild("data");
00242         @SuppressWarnings("unchecked")
00243         List<Element> params = (List<Element>)new_configuration.getChildren();
00244         for (int i = 0; i < params.size(); i++)
00245         {
00246             Element param = params.get(i);
00247             String name = param.getName();
00248             Element e = old_data.getChild(name);
00249             if (null == e)
00250             {
00251                 throw new Exception("Unexpected error : the specified parameter \"" + name + "\" could not be found in the current configuration. Please note that this error should not happen unless you modify the software.");
00252             }
00253             try
00254             {
00255                 e.setText(param.getText());
00256             }
00257             catch (Exception ex)
00258             {
00259                 throw new Exception("Unexpected error : " + ex.getMessage());
00260             }
00261         }
00262 
00263         // try { System.out.println("Profile to inject into repository:");
00264         // System.out.println(org.dbview.utils.Jdom.print(in_old_configuration));
00265         // } catch (Exception e) { }
00266 
00267         // Update the repository with the new version of the profile.
00268         try
00269         {
00270             InputCatalog c = new InputCatalog();
00271             AbstractConfiguration new_conf = (AbstractConfiguration) c.getAdaptor(target_name, "Configuration");
00272             new_conf.fromXml(old_configuration, null, null);
00273             ProfilesRepository.update(new_conf);
00274         }
00275         catch (Exception ex)
00276         {
00277             throw new Exception("Unexpected error: " + ex.getMessage() + " " + ex.getClass().getName());
00278         }
00279     }
00280 
00281     /**
00282      * This method prints a given profile.
00283      * @param in_args This hash table contains the parameters required for showing a profile.
00284      *        Keys are:
00285      *        <ul>
00286      *          <li>name: Name of the profile to show.</li>
00287      *        </ul>
00288      * @throws Exception
00289      */
00290     public static void showProfile(Hashtable<String, Object> in_args) throws Exception
00291 
00292     {
00293         String name = (String)in_args.get("name");
00294         ProfilesRepository.init();
00295         AbstractConfiguration profile_configuration = ProfilesRepository.getProfileInstance(name);
00296         if (null == profile_configuration)
00297         {
00298             throw new Exception("The profile \"" + name + "\" does not exist.");
00299         }
00300 
00301         ArrayList<String[]> data = profile_configuration.toStrings();
00302         ArrayList<String> fields = new ArrayList<String>();
00303         for (int i = 0; i < data.size(); i++)
00304         {
00305             fields.add(data.get(i)[0]);
00306         }
00307         Strings.margingRight(fields, 2);
00308         for (int i = 0; i < data.size(); i++)
00309         {
00310             System.out.println("\t" + fields.get(i) + data.get(i)[1]);
00311         }
00312     }
00313 
00314     /**
00315      * This method prints the list of profile's names stored in the repository.
00316      *
00317      * @throws Exception
00318      */
00319     public static void listProfiles() throws Exception
00320     {
00321         ArrayList<String> profiles = null;
00322 
00323         ProfilesRepository.init();
00324         profiles = ProfilesRepository.getProfilesNames();
00325         for (int i = 0; i < profiles.size(); i++)
00326         {
00327             System.out.println(profiles.get(i));
00328 
00329             Hashtable<String, Object> params = new Hashtable<String, Object>();
00330             params.put("name", profiles.get(i));
00331             Actions.showProfile(params);
00332             System.out.println();
00333         }
00334     }
00335 
00336     /**
00337      * This method exports a given database to a given output format.
00338      * @param in_args his hash table contains the parameters for the export.
00339      *        Keys are:
00340      *        <ul>
00341      *          <li>path-between: If the user request the calculation of a path, this array contains the names of the tables at the extremities.</li>
00342      *          <li>path-limit: If the user request the calculation of a path, this integer represents the maximum number of paths.</li>
00343      *          <li>zoom-list: If the user request a zoom around tables, this array contains the list of tables to zoom in.</li>
00344      *          <li>zoom-level: If the user request a zoom around tables, this integer represents the neighbourhood area.</li>
00345      *          <li>input-target-name: Name of the add-on that is used to connect to a database.</li>
00346      *          <li>output-target-name: Name of the add-on used to export the database.</li>
00347      *          <li>input-configuration: Specific configuration for the input add-on.</li>
00348      *          <li>output-configuration: Specific configuration for the output add-on.</li>
00349      *        </ul>
00350      *
00351      * @throws Exception
00352      */
00353 
00354     public static void export(Hashtable<String, Object> in_args) throws Exception
00355     {
00356         @SuppressWarnings("unchecked")
00357         ArrayList<String> path_between  = in_args.containsKey("path-between") ? (ArrayList<String>)in_args.get("path-between") : null;
00358         Integer path_limit              = in_args.containsKey("path-limit")   ? (Integer)in_args.get("path-limit") : null;
00359 
00360         @SuppressWarnings("unchecked")
00361         ArrayList<String> zoom_list     = in_args.containsKey("zoom-list")  ? (ArrayList<String>)in_args.get("zoom-list") : null;
00362         Integer zoom_level              = in_args.containsKey("zoom-level") ? (Integer)in_args.get("zoom-level") : null;
00363 
00364         String  input_target            = (String)in_args.get("input-target-name");
00365         String  output_target           = (String)in_args.get("output-target-name");
00366         Element input_configuration     = (Element)in_args.get("input-configuration");
00367         Element in_output_confguration  = (Element)in_args.get("output-configuration");
00368 
00369 
00370         // Create the catalogues.
00371         InputCatalog in_catalog   = new InputCatalog();
00372         OutputCatalog out_catalog = new OutputCatalog();
00373 
00374         // First get the "loader" adapter for the requested input target.
00375         AbstractLoader loader = (AbstractLoader) in_catalog.getAdaptor(input_target, "Loader");
00376 
00377         // Then, get the "exporter" adaptor for the requested output target.
00378         AbstractExporter exporter = (AbstractExporter) out_catalog.getAdaptor(output_target, "Exporter");
00379 
00380         // System.out.println("OK");
00381 
00382         // Load the database.
00383         Database db = loader.load(input_configuration);
00384         // System.out.println("DB loaded!");
00385         
00386         // Get the list of tables to export.
00387         Object representation;
00388         if (null != zoom_list)
00389         {
00390             ArrayList<Table> tables = db.zoomAroundByNames(zoom_list, zoom_level);
00391             representation = exporter.export(db, in_output_confguration, tables);
00392         }
00393         else
00394         {
00395             if (null != path_between)
00396             {
00397                 ArrayList<Object> lr   = new ArrayList<Object>();
00398                 String from_table_name = path_between.get(0);
00399                 String to_table_name   = path_between.get(1);
00400 
00401                 // Make sure that the given table's names exist in the loaded database.
00402                 if (null == db.getTable(from_table_name))
00403                 { throw new Exception("The name of the table you specified as starting point of the path (\"" + from_table_name + "\") does not exist in the database."); }
00404 
00405                 if (null == db.getTable(to_table_name))
00406                 { throw new Exception("The name of the table you specified as ending point of the path (\"" + to_table_name + "\") does not exist in the database."); }
00407 
00408                 // Get the JgraphT object that represents the database.
00409                 UndirectedGraph<Table, JgraphtTableToTableEdge> g = db.jgrapht(null);
00410 
00411                 // Calculate the shortest path(es) between the two specified tables.
00412                 KShortestPaths<Table, JgraphtTableToTableEdge> pathesFinder = new KShortestPaths<Table, JgraphtTableToTableEdge>(g, db.getTable(from_table_name), path_limit);
00413                 List <GraphPath<Table, JgraphtTableToTableEdge>> pathes = pathesFinder.getPaths(db.getTable(to_table_name));
00414                 Iterator<GraphPath<Table, JgraphtTableToTableEdge>> pathesIterator = pathes.iterator();
00415 
00416                 while (pathesIterator.hasNext())
00417                 {
00418                     // Get the start and the end of the pathes (we already know)
00419                     GraphPath<Table, JgraphtTableToTableEdge> gr = pathesIterator.next();
00420 
00421                     // For memory:
00422                     // String StartVertex = gr.getStartVertex().getName();
00423                     // String EndVertex   = gr.getEndVertex().getName();
00424 
00425                     // Get the list of jumps.
00426                     List <JgraphtTableToTableEdge> edges = gr.getEdgeList();
00427                     Iterator<JgraphtTableToTableEdge> edgesItearator = edges.iterator();
00428                     ArrayList<Table> tables = new ArrayList<Table>();
00429                     while (edgesItearator.hasNext())
00430                     {
00431                         JgraphtTableToTableEdge edge = (JgraphtTableToTableEdge)edgesItearator.next();
00432 
00433                         Table src = edge.getSource();
00434                         Table dst = edge.getTarget();
00435                         if (! tables.contains(src)) { tables.add(src); }
00436                         if (! tables.contains(dst)) { tables.add(dst); }
00437                     }
00438                     lr.add((String)exporter.export(db, in_output_confguration, tables));
00439                 }
00440             }
00441             else
00442             {
00443                 ArrayList<Table> tables = db.getTables();
00444                 representation = exporter.export(db, in_output_confguration, tables);
00445             }
00446         }
00447 
00448         // DEBUG
00449         // System.out.println("export() - exported...");
00450     }
00451 
00452 
00453 }