DBVIEW
|
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.addons; 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 * @class AddOnCatalog 00037 * The class is a base class for all add-on catalogues. 00038 * <ul> 00039 * <li>An add-on is represented by a package.</li> 00040 * <li>An add-on exports adaptors that are interfaces to the add-on's environment.</li> 00041 * <li>An add-on's adaptors are located in the add-on's package.</li> 00042 * <li>Add-ons are regrouped into JAR files.</li> 00043 * <li>A catalogue lists all add-ons located in a given JAR file.</li> 00044 * </ul> 00045 * 00046 * @author Denis Beurive 00047 */ 00048 public class AddOnCatalog 00049 { 00050 /** 00051 * This hash table lists all add-ons declared in the given resource. Each 00052 * add-on is associated to its adaptors. 00053 * <ul> 00054 * <li>Key: Name of the add-on.</li> 00055 * <li>Value: See class AddDon. It defines the following data: 00056 * <ul> 00057 * <li>The name of the package in which the add-on is declared.</li> 00058 * <li>The list of adaptors declared for the add-on.</li> 00059 * </ul> 00060 * </li> 00061 * </ul> 00062 */ 00063 private Hashtable<String, AddOn> __addons = null; 00064 00065 /** 00066 * This array contains the expected list of adaptors' names. 00067 * This array is used to check that all add-ons present all the mandatory adaptors. 00068 */ 00069 private ArrayList<String> __adaptors_list = null; 00070 00071 /** 00072 * Create a catalogue of add-ons. 00073 * 00074 * @param in_resource_name 00075 * Name of the resource that contains the add-ons (this is a JAR). 00076 * @param in_adaptors_list 00077 * List of adaptors that must be part of the add-on's package. 00078 * @param in_pattern 00079 * Regular expression that is used to recognize an add-on. 00080 * @throws Exception 00081 */ 00082 public AddOnCatalog(String in_resource_name, 00083 ArrayList<String> in_adaptors_list, 00084 Pattern in_pattern) throws Exception 00085 { 00086 this.__addons = new Hashtable<String, AddOn>(); 00087 this.__adaptors_list = in_adaptors_list; 00088 00089 // Load the JAR file that contains all adapters. 00090 ArrayList<String> jar_content = JavaVm.listJar(Conf.get(in_resource_name)); 00091 00092 // Locate targets. 00093 // System.out.println(in_resource_name + " > " + jar_content.size()); 00094 Iterator<String> i = jar_content.iterator(); 00095 while (i.hasNext()) 00096 { 00097 String entry = i.next().replaceAll("/|\\\\", "."); 00098 00099 Matcher m_adaptor = in_pattern.matcher(entry); 00100 00101 // Did we find an adaptor? 00102 if (m_adaptor.matches()) 00103 { 00104 AddOn target = null; 00105 String target_package = m_adaptor.group(1); 00106 String target_name = m_adaptor.group(2); 00107 String target_adaptor = m_adaptor.group(3); 00108 00109 if (! this.__adaptors_list.contains(target_adaptor)) { continue; } 00110 00111 if (!this.__addons.containsKey(target_name)) 00112 { 00113 target = new AddOn(); 00114 target.package_name = target_package; 00115 this.__addons.put(target_name, target); 00116 } 00117 else 00118 { 00119 target = this.__addons.get(target_name); 00120 } 00121 00122 target.adaptors_list.add(target_adaptor); 00123 } 00124 00125 // The entry is not related to targets... skip it. 00126 } 00127 00128 // Check that the target has all the mandatory adaptors. 00129 Enumeration<String> targets = this.__addons.keys(); 00130 while (targets.hasMoreElements()) 00131 { 00132 String target_name = targets.nextElement(); 00133 if (!this.__isOk()) 00134 { 00135 throw new Exception("Unexpected error. The add-on \"" + target_name + "\" is missing an adaptor! This error should not happen unless you modify the software."); 00136 } 00137 } 00138 00139 // At this point, the catalog is built. 00140 } 00141 00142 /** 00143 * The method produces a string that represents the catalogue. 00144 * @note This method is used to debug the application. 00145 * @return The method returns a string that represents the catalogue. 00146 */ 00147 @Override 00148 public String toString() 00149 { 00150 try 00151 { 00152 String r = ""; 00153 Enumeration<String> targets = this.getTargets(); 00154 00155 while (targets.hasMoreElements()) 00156 { 00157 String target_name = targets.nextElement(); 00158 AddOn target = this.__addons.get(target_name); 00159 String package_name = target.package_name; 00160 00161 r = r.concat("[Target] " + target_name + System.getProperty("line.separator")); 00162 r = r.concat("\tPackage: " + package_name + System.getProperty("line.separator")); 00163 00164 for (int i = 0; i < target.adaptors_list.size(); i++) 00165 { 00166 String adaptator_name = target.adaptors_list.get(i); 00167 r = r.concat("\t - " + adaptator_name + System.getProperty("line.separator")); 00168 } 00169 } 00170 00171 return r; 00172 } 00173 catch (Exception e) 00174 { 00175 return "Could not generate textual representation of the catalogue: " + e.getMessage(); 00176 } 00177 } 00178 00179 /** 00180 * This method returns the list of all add-ons found in the catalog. 00181 * @return This method returns the list of all add-ons found in the catalog. 00182 * @throws Exception 00183 */ 00184 public Enumeration<String> getTargets() throws Exception 00185 { 00186 Enumeration<String> e = this.__addons.keys(); 00187 ArrayList<String> r = new ArrayList<String>(); 00188 00189 while (e.hasMoreElements()) { r.add(e.nextElement()); } 00190 return Collections.enumeration(r); 00191 } 00192 00193 /** 00194 * Check the list of detected adaptors, for all add-ons in the catalogue. 00195 * @return If the list of detected adaptors is valid, then the function 00196 * returns the value TRUE. Otherwise the function returns the value 00197 * fALSE. 00198 */ 00199 private Boolean __isOk() 00200 { 00201 for (String adaptor : this.__adaptors_list) 00202 { 00203 if (-1 == this.__adaptors_list.indexOf(adaptor)) 00204 { 00205 return Boolean.FALSE; 00206 } 00207 } 00208 return Boolean.TRUE; 00209 } 00210 00211 /** 00212 * This method returns the name of the package that contains adaptors' 00213 * implementations for a given add-on (that is: the add-on's package). 00214 * 00215 * @param in_add_on_name 00216 * Name of the add-on. 00217 * @return This method returns the name of the package that contains 00218 * adaptors' implementations for the given add-on. 00219 * @throws Exception 00220 */ 00221 public String getPackage(String in_add_on_name) throws AddOnCatalogException 00222 { 00223 if (!this.__addons.containsKey(in_add_on_name)) 00224 { 00225 throw new AddOnCatalogException("You try to get the name of a package (out of the catalog) for an add-on (\"" + in_add_on_name + "\") that does not exist!"); 00226 } 00227 return this.__addons.get(in_add_on_name).package_name; 00228 } 00229 00230 /** 00231 * This method returns an instance of a given adaptor's, for a given add-on. 00232 * 00233 * @param in_target_name 00234 * Name of the add-on to which the adaptor belongs. 00235 * Please note that this name may contain dashes. 00236 * This string will be converted into "Lower Camel Case". 00237 * @param in_adaptor_name 00238 * Name of the adaptor to create. 00239 * @return The method returns a new instance of the required adaptor. 00240 * @throws AddOnCatalogException 00241 */ 00242 public Object getAdaptor(String in_target_name, 00243 String in_adaptor_name) throws AddOnCatalogException 00244 { 00245 // Convert into Lower Camel Case ("a-bc-de" -> "aBcDe"). 00246 String real_name = AddOnCatalog.fromCli(in_target_name); 00247 00248 AddOn target = this.__addons.get(real_name); 00249 if (null == target) 00250 { 00251 throw new AddOnCatalogException("The requested add-on (\"" + in_target_name + "\") does not exist."); 00252 } 00253 String package_name = target.package_name; 00254 String class_name = package_name + "." + in_adaptor_name; 00255 00256 try 00257 { 00258 // System.out.println("Name = " + class_name); 00259 return Class.forName(class_name).newInstance(); 00260 } 00261 catch (ExceptionInInitializerError e) 00262 { 00263 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (ExceptionInInitializerError). " + e.getClass().getName() + ": " + e.getMessage()); 00264 } 00265 catch (ClassNotFoundException e) 00266 { 00267 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (ClassNotFoundException). " + e.getClass().getName() + ": " + e.getMessage()); 00268 } 00269 catch (LinkageError e) 00270 { 00271 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (LinkageError). " + e.getClass().getName() + ": " + e.getMessage()); 00272 } 00273 catch (IllegalAccessException e) 00274 { 00275 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (IllegalAccessException). " + e.getClass().getName() + ": " + e.getMessage()); 00276 } 00277 catch (InstantiationException e) 00278 { 00279 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (InstantiationException). " + e.getClass().getName() + ": " + e.getMessage()); 00280 } 00281 catch (SecurityException e) 00282 { 00283 throw new AddOnCatalogException("Unexpected error. This error should not happen, unless you modify the software (SecurityException). " + e.getClass().getName() + ": " + e.getMessage()); 00284 } 00285 } 00286 00287 /** 00288 * This method converts an add-on name, given from the command line interface, into its internal representation. 00289 * @param in_cli_name Name of the add-on, as given by the command line. 00290 * @return The method returns the internal name of the add-on. 00291 */ 00292 00293 public static String fromCli(String in_cli_name) 00294 { 00295 return org.dbview.utils.Strings.dashToLowerCamelCase(in_cli_name); 00296 } 00297 00298 /** 00299 * This method converts an add-on name into its CLI name. 00300 * @param in_real_name "Internal" name of the add-on. 00301 * @return The method returns the CLI name of the add-on. 00302 */ 00303 public static String toCli(String in_real_name) 00304 { 00305 return org.dbview.utils.Strings.lowerCamelCaseToDash(in_real_name); 00306 } 00307 }