Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements utility methods for a metadata catalog
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones, Jivka Bojilova
7
 *    Release: @release@
8
 * 
9
 *   '$Author: jones $'
10
 *     '$Date: 2001-10-18 16:57:20 -0700 (Thu, 18 Oct 2001) $'
11
 * '$Revision: 845 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.File;
31
import java.net.URL;
32
import java.net.MalformedURLException;
33
import java.sql.Connection;
34
import java.sql.DriverManager;
35
import java.sql.SQLException;
36
import java.util.PropertyResourceBundle;
37
import java.util.Hashtable;
38
import java.util.Enumeration;
39

    
40
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
41

    
42
/**
43
 * A suite of utility classes for the metadata catalog server
44
 */
45
public class MetaCatUtil {
46

    
47
  public static AbstractDatabase dbAdapter;
48
  private static PropertyResourceBundle options = null;
49
  private static String propertiesFile = "edu.ucsb.nceas.metacat.metacat";
50
  private static boolean debug = false;
51

    
52
  private Hashtable connectionPool = new Hashtable();
53

    
54
  /** 
55
   * Determine our db adapter class and create an instance of that class
56
   */
57
  static {
58
    try {
59
      dbAdapter = (AbstractDatabase)createObject(getOption("dbAdapter"));
60
    } catch (Exception e) {
61
      System.err.println("Error in MetaCatUtil static block:" + e.getMessage());
62
    }
63
  }
64

    
65
// CONSTRUCTORS NOT NEEDED
66
//  /**
67
//   * Construct an instance of the utility class
68
//   */
69
//  public MetaCatUtil() {
70
//
71
//    options = (PropertyResourceBundle)
72
//          PropertyResourceBundle.getBundle(propertiesFile);
73
//  }
74
//  
75
//  /**
76
//   * This constructor allows the usage of a different properties file
77
//   * @param propFile the properties file that you wish to use.
78
//   */
79
//  public MetaCatUtil(String propFile)  {
80
//
81
//    propertiesFile = propFile;
82
//  }
83

    
84
  /**
85
   * Instantiate a class using the name of the class at runtime
86
   *
87
   * @param className the fully qualified name of the class to instantiate
88
   */
89
  public static Object createObject(String className) throws Exception {
90
 
91
    Object object = null;
92
    try {
93
      Class classDefinition = Class.forName(className);
94
      object = classDefinition.newInstance();
95
    } catch (InstantiationException e) {
96
      throw e;
97
    } catch (IllegalAccessException e) {
98
      throw e;
99
    } catch (ClassNotFoundException e) {
100
      throw e;
101
    }
102
    return object;
103
  }
104

    
105
  /** 
106
   * Utility method to get an option value from the properties file
107
   *
108
   * @param optionName the name of the option requested
109
   */
110
  public static String getOption(String optionName) {
111
      // Get the configuration file information
112
      if (options == null) {
113
        options = (PropertyResourceBundle)
114
          PropertyResourceBundle.getBundle(propertiesFile);
115
      }
116
      String value = (String)options.handleGetObject(optionName);
117
      return value;
118
  }
119

    
120
  /** 
121
   * Utility method to get an option value from a properties file
122
   *
123
   * @param optionName the name of the option requested
124
   * @param propFile the name of the file where to get the properties from
125
   */
126
  public String getOption(String optionName, String propFile) {
127
    // Get the configuration file information
128
    PropertyResourceBundle options = (PropertyResourceBundle)
129
                                     PropertyResourceBundle.getBundle(propFile);
130
    String value = (String)options.handleGetObject(optionName);
131
    return value;
132
  }
133

    
134
  /** 
135
   * Utility method to establish a JDBC database connection using connection
136
   * info from the properties file
137
   */
138
  public Connection openDBConnection()
139
                throws SQLException, ClassNotFoundException {
140
    return openDBConnection(getOption("dbDriver"), getOption("defaultDB"),
141
                     getOption("user"), getOption("password"));
142
  }
143

    
144
  /** 
145
   * Utility method to establish a JDBC database connection 
146
   *
147
   * @param dbDriver the string representing the database driver
148
   * @param connection the string representing the database connectin parameters
149
   * @param user name of the user to use for database connection
150
   * @param password password for the user to use for database connection
151
   */
152
  public static Connection openDBConnection(String dbDriver, String connection,
153
                String user, String password)
154
                throws SQLException, ClassNotFoundException {
155

    
156
     // Load the Oracle JDBC driver
157
     Class.forName (dbDriver);
158

    
159
     debugMessage("Opening connection: " + connection);
160
     // Connect to the database
161
     Connection conn = DriverManager.getConnection( connection, user, password);
162
     return conn;
163
  }
164

    
165
  /* Utility method to create and return a pool of Connection objects */
166
  public Hashtable getConnectionPool()
167
                throws SQLException, ClassNotFoundException {
168

    
169
    int initConn = (new Integer(getOption("initialConnections"))).intValue();
170
    
171
    for ( int i = 0; i < initConn; i++ ) {
172
        connectionPool.put( openDBConnection(), Boolean.FALSE );
173
    }    
174
    
175
    return connectionPool;
176
  }
177
  
178
  /* Utility method to get a unused Connection object from the pool */
179
  public Connection getConnection()
180
                throws SQLException, ClassNotFoundException, Exception 
181
  {
182

    
183
    Connection conn = null;
184
    Enumeration connections = connectionPool.keys();
185
    
186
    synchronized (connectionPool) {
187
      while (connections.hasMoreElements()) {
188

    
189
        conn = (Connection)connections.nextElement();
190
        Boolean b = (Boolean)connectionPool.get(conn);
191

    
192
        if (conn == null || conn.isClosed()) {
193
            // closed connection; replace it
194
            conn = openDBConnection();
195
            // update the pool to show this one taken
196
            connectionPool.put(conn, Boolean.TRUE);  
197
            
198
            return conn;
199
        } else if (b == Boolean.FALSE) {
200
            // unused connection; test if it works and get it
201
            try {
202
                conn.setAutoCommit(true);
203
            } catch (SQLException e) {
204
                // problem with the connection, replace it
205
                conn = openDBConnection();
206
            }    
207
            // update the pool to show this one taken
208
            connectionPool.put(conn, Boolean.TRUE);    
209

    
210
            return conn;
211
        }    
212
      }  
213
    }   
214
    
215
    // If we get here, there no free connections;
216
    // we need to make more
217
    int incConn = (new Integer(getOption("incrementConnections"))).intValue();
218
    int maxConn = (new Integer(getOption("maximumConnections"))).intValue();
219
    int k = connectionPool.size();
220
    if ( k >= maxConn ) {
221
        throw new Exception("The maximum of " + maxConn + 
222
                            " open db connections is reached." +
223
                            " New db connection to MetaCat" +
224
                            " cannot be established.");
225
    }    
226

    
227
    // decide how many new connections to open; no more than the maximum
228
    if ( incConn > maxConn - k ) { incConn = maxConn - k; }
229
    
230
    // get them
231
    for ( int i = 0; i < incConn; i++ ) {
232
        connectionPool.put( openDBConnection(), Boolean.FALSE );
233
    }
234

    
235
    // Recurse to get one of the new connections
236
    return getConnection();
237
  }
238
  
239
  /* Utility method to give the connection back to the pool */
240
  public void returnConnection (Connection returned) {
241
    
242
    Connection conn;
243
    Enumeration connections = connectionPool.keys();
244
    
245
    try {
246
      if ( (returned != null) && !(returned.isClosed()) ) {
247
        while (connections.hasMoreElements()) {
248
          conn = (Connection)connections.nextElement();
249
          if ( conn == returned ) {
250
            connectionPool.put( conn, Boolean.FALSE );
251
            break;
252
          }    
253
        }    
254
      }
255
    } catch (SQLException e) {}    
256
  }
257

    
258
  /* Return the size of the pool */
259
  public int getPoolSize() {
260
    return connectionPool.size();
261
  }
262
  
263
  /* Utility method to close all the connection from the pool */
264
  public void closeConnections() {
265
    
266
    Connection conn;
267
    Enumeration connections = connectionPool.keys();
268
    
269
    while (connections.hasMoreElements()) {
270
        conn = (Connection)connections.nextElement();
271
        try {
272
            if ( (conn != null) && !(conn.isClosed()) ) {
273
              conn.close();
274
            }    
275
        } catch (SQLException e) {}    
276
    }
277
  }
278
  
279
  
280
  /** Utility method to convert a file handle into a URL */
281
  public static URL fileToURL(File file)
282
  {
283
     String path = file.getAbsolutePath();
284
     String fSep = System.getProperty("file.separator");
285
     if (fSep != null && fSep.length() == 1)
286
       path = path.replace(fSep.charAt(0), '/');
287
     if (path.length() > 0 && path.charAt(0) != '/')
288
       path = '/' + path;
289
     try {
290
       return new URL("file", null, path);
291
     }
292
     catch (java.net.MalformedURLException e) {
293
       /* According to the spec this could only happen if the file
294
          protocol were not recognized. */
295
       throw new Error("unexpected MalformedURLException");
296
     }
297
  }
298

    
299
  /** 
300
   * Utility method to parse the query part of a URL into parameters. This
301
   * method assumes the format of the query par tof the url is an 
302
   * ampersand separated list of name/value pairs, with equal signs separating
303
   * the name from the value (e.g., name=tom&zip=99801 ). Returns a
304
   * has of the name value pairs, hashed on name.
305
   */
306
  public static Hashtable parseQuery(String query) throws MalformedURLException
307
  {
308
    String[][] params = new String[200][2];
309
    Hashtable parameters = new Hashtable();
310

    
311
    String temp = "";
312
    boolean ampflag = true;
313
    boolean poundflag = false;
314
    int arrcount = 0;
315

    
316
    if ( query != null ) {
317
      for (int i=0; i < query.length(); i++) { 
318

    
319
        // go throught the remainder of the query one character at a time.
320
        if (query.charAt(i) == '=') { 
321
          // if the current char is a # then the preceding should be a name
322
          if (!poundflag && ampflag) {
323
            params[arrcount][0] = temp.trim();
324
            temp = "";
325
          } else { 
326
            //if there are two #s or &s in a row throw an exception.
327
            throw new MalformedURLException("metacatURL: Two parameter names "+
328
                                            "not allowed in sequence");
329
          }
330
          poundflag = true;
331
          ampflag = false;
332
        } else if (query.charAt(i) == '&' || i == query.length()-1) { 
333
          //the text preceding the & should be the param value.
334
          if (i == query.length() - 1) { 
335
            //if at the end of the string grab the last value and append it.
336
            if (query.charAt(i) != '=') { 
337
            //ignore an extra & on the end of the string
338
              temp += query.charAt(i);
339
            }
340
          }
341
  
342
          if (!ampflag && poundflag) {
343
            params[arrcount][1] = temp.trim();
344
            parameters.put(params[arrcount][0], params[arrcount][1]);
345
            temp = "";
346
            arrcount++; //increment the array to the next row.
347
          } else { 
348
            //if there are two =s or &s in a row through an exception
349
            throw new MalformedURLException("metacatURL: Two parameter values "+
350
                                            "not allowed in sequence");
351
          }
352
          poundflag = false;
353
          ampflag = true;
354
        } else { 
355
          //get the next character in the string
356
          temp += query.charAt(i);
357
        }
358
      }
359
    }
360
    return parameters;
361
  }
362

    
363
  /** 
364
   * Utility method to print debugging messages
365
   *
366
   * @param flag an integer indicating the message number
367
   */
368
  public static void debugMessage(int flag) {
369
    if (debug) {
370
      System.err.println("DEBUG FLAG: " + flag);
371
    }
372
  }
373

    
374
  /** 
375
   * Utility method to print debugging messages
376
   *
377
   * @param flag an integer indicating the message number
378
   */
379
  public static void debugMessage(String msg) {
380
    if (debug) {
381
      System.err.println(msg);
382
    }
383
  }
384
}
(30-30/40)