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: tao $'
10
 *     '$Date: 2002-05-06 11:30:14 -0700 (Mon, 06 May 2002) $'
11
 * '$Revision: 1053 $'
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. User can set debug level
366
   * for this message. The number is fewer, the message is more important
367
   * @param msg, the content of the message
368
   * @param debugLevel, an integer indicating the message debug leve
369
   */
370
  public static void debugMessage(String msg, int debugLevel) 
371
  {
372
    int limit = 1;
373
    try 
374
    {
375
      limit=Integer.parseInt(getOption("debuglevel"));
376
     
377
    }
378
    catch (Exception e)
379
    {
380
      System.out.println(e.getMessage());
381
    }
382
    //don't allow the user set debugLevel less than or equals 0
383
    if (debugLevel<=0)
384
    {
385
      debugLevel=1;
386
    }
387
    
388
    if (debugLevel < limit) 
389
    {
390
      System.err.println(msg);
391
    }
392
  }
393
  
394
  /** 
395
   * Utility method to print debugging messages
396
   *
397
   * @param flag an integer indicating the message number
398
   */
399
  public static void debugMessage(int flag) {
400
    if (debug) {
401
      System.err.println("DEBUG FLAG: " + flag);
402
    }
403
  }
404

    
405
  /** 
406
   * Utility method to print debugging messages
407
   *
408
   * @param flag an integer indicating the message number
409
   */
410
  public static void debugMessage(String msg) {
411
    if (debug) {
412
      System.err.println(msg);
413
    }
414
  }
415
  
416
  public static void debug(String msg)
417
  {
418
    if(debug)
419
    {
420
      System.err.println(msg);
421
    }
422
  }
423
  
424
  
425
  
426
  public static Vector getOptionList(String optiontext)
427
  {
428
    Vector options = new Vector();
429
    if(optiontext.indexOf(",") == -1)
430
    {
431
      options.addElement(optiontext);
432
      return options;
433
    }
434
    
435
    while(optiontext.indexOf(",") != -1)
436
    {
437
      String s = optiontext.substring(0, optiontext.indexOf(","));
438
      options.addElement(s.trim());
439
      optiontext = optiontext.substring(optiontext.indexOf(",") + 1, 
440
                                        optiontext.length());
441
      if(optiontext.indexOf(",") == -1)
442
      { //catch the last list entry
443
        options.addElement(optiontext.trim());
444
      }
445
    }
446
    return options;
447
  }
448
  
449
  /** Normalizes the given string. Taken from configXML.java*/
450
  public static String normalize(String s)
451
  {
452
    StringBuffer str = new StringBuffer();
453

    
454
    int len = (s != null) ? s.length() : 0;
455
    for (int i = 0; i < len; i++)
456
    {
457
      char ch = s.charAt(i);
458
      switch (ch)
459
      {
460
      case '<':
461
      {
462
        str.append("&lt;");
463
        break;
464
      }
465
        case '>':
466
      {
467
        str.append("&gt;");
468
        break;
469
      }
470
      case '&':
471
      {
472
        str.append("&amp;");
473
        break;
474
      }
475
      case '"':
476
      {
477
        str.append("&quot;");
478
        break;
479
      }
480
      case '\r':
481
      case '\n':
482
      {
483
        // else, default append char
484
      }
485
      default:
486
      {
487
        str.append(ch);
488
      }
489
      }
490
    }
491
    return (str.toString());
492
  } 
493
  
494
  /** 
495
   * Utility method to get docid from a given string
496
   * @param string, the given string should be these two format:
497
   *              1) str1.str2  in this case docid= str1.str2
498
   *              2) str1.str2.str3, in this case docid =str1.str2
499
   * @param the sperator char
500
   */
501
  public static String getDocIdFromString(String str)
502
  {
503
    String docId = null;
504
    int dotNumber = 0;//count how many dots in given string
505
    int indexOfLastDot = 0;
506
    
507
    //assume that seperator is one charactor string
508
    char seperator=getOption("accNumSeparator").charAt(0);
509
     
510
    for (int i=0; i<str.length(); i++)
511
    {
512
      if ( str.charAt(i)==seperator)
513
      {
514
        dotNumber++;//count how many dots
515
        indexOfLastDot=i;//keep the last dot postion
516
      }
517
    }//for
518
    
519
    //The string formatt is wrong, because it has more than two or less than
520
    //one seperator
521
    if ( dotNumber>2 || dotNumber < 1)
522
    {
523
      docId=null;
524
    }
525
    else if (dotNumber == 2) //the case for str1.str2.str3
526
    {
527
       docId=str.substring(0, indexOfLastDot);
528
    }
529
    else if (dotNumber == 1) //the case for str1.str2
530
    {
531
      docId=str;
532
    }
533
    
534
    return docId;  
535
  }//getDocIdFromString
536

    
537
  /** 
538
   * Utility method to get version number from a given string
539
   * @param string, the given string should be these two format:
540
   *              1) str1.str2(no version)  version =-1;
541
   *              2) str1.str2.str3, in this case version = str3;
542
   *              3) other, vresion =-2
543
   * @param the sperator char
544
   */
545
  public static int getVersionFromString(String str)
546
                                throws NumberFormatException
547
  {
548
    int version=-1;
549
    String versionString=null;
550
    int dotNumber = 0;//count how many dots in given string
551
    int indexOfLastDot = 0;
552
    
553
    //assume that seperator is one charactor string
554
    char seperator=getOption("accNumSeparator").charAt(0);
555
    
556
    for (int i=0; i<str.length(); i++)
557
    {
558
      if ( str.charAt(i)==seperator)
559
      {
560
        dotNumber++;//count how many dots
561
        indexOfLastDot=i;//keep the last dot postion
562
      }
563
    }//for
564
    
565
    //The string formatt is wrong, because it has more than two or less than
566
    //one seperator
567
    if ( dotNumber>2 || dotNumber < 1)
568
    {
569
      version=-2;
570
    }
571
    else if (dotNumber == 2) //the case for str1.str2.str3
572
    {
573
       versionString=str.substring((indexOfLastDot+1), str.length());
574
       version=Integer.parseInt(versionString);
575
    }
576
    else if (dotNumber == 1) //the case for str1.str2
577
    {
578
      version=-1;
579
    }
580
    
581
    return version;  
582
  }//getVersionFromString
583
  
584
   /**
585
   * Method to get the name of local replication server
586
   */
587
   public String getLocalReplicationServerName()
588
   {
589
     String replicationServerName=null;
590
     String serverHost=null;
591
     serverHost=getOption("server");
592
     // append "context/servelet/replication" to the host name
593
     replicationServerName=serverHost+getOption("replicationpath");
594
     return replicationServerName;
595
       
596
   }
597
  
598
}
(31-31/41)