View Javadoc

1   package com.explosion.expfmodules.rdbmsconn;
2   
3   /*
4    * =============================================================================
5    * 
6    * Copyright 2004 Stephen Cowx
7    * 
8    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9    * use this file except in compliance with the License. You may obtain a copy of
10   * the License at
11   * 
12   * http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   * 
20   * =============================================================================
21   */
22  
23  import java.io.File;
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.StringTokenizer;
31  import java.util.Vector;
32  import java.util.prefs.Preferences;
33  
34  import org.apache.log4j.LogManager;
35  import org.apache.log4j.Logger;
36  
37  import com.explosion.utilities.GeneralConstants;
38  import com.explosion.utilities.GeneralUtils;
39  import com.explosion.utilities.PropertiesUtils;
40  import com.explosion.utilities.exception.ExceptionManagerFactory;
41  import com.explosion.utilities.preferences.Preference;
42  import com.explosion.utilities.preferences.groups.PreferenceGroup;
43  import com.explosion.utilities.preferences.groups.PreferenceGroupManager;
44  
45  /***
46   * @author Stephen Cowx Date created:@25-Jan-2003
47   * This class holds information about a set of drivers.
48   * 
49   * I guess you should only normally need one of these per application
50   */
51  public class DriverDescriptorManager extends PreferenceGroupManager
52  {
53  
54      private static Logger log = LogManager.getLogger(DriverDescriptorManager.class);
55      private Properties driverProperties;
56      protected String driverFileName;
57      private Map driverDetails = new HashMap();
58      private List embeddedList = new ArrayList();
59      
60      
61      public DriverDescriptorManager(Object referenceToStore) throws Exception
62      {
63          super(referenceToStore);
64          loadUsing(referenceToStore);        
65      }
66      
67      /***
68       * Loads the preferences from storage and initialises them. It will
69       * reconcile the loaded entries with those it finds in the properties file
70       * "driver.properties".
71       */
72      public void loadUsing(Object referenceToStore) throws Exception
73      {
74          loadUsing(referenceToStore, RdbmsConnConstants.EMBEDDED_PROPERTIES_FILE);
75      }
76  
77      /***
78       * This method is used mainly for testing. It allows an override of the
79       * default properties file "driver.properties".
80       */
81      public void loadUsing(Object referenceToStore, String driverFileName) throws Exception
82      {
83          if (referenceToStore instanceof Preferences)
84          {
85  	    	this.driverFileName = driverFileName;
86  	
87  	        /* Load preprepared driver information from driver properties file*/
88  	        loadDriverDetails();
89  	
90  	        /* Run through existing items, initialising them and updating them with new keys if neccessary */
91  	        Preferences root = (Preferences) referenceToStore;
92  	        String[] names = root.childrenNames();
93  	        for (int i = 0; i < names.length; i++)
94  	        {
95  	            /* Add the persistent object to the store */
96  	            this.addGroup(names[i], createGroup(names[i]));
97  	        }
98  	
99  	        /* Run through the list of embedded drivers, creating them if they have not been created before */
100 	        for (Iterator it = embeddedList.iterator(); it.hasNext();)
101 	        {
102 	            createOrUpdateEmbeddedDriver((String)it.next());
103 	        }
104         }
105         else
106         {
107         	//no need to load anything
108         }
109     }
110 
111     /***
112      * Return the correct node for the group with the given identifier
113      * @param identifier
114      * @return
115      */
116     public Object getReferenceForGroup(String identifier)
117     {
118 	      if (getReferenceToStore() instanceof Preferences)
119 	      {
120 	      	  Preferences pref = (Preferences) getReferenceToStore();
121 	          return pref.node(identifier); 
122 	      }
123 	      else
124 	      {
125 	          return new HashMap();
126 	      }
127     	  
128     }
129     
130     /***
131      * This method creates a new ConnectionPersistentObject
132      */
133     public PreferenceGroup createGroup(String driverLabel) throws Exception
134     {
135         Object correctReferenceForThisGroup = getReferenceForGroup(driverLabel);
136         
137         DriverDetails drvr = (DriverDetails) driverDetails.get(driverLabel);
138         
139         Preference embedded = new Preference(RdbmsConnConstants.DRVR_EMBEDDED, Preference.PROPERTY_TYPE_BOOLEAN, drvr == null ? new Boolean(false) : new Boolean(drvr.isEmbedded()) , correctReferenceForThisGroup);
140         embedded.setLongName("Embedded");
141         embedded.setDescription("This indicates whether the driver is to be found on the classpath of the program or on an independantly specified path.");
142         embedded.setEditable(false);
143         embedded.setVisible(false);
144         
145         Preference supportsNamespaces = new Preference(RdbmsConnConstants.DRVR_DB_SUPPORTS_NAMESPACES, Preference.PROPERTY_TYPE_BOOLEAN, drvr == null ? new Boolean(true) : new Boolean(drvr.isDbSupportsNamespaces()) , correctReferenceForThisGroup);
146         supportsNamespaces.setLongName("Supports namespaces");
147         supportsNamespaces.setDescription("Indicates whether or not this database/driver schema supports namespaces such as Schemas and Catalogs.");
148         
149         Preference useQuotes = new Preference(RdbmsConnConstants.DRVR_USE_QUOTES_WITH_IDENTIFERS, Preference.PROPERTY_TYPE_BOOLEAN, new Boolean(false) , correctReferenceForThisGroup);
150         useQuotes.setLongName("Use quotes around identifiers");
151         useQuotes.setDescription("Indicates whether or not this database/driver should surround identifiers with quotes when creating SQL queries.  This is relevant in databases where the identiers are case-sensitive.");
152                 
153         Preference rememberedPossibleValues = new Preference(RdbmsConnConstants.DRVR_POSSIBLE_VALUES, Preference.PROPERTY_TYPE_TEXT, drvr == null ? "" : drvr.getClassNamesString(), correctReferenceForThisGroup);
154         rememberedPossibleValues.setLongName("Remembered possible driver names");
155         rememberedPossibleValues.setDescription("This is a list of the driver names which are in the path of this driver file.");
156         rememberedPossibleValues.setEditable(false);
157         rememberedPossibleValues.setVisible(false);
158        
159         Preference location = new Preference(RdbmsConnConstants.DRVR_LOCATION, Preference.PROPERTY_TYPE_COLLECTION, Preference.PROPERTY_TYPE_FILE, new File(GeneralConstants.DEFAULT_FILE), correctReferenceForThisGroup);
160         location.setLongName("Driver libraries");
161         location.setDescription("This is the location of the library or libraries containing the actual JDBC driver. It should point to at least one jar file on the local drive or the network.  It may point to more than one if the driver requires supporting jar files.");
162 
163         DriverDescriptorPreference driver = new DriverDescriptorPreference(RdbmsConnConstants.DRVR_NAME, Preference.PROPERTY_TYPE_STRING_CHOICE, "", correctReferenceForThisGroup);
164         driver.setLongName("Driver name");
165         driver.setDescription("The name given to the driver by the driver authors. Be aware that there might be more than one driver in your driver file, be sure to select the correct one.");
166        
167         /* Create a persistent object out of them */
168          
169         PreferenceGroup driverGroup = new PreferenceGroup(correctReferenceForThisGroup, driverLabel);
170         driverGroup.addPreference(RdbmsConnConstants.DRVR_LOCATION, location);
171         driverGroup.addPreference(RdbmsConnConstants.DRVR_DB_SUPPORTS_NAMESPACES, supportsNamespaces);
172         driverGroup.addPreference(RdbmsConnConstants.DRVR_EMBEDDED, embedded);
173         driverGroup.addPreference(RdbmsConnConstants.DRVR_POSSIBLE_VALUES, rememberedPossibleValues);
174         driverGroup.addPreference(RdbmsConnConstants.DRVR_USE_QUOTES_WITH_IDENTIFERS, useQuotes);
175         
176         /* Perform initialisation */
177         if (drvr != null && drvr.isEmbedded())
178         {
179             driver.setChoiceValues(drvr.getClassNames());
180             driver.setValue(drvr.getClassNames().get(0));
181             driverGroup.addPreference(RdbmsConnConstants.DRVR_NAME, driver);
182             driverGroup.setEditable(false);
183         }
184         else
185         {
186             driver.initialiseNonEmbeddedDriver(location, rememberedPossibleValues);
187             location.addPreferenceChangeListener(driver);
188             driverGroup.addPreference(RdbmsConnConstants.DRVR_NAME, driver);
189         }        
190        
191         return driverGroup;
192     }
193 
194 
195     /***
196      * If an embedded driver exists it will be updated, if it does not, it will be created
197      * 
198      * @throws Exception
199      */
200     private void createOrUpdateEmbeddedDriver(String driverLabel) throws Exception
201     {
202         /*  */
203         PreferenceGroup driver = this.getGroup(driverLabel);
204         if (driver == null)
205         {
206             /* Add the Driver */
207             this.addGroup(driverLabel, createGroup(driverLabel));
208         }
209         else
210         {
211             /* This item exists, update it with a new one */
212             PreferenceGroup newDesc = createGroup(driverLabel);
213             this.setGroup(driverLabel, newDesc);
214         }
215     }    
216     
217     /***
218      * This method loads the driver details from the list of drivers in the
219      * driver.properties file.
220      * 
221      * @throws Exception
222      */
223     private void loadDriverDetails() throws Exception
224     {
225         driverProperties = PropertiesUtils.loadPropertiesFromClasspath(driverFileName, this.getClass().getClassLoader());
226          if (driverProperties != null)
227         {
228             /* Find the embedded drivers */
229             Map embeddedDrivers = findEmbeddedDrivers();
230             
231             /* Find all of the info for all of the drivers */
232             getDriverDetails(embeddedDrivers);
233             
234         }
235         else
236         {
237             log.warn("No embedded driver information available as file " + driverFileName + " cannot be found.");
238         }        
239     }
240 
241     /***
242      * Loads information about all of the drivers
243      * @param embeddedDrivers
244      * @throws Exception
245      */
246     private void getDriverDetails(Map embeddedDrivers) throws Exception
247     {
248         driverDetails = new HashMap();
249         int itemCount = 0;
250         try
251         {
252             String itemString =  driverProperties.getProperty(RdbmsConnConstants.EMBEDDED_PROPERTIES_ITEMS_DRIVERS);
253             if (itemString == null )
254                 throw new Exception("Mandatory property " + RdbmsConnConstants.EMBEDDED_PROPERTIES_ITEMS_DRIVERS + " was missing from the properties file.");
255             
256             itemCount =  Integer.parseInt(itemString);
257             if (itemCount < 1)
258                 log.warn("No driver information found in driver properties file " + driverFileName);
259         }
260         catch (NumberFormatException e)
261         {
262             ExceptionManagerFactory.getExceptionManager().manageException(e,"Property "+RdbmsConnConstants.EMBEDDED_PROPERTIES_ITEMS_DRIVERS+" specified in properties file " + driverFileName + " is not a valid integer.");
263         }
264         
265         for (int i=1;i<=itemCount;i++)
266         {
267             String driverLabel = (String) driverProperties.getProperty(i + "." + RdbmsConnConstants.EMBEDDED_PROP_LABEL);
268             String driverClassNames = (String) driverProperties.getProperty(i + "." + RdbmsConnConstants.EMBEDDED_PROP_CLASSNAMES);
269             String driverSupportsNamespaces = (String) driverProperties.getProperty(i + "." + RdbmsConnConstants.EMBEDDED_PROP_SUPPORTS_NAMESPACES);
270 
271             DriverDetails drvr = new DriverDetails();
272             
273             if (embeddedDrivers.get(Integer.toString(i)) != null)
274             {
275                 if (embeddedList == null)
276                     embeddedList = new ArrayList();
277                 
278                 embeddedList.add(driverLabel);
279                 
280                 drvr.setEmbedded(true);
281                
282               if (driverLabel == null)
283                 throw new Exception("Mandatory property " + i + "." + RdbmsConnConstants.EMBEDDED_PROP_LABEL + " was missing from the properties file.");
284               
285               if (driverClassNames == null)
286                 throw new Exception("Mandatory property " + i + "." + RdbmsConnConstants.EMBEDDED_PROP_CLASSNAMES + " was missing from the properties file.");
287             }
288             
289             if (driverSupportsNamespaces != null)
290             {
291                 drvr.setDbSupportsNamespaces(GeneralUtils.getLenientBoolean(driverSupportsNamespaces));
292             }
293             
294             /* Add these classnames to the list */
295             if (driverClassNames != null)
296             {
297               StringTokenizer classNamesTokenizer = new StringTokenizer(driverClassNames, ",");
298               Vector classNames = new Vector();
299               while (classNamesTokenizer.hasMoreTokens())
300               {
301                 classNames.add(classNamesTokenizer.nextToken().trim());
302               }
303               drvr.setClassNames(classNames);
304               drvr.setClassNamesString(driverClassNames);
305             }
306             
307             drvr.setLabel(driverLabel);
308             
309             driverDetails.put(driverLabel,drvr);
310         }
311     }
312 
313     /***
314      * Makes a map of keys which are embedded drivers
315      * @param embeddedDrivers
316      */
317     private Map findEmbeddedDrivers()
318     {
319         /***
320          * Look for and mark embedded drivers
321          */
322         Map embeddedDrivers = new HashMap();
323         String embeddedDriversString = (String) driverProperties.getProperty(RdbmsConnConstants.EMBEDDED_PROPERTIES_EMBEDDED_DRIVERS);
324         if (embeddedDriversString != null)
325         {
326             StringTokenizer tokenizer = new StringTokenizer(embeddedDriversString, ",");
327             while (tokenizer.hasMoreTokens())
328             {
329                 embeddedDrivers.put(tokenizer.nextToken(), "");
330             }
331         }
332         else
333         {
334             log.warn("No embedded drivers found in driver properties file " + driverFileName);
335         }
336         
337         return embeddedDrivers;
338     }
339 }
340 
341 /***
342  * Small helper class to store temporary information about an embedded driver
343  * once it has been read from a properties file
344  * 
345  * @author Stephen Cowx Created on 18-Oct-2004
346  */
347 
348 class DriverDetails
349 {
350     private String label;
351     private Vector classNames;
352     private String classNamesString;
353     private boolean isEmbedded;
354     private boolean dbSupportsNamespaces = true;
355 
356     public Vector getClassNames()
357     {
358         return classNames;
359     }
360 
361     public void setClassNames(Vector classNames)
362     {
363         this.classNames = classNames;
364     }
365 
366     public String getLabel()
367     {
368         return label;
369     }
370 
371     public void setLabel(String label)
372     {
373         this.label = label;
374     }
375 
376     public boolean isEmbedded()
377     {
378         return isEmbedded;
379     }
380     
381     public void setEmbedded(boolean isEmbedded)
382     {
383         this.isEmbedded = isEmbedded;
384     }
385     
386     public String getClassNamesString()
387     {
388         return classNamesString;
389     }
390     
391     public void setClassNamesString(String classNamesString)
392     {
393         this.classNamesString = classNamesString;
394     }
395     
396     public boolean isDbSupportsNamespaces() {
397         return dbSupportsNamespaces;
398     }
399     
400     public void setDbSupportsNamespaces(boolean dbSupportsNamespaces) {
401         this.dbSupportsNamespaces = dbSupportsNamespaces;
402     }
403 }
404