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 1002 berkley
  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 1053 tao
   /**
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 566 jones
  /**
395 185 jones
   * Utility method to print debugging messages
396
   *
397
   * @param flag an integer indicating the message number
398
   */
399 203 jones
  public static void debugMessage(int flag) {
400
    if (debug) {
401
      System.err.println("DEBUG FLAG: " + flag);
402
    }
403 185 jones
  }
404 203 jones
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 887 berkley
416 1000 berkley
  public static void debug(String msg)
417
  {
418
    if(debug)
419
    {
420
      System.err.println(msg);
421
    }
422
  }
423
424 1053 tao
425
426 887 berkley
  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 894 berkley
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 942 tao
  /**
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 1013 tao
   /**
585
   * Method to get the name of local replication server
586
   */
587 1060 tao
   public static String getLocalReplicationServerName()
588 1013 tao
   {
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 50 jones
}