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 777 bojilova
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
41 747 bojilova
42 50 jones
/**
43
 * A suite of utility classes for the metadata catalog server
44
 */
45
public class MetaCatUtil {
46
47 777 bojilova
  public static AbstractDatabase dbAdapter;
48 747 bojilova
  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 777 bojilova
      dbAdapter = (AbstractDatabase)createObject(getOption("dbAdapter"));
60 747 bojilova
    } 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 845 jones
                throws SQLException, ClassNotFoundException, Exception
181
  {
182 309 bojilova
183
    Connection conn = null;
184
    Enumeration connections = connectionPool.keys();
185
186
    synchronized (connectionPool) {
187
      while (connections.hasMoreElements()) {
188 320 bojilova
189 309 bojilova
        conn = (Connection)connections.nextElement();
190
        Boolean b = (Boolean)connectionPool.get(conn);
191 320 bojilova
192 739 bojilova
        if (conn == null || conn.isClosed()) {
193 320 bojilova
            // 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 309 bojilova
            // 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 320 bojilova
210 309 bojilova
            return conn;
211
        }
212
      }
213 320 bojilova
    }
214 309 bojilova
215
    // If we get here, there no free connections;
216
    // we need to make more
217
    int incConn = (new Integer(getOption("incrementConnections"))).intValue();
218 320 bojilova
    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 309 bojilova
    for ( int i = 0; i < incConn; i++ ) {
232
        connectionPool.put( openDBConnection(), Boolean.FALSE );
233
    }
234 320 bojilova
235 309 bojilova
    // 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 739 bojilova
    try {
246
      if ( (returned != null) && !(returned.isClosed()) ) {
247
        while (connections.hasMoreElements()) {
248
          conn = (Connection)connections.nextElement();
249
          if ( conn == returned ) {
250 309 bojilova
            connectionPool.put( conn, Boolean.FALSE );
251
            break;
252 739 bojilova
          }
253 309 bojilova
        }
254 739 bojilova
      }
255
    } catch (SQLException e) {}
256 309 bojilova
  }
257 320 bojilova
258 464 bojilova
  /* Return the size of the pool */
259
  public int getPoolSize() {
260
    return connectionPool.size();
261
  }
262
263 320 bojilova
  /* 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 739 bojilova
        try {
272
            if ( (conn != null) && !(conn.isClosed()) ) {
273
              conn.close();
274
            }
275
        } catch (SQLException e) {}
276 320 bojilova
    }
277
  }
278 309 bojilova
279
280 185 jones
  /** 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 566 jones
   * 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 731 bojilova
    if ( query != null ) {
317
      for (int i=0; i < query.length(); i++) {
318 566 jones
319 731 bojilova
        // 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 566 jones
            //ignore an extra & on the end of the string
338 731 bojilova
              temp += query.charAt(i);
339
            }
340 566 jones
          }
341 731 bojilova
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 566 jones
        } else {
355 731 bojilova
          //get the next character in the string
356
          temp += query.charAt(i);
357 566 jones
        }
358
      }
359
    }
360
    return parameters;
361
  }
362
363
  /**
364 185 jones
   * Utility method to print debugging messages
365
   *
366
   * @param flag an integer indicating the message number
367
   */
368 203 jones
  public static void debugMessage(int flag) {
369
    if (debug) {
370
      System.err.println("DEBUG FLAG: " + flag);
371
    }
372 185 jones
  }
373 203 jones
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 50 jones
}