Project

General

Profile

1 51 jones
/**
2 203 jones
 *  '$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 309 bojilova
 *    Authors: Matt Jones, Jivka Bojilova
7 349 jones
 *    Release: @release@
8 51 jones
 *
9 203 jones
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
12 669 jones
 *
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 51 jones
 */
27
28
package edu.ucsb.nceas.metacat;
29
30 185 jones
import java.io.File;
31
import java.net.URL;
32
import java.net.MalformedURLException;
33 50 jones
import java.sql.Connection;
34
import java.sql.DriverManager;
35
import java.sql.SQLException;
36 184 jones
import java.util.PropertyResourceBundle;
37 309 bojilova
import java.util.Hashtable;
38
import java.util.Enumeration;
39 50 jones
40 747 bojilova
import edu.ucsb.nceas.dbadapter.DBAdapter;
41
42 50 jones
/**
43
 * A suite of utility classes for the metadata catalog server
44
 */
45
public class MetaCatUtil {
46
47 747 bojilova
  public static DBAdapter dbAdapter;
48
  private static PropertyResourceBundle options = null;
49
  private static String propertiesFile = "edu.ucsb.nceas.metacat.metacat";
50 203 jones
  private static boolean debug = false;
51 109 bojilova
52 747 bojilova
  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 = (DBAdapter)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 184 jones
  /**
85 747 bojilova
   * 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 184 jones
   */
89 747 bojilova
  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 184 jones
          PropertyResourceBundle.getBundle(propertiesFile);
115 747 bojilova
      }
116
      String value = (String)options.handleGetObject(optionName);
117
      return value;
118 184 jones
  }
119 747 bojilova
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 354 berkley
   */
126 747 bojilova
  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 354 berkley
  }
133 184 jones
134 50 jones
  /**
135 184 jones
   * 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 50 jones
   * 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 329 jones
     debugMessage("Opening connection: " + connection);
160 50 jones
     // Connect to the database
161
     Connection conn = DriverManager.getConnection( connection, user, password);
162
     return conn;
163
  }
164 184 jones
165 309 bojilova
  /* 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 320 bojilova
                throws SQLException, ClassNotFoundException, Exception {
181 309 bojilova
182
    Connection conn = null;
183
    Enumeration connections = connectionPool.keys();
184
185
    synchronized (connectionPool) {
186
      while (connections.hasMoreElements()) {
187 320 bojilova
188 309 bojilova
        conn = (Connection)connections.nextElement();
189
        Boolean b = (Boolean)connectionPool.get(conn);
190 320 bojilova
191 739 bojilova
        if (conn == null || conn.isClosed()) {
192 320 bojilova
            // closed connection; replace it
193
            conn = openDBConnection();
194
            // update the pool to show this one taken
195
            connectionPool.put(conn, Boolean.TRUE);
196
197
            return conn;
198
        } else if (b == Boolean.FALSE) {
199 309 bojilova
            // unused connection; test if it works and get it
200
            try {
201
                conn.setAutoCommit(true);
202
            } catch (SQLException e) {
203
                // problem with the connection, replace it
204
                conn = openDBConnection();
205
            }
206
            // update the pool to show this one taken
207
            connectionPool.put(conn, Boolean.TRUE);
208 320 bojilova
209 309 bojilova
            return conn;
210
        }
211
      }
212 320 bojilova
    }
213 309 bojilova
214
    // If we get here, there no free connections;
215
    // we need to make more
216
    int incConn = (new Integer(getOption("incrementConnections"))).intValue();
217 320 bojilova
    int maxConn = (new Integer(getOption("maximumConnections"))).intValue();
218
    int k = connectionPool.size();
219
    if ( k >= maxConn ) {
220
        throw new Exception("The maximum of " + maxConn +
221
                            " open db connections is reached." +
222
                            " New db connection to MetaCat" +
223
                            " cannot be established.");
224
    }
225
226
    // decide how many new connections to open; no more than the maximum
227
    if ( incConn > maxConn - k ) { incConn = maxConn - k; }
228
229
    // get them
230 309 bojilova
    for ( int i = 0; i < incConn; i++ ) {
231
        connectionPool.put( openDBConnection(), Boolean.FALSE );
232
    }
233 320 bojilova
234 309 bojilova
    // Recurse to get one of the new connections
235
    return getConnection();
236
  }
237
238
  /* Utility method to give the connection back to the pool */
239
  public void returnConnection (Connection returned) {
240
241
    Connection conn;
242
    Enumeration connections = connectionPool.keys();
243
244 739 bojilova
    try {
245
      if ( (returned != null) && !(returned.isClosed()) ) {
246
        while (connections.hasMoreElements()) {
247
          conn = (Connection)connections.nextElement();
248
          if ( conn == returned ) {
249 309 bojilova
            connectionPool.put( conn, Boolean.FALSE );
250
            break;
251 739 bojilova
          }
252 309 bojilova
        }
253 739 bojilova
      }
254
    } catch (SQLException e) {}
255 309 bojilova
  }
