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: bojilova $'
10
 *     '$Date: 2001-05-23 15:19:38 -0700 (Wed, 23 May 2001) $'
11
 * '$Revision: 747 $'
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.DBAdapter;
41

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

    
47
  public static DBAdapter 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 = (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
  /**
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
    Connection conn = null;
183
    Enumeration connections = connectionPool.keys();
184
    
185
    synchronized (connectionPool) {
186
      while (connections.hasMoreElements()) {
187

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

    
191
        if (conn == null || conn.isClosed()) {
192
            // 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
            // 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

    
209
            return conn;
210
        }    
211
      }  
212
    }   
213
    
214
    // If we get here, there no free connections;
215
    // we need to make more
216
    int incConn = (new Integer(getOption("incrementConnections"))).intValue();
217
    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
    for ( int i = 0; i < incConn; i++ ) {
231
        connectionPool.put( openDBConnection(), Boolean.FALSE );
232
    }
233

    
234
    // 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
    try {
245
      if ( (returned != null) && !(returned.isClosed()) ) {
246
        while (connections.hasMoreElements()) {
247
          conn = (Connection)connections.nextElement();
248
          if ( conn == returned ) {
249
            connectionPool.put( conn, Boolean.FALSE );
250
            break;
251
          }    
252
        }    
253
      }
254
    } catch (SQLException e) {}    
255
  }
256

    
257
  /* Return the size of the pool */
258
  public int getPoolSize() {
259
    return connectionPool.size();
260
  }
261
  
262
  /* 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
        try {
271
            if ( (conn != null) && !(conn.isClosed()) ) {
272
              conn.close();
273
            }    
274
        } catch (SQLException e) {}    
275
    }
276
  }
277
  
278
  
279
  /** 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
   * 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
    if ( query != null ) {
316
      for (int i=0; i < query.length(); i++) { 
317

    
318
        // 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
            //ignore an extra & on the end of the string
337
              temp += query.charAt(i);
338
            }
339
          }
340
  
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
        } else { 
354
          //get the next character in the string
355
          temp += query.charAt(i);
356
        }
357
      }
358
    }
359
    return parameters;
360
  }
361

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

    
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
}
(33-33/43)