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: berkley $'
10
 *     '$Date: 2002-04-10 15:51:16 -0700 (Wed, 10 Apr 2002) $'
11
 * '$Revision: 1002 $'
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
import java.util.Vector;
40

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

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

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

    
53
  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
      dbAdapter = (AbstractDatabase)createObject(getOption("dbAdapter"));
61
    } 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
  /**
86
   * 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
   */
90
  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
          PropertyResourceBundle.getBundle(propertiesFile);
116
      }
117
      String value = (String)options.handleGetObject(optionName);
118
      return value;
119
  }
120

    
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
   */
127
  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
  }
134

    
135
  /** 
136
   * 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
   * 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
     debugMessage("Opening connection: " + connection);
161
     // Connect to the database
162
     Connection conn = DriverManager.getConnection( connection, user, password);
163
     return conn;
164
  }
165

    
166
  /* 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
                throws SQLException, ClassNotFoundException, Exception 
182
  {
183

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

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

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

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

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

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

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

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

    
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
  
386
  public static void debug(String msg)
387
  {
388
    if(debug)
389
    {
390
      System.err.println(msg);
391
    }
392
  }
393
  
394
  public static Vector getOptionList(String optiontext)
395
  {
396
    Vector options = new Vector();
397
    if(optiontext.indexOf(",") == -1)
398
    {
399
      options.addElement(optiontext);
400
      return options;
401
    }
402
    
403
    while(optiontext.indexOf(",") != -1)
404
    {
405
      String s = optiontext.substring(0, optiontext.indexOf(","));
406
      options.addElement(s.trim());
407
      optiontext = optiontext.substring(optiontext.indexOf(",") + 1, 
408
                                        optiontext.length());
409
      if(optiontext.indexOf(",") == -1)
410
      { //catch the last list entry
411
        options.addElement(optiontext.trim());
412
      }
413
    }
414
    return options;
415
  }
416
  
417
  /** Normalizes the given string. Taken from configXML.java*/
418
  public static String normalize(String s)
419
  {
420
    StringBuffer str = new StringBuffer();
421

    
422
    int len = (s != null) ? s.length() : 0;
423
    for (int i = 0; i < len; i++)
424
    {
425
      char ch = s.charAt(i);
426
      switch (ch)
427
      {
428
      case '<':
429
      {
430
        str.append("&lt;");
431
        break;
432
      }
433
        case '>':
434
      {
435
        str.append("&gt;");
436
        break;
437
      }
438
      case '&':
439
      {
440
        str.append("&amp;");
441
        break;
442
      }
443
      case '"':
444
      {
445
        str.append("&quot;");
446
        break;
447
      }
448
      case '\r':
449
      case '\n':
450
      {
451
        // else, default append char
452
      }
453
      default:
454
      {
455
        str.append(ch);
456
      }
457
      }
458
    }
459
    return (str.toString());
460
  } 
461
  
462
  /** 
463
   * Utility method to get docid from a given string
464
   * @param string, the given string should be these two format:
465
   *              1) str1.str2  in this case docid= str1.str2
466
   *              2) str1.str2.str3, in this case docid =str1.str2
467
   * @param the sperator char
468
   */
469
  public static String getDocIdFromString(String str)
470
  {
471
    String docId = null;
472
    int dotNumber = 0;//count how many dots in given string
473
    int indexOfLastDot = 0;
474
    
475
    //assume that seperator is one charactor string
476
    char seperator=getOption("accNumSeparator").charAt(0);
477
     
478
    for (int i=0; i<str.length(); i++)
479
    {
480
      if ( str.charAt(i)==seperator)
481
      {
482
        dotNumber++;//count how many dots
483
        indexOfLastDot=i;//keep the last dot postion
484
      }
485
    }//for
486
    
487
    //The string formatt is wrong, because it has more than two or less than
488
    //one seperator
489
    if ( dotNumber>2 || dotNumber < 1)
490
    {
491
      docId=null;
492
    }
493
    else if (dotNumber == 2) //the case for str1.str2.str3
494
    {
495
       docId=str.substring(0, indexOfLastDot);
496
    }
497
    else if (dotNumber == 1) //the case for str1.str2
498
    {
499
      docId=str;
500
    }
501
    
502
    return docId;  
503
  }//getDocIdFromString
504

    
505
  /** 
506
   * Utility method to get version number from a given string
507
   * @param string, the given string should be these two format:
508
   *              1) str1.str2(no version)  version =-1;
509
   *              2) str1.str2.str3, in this case version = str3;
510
   *              3) other, vresion =-2
511
   * @param the sperator char
512
   */
513
  public static int getVersionFromString(String str)
514
                                throws NumberFormatException
515
  {
516
    int version=-1;
517
    String versionString=null;
518
    int dotNumber = 0;//count how many dots in given string
519
    int indexOfLastDot = 0;
520
    
521
    //assume that seperator is one charactor string
522
    char seperator=getOption("accNumSeparator").charAt(0);
523
    
524
    for (int i=0; i<str.length(); i++)
525
    {
526
      if ( str.charAt(i)==seperator)
527
      {
528
        dotNumber++;//count how many dots
529
        indexOfLastDot=i;//keep the last dot postion
530
      }
531
    }//for
532
    
533
    //The string formatt is wrong, because it has more than two or less than
534
    //one seperator
535
    if ( dotNumber>2 || dotNumber < 1)
536
    {
537
      version=-2;
538
    }
539
    else if (dotNumber == 2) //the case for str1.str2.str3
540
    {
541
       versionString=str.substring((indexOfLastDot+1), str.length());
542
       version=Integer.parseInt(versionString);
543
    }
544
    else if (dotNumber == 1) //the case for str1.str2
545
    {
546
      version=-1;
547
    }
548
    
549
    return version;  
550
  }//getVersionFromString
551
  
552
}
(30-30/40)