256 320 bojilova
257 464 bojilova
  /* Return the size of the pool */
258
  public int getPoolSize() {
259
    return connectionPool.size();
260
  }
261
262 320 bojilova
  /* Utility method to close all the connection from the pool */
263
  public void closeConnections() {
264
265
    Connection conn;
266
    Enumeration connections = connectionPool.keys();
267
268
    while (connections.hasMoreElements()) {
269
        conn = (Connection)connections.nextElement();
270 739 bojilova
        try {
271
            if ( (conn != null) && !(conn.isClosed()) ) {
272
              conn.close();
273
            }
274
        } catch (SQLException e) {}
275 320 bojilova
    }
276
  }
277 309 bojilova
278
279 185 jones
  /** Utility method to convert a file handle into a URL */
280
  public static URL fileToURL(File file)
281
  {
282
     String path = file.getAbsolutePath();
283
     String fSep = System.getProperty("file.separator");
284
     if (fSep != null && fSep.length() == 1)
285
       path = path.replace(fSep.charAt(0), '/');
286
     if (path.length() > 0 && path.charAt(0) != '/')
287
       path = '/' + path;
288
     try {
289
       return new URL("file", null, path);
290
     }
291
     catch (java.net.MalformedURLException e) {
292
       /* According to the spec this could only happen if the file
293
          protocol were not recognized. */
294
       throw new Error("unexpected MalformedURLException");
295
     }
296
  }
297
298
  /**
299 566 jones
   * Utility method to parse the query part of a URL into parameters. This
300
   * method assumes the format of the query par tof the url is an
301
   * ampersand separated list of name/value pairs, with equal signs separating
302
   * the name from the value (e.g., name=tom&zip=99801 ). Returns a
303
   * has of the name value pairs, hashed on name.
304
   */
305
  public static Hashtable parseQuery(String query) throws MalformedURLException
306
  {
307
    String[][] params = new String[200][2];
308
    Hashtable parameters = new Hashtable();
309
310
    String temp = "";
311
    boolean ampflag = true;
312
    boolean poundflag = false;
313
    int arrcount = 0;
314
315 731 bojilova
    if ( query != null ) {
316
      for (int i=0; i < query.length(); i++) {
317 566 jones
318 731 bojilova
        // go throught the remainder of the query one character at a time.
319
        if (query.charAt(i) == '=') {
320
          // if the current char is a # then the preceding should be a name
321
          if (!poundflag && ampflag) {
322
            params[arrcount][0] = temp.trim();
323
            temp = "";
324
          } else {
325
            //if there are two #s or &s in a row throw an exception.
326
            throw new MalformedURLException("metacatURL: Two parameter names "+
327
                                            "not allowed in sequence");
328
          }
329
          poundflag = true;
330
          ampflag = false;
331
        } else if (query.charAt(i) == '&' || i == query.length()-1) {
332
          //the text preceding the & should be the param value.
333
          if (i == query.length() - 1) {
334
            //if at the end of the string grab the last value and append it.
335
            if (query.charAt(i) != '=') {
336 566 jones
            //ignore an extra & on the end of the string
337 731 bojilova
              temp += query.charAt(i);
338
            }
339 566 jones
          }
340 731 bojilova
341
          if (!ampflag && poundflag) {
342
            params[arrcount][1] = temp.trim();
343
            parameters.put(params[arrcount][0], params[arrcount][1]);
344
            temp = "";
345
            arrcount++; //increment the array to the next row.
346
          } else {
347
            //if there are two =s or &s in a row through an exception
348
            throw new MalformedURLException("metacatURL: Two parameter values "+
349
                                            "not allowed in sequence");
350
          }
351
          poundflag = false;
352
          ampflag = true;
353 566 jones
        } else {
354 731 bojilova
          //get the next character in the string
355
          temp += query.charAt(i);
356 566 jones
        }
357
      }
358
    }
359
    return parameters;
360
  }
361
362
  /**
363 185 jones
   * Utility method to print debugging messages
364
   *
365
   * @param flag an integer indicating the message number
366
   */
367 203 jones
  public static void debugMessage(int flag) {
368
    if (debug) {
369
      System.err.println("DEBUG FLAG: " + flag);
370
    }
371 185 jones
  }
372 203 jones
373
  /**
374
   * Utility method to print debugging messages
375
   *
376
   * @param flag an integer indicating the message number
377
   */
378
  public static void debugMessage(String msg) {
379
    if (debug) {
380
      System.err.println(msg);
381
    }
382
  }
383 50 jones
}