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 887 berkley
import java.util.Vector;
40 50 jones
41 777 bojilova
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
42 747 bojilova
43 50 jones
/**
44
 * A suite of utility classes for the metadata catalog server
45
 */
46
public class MetaCatUtil {
47
48 777 bojilova
  public static AbstractDatabase dbAdapter;
49 747 bojilova
  private static PropertyResourceBundle options = null;
50
  private static String propertiesFile = "edu.ucsb.nceas.metacat.metacat";
51 203 jones
  private static boolean debug = false;
52 109 bojilova
53 747 bojilova
  private Hashtable connectionPool = new Hashtable();
54
55
  /**
56
   * Determine our db adapter class and create an instance of that class
57
   */
58
  static {
59
    try {
60 777 bojilova
      dbAdapter = (AbstractDatabase)createObject(getOption("dbAdapter"));
61 747 bojilova
    } catch (Exception e) {
62
      System.err.println("Error in MetaCatUtil static block:" + e.getMessage());
63
    }
64
  }
65
66
// CONSTRUCTORS NOT NEEDED
67
//  /**
68
//   * Construct an instance of the utility class
69
//   */
70
//  public MetaCatUtil() {
71
//
72
//    options = (PropertyResourceBundle)
73
//          PropertyResourceBundle.getBundle(propertiesFile);
74
//  }
75
//
76
//  /**
77
//   * This constructor allows the usage of a different properties file
78
//   * @param propFile the properties file that you wish to use.
79
//   */
80
//  public MetaCatUtil(String propFile)  {
81
//
82
//    propertiesFile = propFile;
83
//  }
84
85 184 jones
  /**
86 747 bojilova
   * Instantiate a class using the name of the class at runtime
87
   *
88
   * @param className the fully qualified name of the class to instantiate
89 184 jones
   */
90 747 bojilova
  public static Object createObject(String className) throws Exception {
91
92
    Object object = null;
93
    try {
94
      Class classDefinition = Class.forName(className);
95
      object = classDefinition.newInstance();
96
    } catch (InstantiationException e) {
97
      throw e;
98
    } catch (IllegalAccessException e) {
99
      throw e;
100
    } catch (ClassNotFoundException e) {
101
      throw e;
102
    }
103
    return object;
104
  }
105
106
  /**
107
   * Utility method to get an option value from the properties file
108
   *
109
   * @param optionName the name of the option requested
110
   */
111
  public static String getOption(String optionName) {
112
      // Get the configuration file information
113
      if (options == null) {
114
        options = (PropertyResourceBundle)
115 184 jones
          PropertyResourceBundle.getBundle(propertiesFile);
116 747 bojilova
      }
117
      String value = (String)options.handleGetObject(optionName);
118
      return value;
119 184 jones
  }
120 747 bojilova
121
  /**
122
   * Utility method to get an option value from a properties file
123
   *
124
   * @param optionName the name of the option requested
125
   * @param propFile the name of the file where to get the properties from
126 354 berkley
   */
127 747 bojilova
  public String getOption(String optionName, String propFile) {
128
    // Get the configuration file information
129
    PropertyResourceBundle options = (PropertyResourceBundle)
130
                                     PropertyResourceBundle.getBundle(propFile);
131
    String value = (String)options.handleGetObject(optionName);
132
    return value;
133 354 berkley
  }
134 184 jones
135 50 jones
  /**
136 184 jones
   * Utility method to establish a JDBC database connection using connection
137
   * info from the properties file
138
   */
139
  public Connection openDBConnection()
140
                throws SQLException, ClassNotFoundException {
141
    return openDBConnection(getOption("dbDriver"), getOption("defaultDB"),
142
                     getOption("user"), getOption("password"));
143
  }
144
145
  /**
146 50 jones
   * Utility method to establish a JDBC database connection
147
   *
148
   * @param dbDriver the string representing the database driver
149
   * @param connection the string representing the database connectin parameters
150
   * @param user name of the user to use for database connection
151
   * @param password password for the user to use for database connection
152
   */
153
  public static Connection openDBConnection(String dbDriver, String connection,
154
                String user, String password)
155
                throws SQLException, ClassNotFoundException {
156
157
     // Load the Oracle JDBC driver
158
     Class.forName (dbDriver);
159
160 329 jones
     debugMessage("Opening connection: " + connection);
161 50 jones
     // Connect to the database
162
     Connection conn = DriverManager.getConnection( connection, user, password);
163
     return conn;
164
  }
165 184 jones
166 309 bojilova
  /* Utility method to create and return a pool of Connection objects */
167
  public Hashtable getConnectionPool()
168
                throws SQLException, ClassNotFoundException {
169
170
    int initConn = (new Integer(getOption("initialConnections"))).intValue();
171
172
    for ( int i = 0; i < initConn; i++ ) {
173
        connectionPool.put( openDBConnection(), Boolean.FALSE );
174
    }
175
176
    return connectionPool;
177
  }
178
179
  /* Utility method to get a unused Connection object from the pool */
180
  public Connection getConnection()
181 845 jones
                throws SQLException, ClassNotFoundException, Exception
182
  {
183 309 bojilova
184
    Connection conn = null;
185
    Enumeration connections = connectionPool.keys();
186
187
    synchronized (connectionPool) {
188
      while (connections.hasMoreElements()) {
189 320 bojilova
190 309 bojilova
        conn = (Connection)connections.nextElement();
191
        Boolean b = (Boolean)connectionPool.get(conn);
192 320 bojilova
193 739 bojilova
        if (conn == null || conn.isClosed()) {
194 320 bojilova
            // closed connection; replace it
195
            conn = openDBConnection();
196
            // update the pool to show this one taken
197
            connectionPool.put(conn, Boolean.TRUE);
198
199
            return conn;
200
        } else if (b == Boolean.FALSE) {
201 309 bojilova
            // unused connection; test if it works and get it
202
            try {
203
                conn.setAutoCommit(true);
204
            } catch (SQLException e) {
205
                // problem with the connection, replace it
206
                conn = openDBConnection();
207
            }
208
            // update the pool to show this one taken
209
            connectionPool.put(conn, Boolean.TRUE);
210 320 bojilova
211 309 bojilova
            return conn;
212
        }
213
      }
214 320 bojilova
    }
215 309 bojilova
216
    // If we get here, there no free connections;
217
    // we need to make more
218
    int incConn = (new Integer(getOption("incrementConnections"))).intValue();
219 320 bojilova
    int maxConn = (new Integer(getOption("maximumConnections"))).intValue();
220
    int k = connectionPool.size();
221
    if ( k >= maxConn ) {
222
        throw new Exception("The maximum of " + maxConn +
223
                            " open db connections is reached." +
224
                            " New db connection to MetaCat" +
225
                            " cannot be established.");
226
    }
227
228
    // decide how many new connections to open; no more than the maximum
229
    if ( incConn > maxConn - k ) { incConn = maxConn - k; }
230
231
    // get them
232 309 bojilova
    for ( int i = 0; i < incConn; i++ ) {
233
        connectionPool.put( openDBConnection(), Boolean.FALSE );
234
    }
235 320 bojilova
236 309 bojilova
    // Recurse to get one of the new connections
237
    return getConnection();
238
  }
239
240
  /* Utility method to give the connection back to the pool */
241
  public void returnConnection (Connection returned) {
242
243
    Connection conn;
244
    Enumeration connections = connectionPool.keys();
245
246 739 bojilova
    try {
247
      if ( (returned != null) && !(returned.isClosed()) ) {
248
        while (connections.hasMoreElements()) {
249
          conn = (Connection)connections.nextElement();
250
          if ( conn == returned ) {
251 309 bojilova
            connectionPool.put( conn, Boolean.FALSE );
252
            break;
253 739 bojilova
          }
254 309 bojilova
        }
255 739 bojilova
      }
256
    } catch (SQLException e) {}
257 309 bojilova
  }
258 320 bojilova
259 464 bojilova
  /* Return the size of the pool */
260
  public int getPoolSize() {
261
    return connectionPool.size();
262
  }
263
264 320 bojilova
  /* Utility method to close all the connection from the pool */
265
  public void closeConnections() {
266
267
    Connection conn;
268
    Enumeration connections = connectionPool.keys();
269
270
    while (connections.hasMoreElements()) {
271
        conn = (Connection)connections.nextElement();
272 739 bojilova
        try {
273
            if ( (conn != null) && !(conn.isClosed()) ) {
274
              conn.close();
275
            }
276
        } catch (SQLException e) {}
277 320 bojilova
    }
278
  }
279 309 bojilova
280
281 185 jones
  /** Utility method to convert a file handle into a URL */
282
  public static URL fileToURL(File file)
283
  {
284
     String path = file.getAbsolutePath();
285
     String fSep = System.getProperty("file.separator");
286
     if (fSep != null && fSep.length() == 1)
287
       path = path.replace(fSep.charAt(0), '/');
288
     if (path.length() > 0 && path.charAt(0) != '/')
289
       path = '/' + path;
290
     try {
291
       return new URL("file", null, path);
292
     }
293
     catch (java.net.MalformedURLException e) {
294
       /* According to the spec this could only happen if the file
295
          protocol were not recognized. */
296
       throw new Error("unexpected MalformedURLException");
297
     }
298
  }
299
300
  /**
301 566 jones
   * Utility method to parse the query part of a URL into parameters. This
302
   * method assumes the format of the query par tof the url is an
303
   * ampersand separated list of name/value pairs, with equal signs separating
304
   * the name from the value (e.g., name=tom&zip=99801 ). Returns a
305
   * has of the name value pairs, hashed on name.
306
   */
307
  public static Hashtable parseQuery(String query) throws MalformedURLException
308
  {
309
    String[][] params = new String[200][2];
310
    Hashtable parameters = new Hashtable();
311
312
    String temp = "";
313
    boolean ampflag = true;
314
    boolean poundflag = false;
315
    int arrcount = 0;
316
317 731 bojilova
    if ( query != null ) {
318
      for (int i=0; i < query.length(); i++) {
319 566 jones
320 731 bojilova
        // go throught the remainder of the query one character at a time.
321
        if (query.charAt(i) == '=') {
322
          // if the current char is a # then the preceding should be a name
323
          if (!poundflag && ampflag) {
324
            params[arrcount][0] = temp.trim();
325
            temp = "";
326
          } else {
327
            //if there are two #s or &s in a row throw an exception.
328
            throw new MalformedURLException("metacatURL: Two parameter names "+
329
                                            "not allowed in sequence");
330
          }
331
          poundflag = true;
332
          ampflag = false;
333
        } else if (query.charAt(i) == '&' || i == query.length()-1) {
334
          //the text preceding the & should be the param value.
335
          if (i == query.length() - 1) {
336
            //if at the end of the string grab the last value and append it.
337
            if (query.charAt(i) != '=') {
338 566 jones
            //ignore an extra & on the end of the string
339 731 bojilova
              temp += query.charAt(i);
340
            }
341 566 jones
          }
342 731 bojilova
343
          if (!ampflag && poundflag) {
344
            params[arrcount][1] = temp.trim();
345
            parameters.put(params[arrcount][0], params[arrcount][1]);
346
            temp = "";
347
            arrcount++; //increment the array to the next row.
348
          } else {
349
            //if there are two =s or &s in a row through an exception
350
            throw new MalformedURLException("metacatURL: Two parameter values "+
351
                                            "not allowed in sequence");
352
          }
353
          poundflag = false;
354
          ampflag = true;
355 566 jones
        } else {
356 731 bojilova
          //get the next character in the string
357
          temp += query.charAt(i);
358 566 jones
        }
359
      }
360
    }
361
    return parameters;
362
  }
363
364
  /**
365 185 jones
   * Utility method to print debugging messages
366
   *
367
   * @param flag an integer indicating the message number
368
   */
369 203 jones
  public static void debugMessage(int flag) {
370
    if (debug) {
371
      System.err.println("DEBUG FLAG: " + flag);
372
    }
373 185 jones
  }
374 203 jones
375
  /**
376
   * Utility method to print debugging messages
377
   *
378
   * @param flag an integer indicating the message number
379
   */
380
  public static void debugMessage(String msg) {
381
    if (debug) {
382
      System.err.println(msg);
383
    }
384
  }
385 887 berkley
386
  public static Vector getOptionList(String optiontext)
387
  {
388
    Vector options = new Vector();
389
    if(optiontext.indexOf(",") == -1)
390
    {
391
      options.addElement(optiontext);
392
      return options;
393
    }
394
395
    while(optiontext.indexOf(",") != -1)
396
    {
397
      String s = optiontext.substring(0, optiontext.indexOf(","));
398
      options.addElement(s.trim());
399
      optiontext = optiontext.substring(optiontext.indexOf(",") + 1,
400
                                        optiontext.length());
401
      if(optiontext.indexOf(",") == -1)
402
      { //catch the last list entry
403
        options.addElement(optiontext.trim());
404
      }
405
    }
406
    return options;
407
  }
408 894 berkley
409
  /** Normalizes the given string. Taken from configXML.java*/
410
  public static String normalize(String s)
411
  {
412
    StringBuffer str = new StringBuffer();
413
414
    int len = (s != null) ? s.length() : 0;
415
    for (int i = 0; i < len; i++)
416
    {
417
      char ch = s.charAt(i);
418
      switch (ch)
419
      {
420
      case '<':
421
      {
422
        str.append("&lt;");
423
        break;
424
      }
425
        case '>':
426
      {
427
        str.append("&gt;");
428
        break;
429
      }
430
      case '&':
431
      {
432
        str.append("&amp;");
433
        break;
434
      }
435
      case '"':
436
      {
437
        str.append("&quot;");
438
        break;
439
      }
440
      case '\r':
441
      case '\n':
442
      {
443
        // else, default append char
444
      }
445
      default:
446
      {
447
        str.append(ch);
448
      }
449
      }
450
    }
451
    return (str.toString());
452
  }
453
454 50 jones
}