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
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2009-08-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
10
 * '$Revision: 5015 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.util;
28

    
29
import java.io.File;
30
import java.io.FileInputStream;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.io.PrintWriter;
34
import java.net.MalformedURLException;
35
import java.util.Hashtable;
36
import java.util.Stack;
37
import java.util.Vector;
38

    
39
import org.apache.log4j.Logger;
40

    
41
import com.oreilly.servlet.multipart.FilePart;
42

    
43
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
44
import edu.ucsb.nceas.metacat.DBSAXHandler;
45
import edu.ucsb.nceas.metacat.NodeRecord;
46
import edu.ucsb.nceas.metacat.service.PropertyService;
47
import edu.ucsb.nceas.metacat.service.ServiceService;
48
import edu.ucsb.nceas.metacat.service.SkinPropertyService;
49
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
50
import edu.ucsb.nceas.metacat.shared.ServiceException;
51
import edu.ucsb.nceas.utilities.GeneralPropertyException;
52
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
53
import edu.ucsb.nceas.utilities.FileUtil;
54
import edu.ucsb.nceas.utilities.UtilException;
55

    
56
/**
57
 * A suite of utility classes for the metadata catalog server
58
 */
59
public class MetacatUtil
60
{
61

    
62
    public static AbstractDatabase dbAdapter;
63
    
64
    private static boolean debugErrorDisplayed = false;
65
    
66
    private static Logger logMetacat = Logger.getLogger(MetacatUtil.class);
67
    private static char separator = '.';
68

    
69
    static {
70
        try {
71
        	separator = PropertyService.getProperty("document.accNumSeparator").charAt(0);
72
        } catch (PropertyNotFoundException pnfe) {
73
        	logMetacat.error("Could not retrieve account number separator. " 
74
        			+ "Separator set to '.' : " + pnfe.getMessage());
75
        }
76
    }
77

    
78
    /**
79
     * Utility method to parse the query part of a URL into parameters. This
80
     * method assumes the format of the query par tof the url is an ampersand
81
     * separated list of name/value pairs, with equal signs separating the name
82
     * from the value (e.g., name=tom&zip=99801 ). Returns a has of the name
83
     * value pairs, hashed on name.
84
     */
85
    public static Hashtable<String,String> parseQuery(String query)
86
            throws MalformedURLException
87
    {
88
        String[][] params = new String[200][2];
89
        Hashtable<String,String> parameters = new Hashtable<String,String>();
90

    
91
        String temp = "";
92
        boolean ampflag = true;
93
        boolean poundflag = false;
94
        int arrcount = 0;
95

    
96
        if (query != null) {
97
            for (int i = 0; i < query.length(); i++) {
98

    
99
                // go throught the remainder of the query one character at a
100
                // time.
101
                if (query.charAt(i) == '=') {
102
                    // if the current char is a # then the preceding should be
103
                    // a name
104
                    if (!poundflag && ampflag) {
105
                        params[arrcount][0] = temp.trim();
106
                        temp = "";
107
                    } else {
108
                        //if there are two #s or &s in a row throw an
109
                        // exception.
110
                        throw new MalformedURLException(
111
                                "metacatURL: Two parameter names "
112
                                        + "not allowed in sequence");
113
                    }
114
                    poundflag = true;
115
                    ampflag = false;
116
                } else if (query.charAt(i) == '&' || i == query.length() - 1) {
117
                    //the text preceding the & should be the param value.
118
                    if (i == query.length() - 1) {
119
                        //if at the end of the string grab the last value and
120
                        // append it.
121
                        if (query.charAt(i) != '=') {
122
                            //ignore an extra & on the end of the string
123
                            temp += query.charAt(i);
124
                        }
125
                    }
126

    
127
                    if (!ampflag && poundflag) {
128
                        params[arrcount][1] = temp.trim();
129
                        parameters
130
                                .put(params[arrcount][0], params[arrcount][1]);
131
                        temp = "";
132
                        arrcount++; //increment the array to the next row.
133
                    } else {
134
                        //if there are two =s or &s in a row through an
135
                        // exception
136
                        throw new MalformedURLException(
137
                                "metacatURL: Two parameter values "
138
                                        + "not allowed in sequence");
139
                    }
140
                    poundflag = false;
141
                    ampflag = true;
142
                } else {
143
                    //get the next character in the string
144
                    temp += query.charAt(i);
145
                }
146
            }
147
        }
148
        return parameters;
149
    }
150
  
151
    public static Vector<String> getOptionList(String optiontext)
152
    {
153
        Vector<String> optionsVector = new Vector<String>();
154
        if (optiontext.indexOf(",") == -1) {
155
            optionsVector.addElement(optiontext);
156
            return optionsVector;
157
        }
158

    
159
        while (optiontext.indexOf(",") != -1) {
160
            String s = optiontext.substring(0, optiontext.indexOf(","));
161
            optionsVector.addElement(s.trim());
162
            optiontext = optiontext.substring(optiontext.indexOf(",") + 1,
163
                    optiontext.length());
164
            if (optiontext.indexOf(",") == -1) { //catch the last list entry
165
                optionsVector.addElement(optiontext.trim());
166
            }
167
        }
168
        return optionsVector;
169
    }
170

    
171
    /** Normalizes a string read from DB. So it will be compatible to HTML */
172
    public static String normalize(String s)
173
    {
174
        StringBuffer str = new StringBuffer();
175

    
176
             int len = (s != null) ? s.length() : 0;
177
             for (int i = 0; i < len; i++) {
178
                 char ch = s.charAt(i);
179
                 switch (ch) {
180
                     case '<': {
181
                         str.append("&lt;");
182
                         break;
183
                     }
184
                     case '>': {
185
                         str.append("&gt;");
186
                         break;
187
                     }
188
                     case '&': {
189
                         /*
190
                          * patch provided by Johnoel Ancheta from U of Hawaii
191
                          */
192
                         // check if & is for a character reference &#xnnnn;
193
                         if (i + 1 < len - 1 && s.charAt(i + 1) == '#') {
194
                             str.append("&#");
195
                             i += 2;
196

    
197
                             ch = s.charAt(i);
198
                             while (i < len && ch != ';') {
199
                                 str.append(ch);
200
                                 i++;
201
                                 ch = s.charAt(i);
202
                             }
203
                             str.append(';');
204
                         } else 
205
                         // check if & is in front of amp; 
206
                         // (we dont yet check for other HTML 4.0 Character entities) 
207
                         if (i + 4 < len  && s.charAt(i + 1) == 'a' 
208
                        	 && s.charAt(i + 2) == 'm' 
209
                        		 && s.charAt(i + 3) == 'p' 
210
                        			 && s.charAt(i + 4) == ';'){
211
                             str.append("&amp;");
212
                             i += 4;                        	 
213
                         }
214
                         else  if (i + 3 < len && s.charAt(i + 1) == 'l' 
215
                        	 && s.charAt(i + 2) == 't' 
216
                        		 && s.charAt(i + 3) == ';' ){
217
                    	  // check if & is in front of it; 
218
                             str.append("&lt;");
219
                             i += 3;                        	 
220
                         } 
221
                         else  if (i + 3 < len && s.charAt(i + 1) == 'g' 
222
                        	 && s.charAt(i + 2) == 't' 
223
                        		 && s.charAt(i + 3) == ';' ){
224
                    	  // check if & is in front of gt; 
225
                           // (we dont yet check for other HTML 4.0 Character entities) 
226
                             str.append("&gt;");
227
                             i += 3;                        	 
228
                         } 
229
                         else  if (i + 5 < len && s.charAt(i + 1) == 'q' 
230
                        	 && s.charAt(i + 2) == 'u' 
231
                        		 && s.charAt(i + 3) == 'o' 
232
                        	 && s.charAt(i + 4) == 't'
233
                        	 && s.charAt(i + 5) == ';')
234
                             {
235
                    	   // check if & is in front of quot; 
236
                           // (we dont yet check for other HTML 4.0 Character entities) 
237
                             str.append("&quot;");
238
                             i += 5;                        	 
239
                         } 
240
                         else  if (i + 5 < len && s.charAt(i + 1) == 'a' 
241
                        	 && s.charAt(i + 2) == 'p' 
242
                        		 && s.charAt(i + 3) == 'o' 
243
                        	 && s.charAt(i + 4) == 's'
244
                        	 && s.charAt(i + 5) == ';')
245
                             {
246
                    	   // check if & is in front of apostrophe; 
247
                           // (we dont yet check for other HTML 4.0 Character entities) 
248
                             str.append("&apos;");
249
                             i += 5;                        	 
250
                         } 
251
                         else{
252
                             str.append("&amp;");
253
                         }
254
                         /////////
255
                         break;
256
                     }
257
                     case '"':
258
                    	 str.append("&quot;");
259
                         break;
260
                     case '\'':
261
                    	 str.append("&apos;");
262
                         break;
263
                    default: {
264
                         if ( (ch<128) && (ch>31) ) {
265
                             str.append(ch);
266
                         }
267
                         else if (ch<32) {
268
                             if (ch == 10) { // new line
269
                                 str.append(ch);
270
                             }
271
                             if (ch == 13) { // carriage return
272
                                 str.append(ch);
273
                             }
274
                             if (ch == 9) {  // tab
275
                                 str.append(ch);
276
                             }
277
                             // otherwise skip
278
                         }
279
                         else {
280
                        	 //Don't transfer special character to numeric entity
281
                             /*str.append("&#");
282
                             str.append(Integer.toString(ch));
283
                             str.append(';');*/
284
                             str.append(ch);
285
                         }
286
                     }
287
                 }
288
             }
289
             return str.toString();
290
    }
291

    
292
    /**
293
     * Get docid from online/url string
294
     */
295
    public static String getDocIdWithRevFromOnlineURL(String url)
296
    {
297
        String docid = null;
298
        String DOCID = "docid";
299
        boolean find = false;
300
        char limited = '&';
301
        int count = 0; //keep track how many & was found
302
        Vector list = new Vector();// keep index number for &
303
        if (url == null) {
304
            logMetacat.info("url is null and null will be returned");
305
            return docid;
306
        }
307
        // the first element in list is 0
308
        list.add(new Integer(0));
309
        for (int i = 0; i < url.length(); i++) {
310
            if (url.charAt(i) == limited) {
311
                // count plus 1
312
                count++;
313
                list.add(new Integer(i));
314
                // get substring beween two &
315
                String str = url.substring(
316
                        ((Integer) list.elementAt(count - 1)).intValue(), i);
317
                logMetacat.info("substring between two & is: " + str);
318
                //if the subString contains docid, we got it
319
                if (str.indexOf(DOCID) != -1) {
320
                    //get index of '="
321
                    int start = getIndexForGivenChar(str, '=') + 1;
322
                    int end = str.length();
323
                    docid = str.substring(start, end);
324
                    find = true;
325
                }//if
326
            }//if
327
        }//for
328
        //if not find, we need check the subtring between the index of last &
329
        // and
330
        // the end of string
331
        if (!find) {
332
            logMetacat.info("Checking the last substring");
333
            String str = url.substring(((Integer) list.elementAt(count))
334
                    .intValue() + 1, url.length());
335
            logMetacat.info("Last substring is: " + str);
336
            if (str.indexOf(DOCID) != -1) {
337
                //get index of '="
338
                int start = getIndexForGivenChar(str, '=') + 1;
339
                int end = str.length();
340
                docid = str.substring(start, end);
341
                find = true;
342
            }//if
343
        }//if
344
        logMetacat.info("The docid from online url is:" + docid);
345
        return docid.trim();
346
    }
347

    
348

    
349
    /**
350
     * Eocgorid identifier will look like: ecogrid://knb/tao.1.1
351
     * The AccessionNumber tao.1.1 will be returned. If the given doesn't
352
     * contains ecogrid, null will be returned.
353
     * @param identifier String
354
     * @return String
355
     */
356
    public static String getAccessionNumberFromEcogridIdentifier(String identifier)
357
    {
358
      String accessionNumber = null;
359
      if (identifier != null && identifier.startsWith(DBSAXHandler.ECOGRID))
360
      {
361
        // find the last "/" in identifier
362
        int indexOfLastSlash = identifier.lastIndexOf("/");
363
        int start = indexOfLastSlash+1;
364
        int end   = identifier.length();
365
        accessionNumber = identifier.substring(start, end);
366
      }
367
      logMetacat.warn("The accession number from url is " +
368
                                 accessionNumber);
369
      return accessionNumber;
370
    }
371

    
372
    private static int getIndexForGivenChar(String str, char character)
373
    {
374
        int index = -1;
375
        // make sure str is not null
376
        if (str == null) {
377
            logMetacat.info(
378
                    "The given str is null and -1 will be returned");
379
            return index;
380
        }
381
        // got though the string
382
        for (int i = 0; i < str.length(); i++) {
383
            // find the first one then break the loop
384
            if (str.charAt(i) == character) {
385
                index = i;
386
                break;
387
            }//if
388
        }//for
389
        logMetacat.info("the index for char " + character + " is: "
390
                + index);
391
        return index;
392
    }
393

    
394
    /**
395
     * Utility method to get docid from a given string
396
     *
397
     * @param string, the given string should be these two format: 1) str1.str2
398
     *            in this case docid= str1.str2 2) str1.str2.str3, in this case
399
     *            docid =str1.str2
400
     * @param the sperator char
401
     */
402
    public static String getDocIdFromString(String str)
403
    {
404
        String docId = null;
405
        if (str == null) {
406
            logMetacat.info(
407
                    "The given str is null and null will be returned"
408
                            + " in getDocIdfromString");
409
            return docId;
410
        } //make sure docid is not null
411
        int dotNumber = 0;//count how many dots in given string
412
        int indexOfLastDot = 0;
413

    
414
        for (int i = 0; i < str.length(); i++) {
415
            if (str.charAt(i) == separator) {
416
                dotNumber++;//count how many dots
417
                indexOfLastDot = i;//keep the last dot postion
418
            }
419
        }//for
420

    
421
        //The string formatt is wrong, because it has more than two or less
422
        // than
423
        //one seperator
424
        if (dotNumber > 2 || dotNumber < 1) {
425
            docId = null;
426
        } else if (dotNumber == 2) //the case for str1.str2.str3
427
        {
428
            docId = str.substring(0, indexOfLastDot);
429
        } else if (dotNumber == 1) //the case for str1.str2
430
        {
431
            docId = str;
432
        }
433

    
434
        return docId;
435
    }//getDocIdFromString
436

    
437
    /**
438
     * Utility method to get version number from a given string
439
     *
440
     * @param string, the given string should be these two format: 1)
441
     *            str1.str2(no version) version =-1; 2) str1.str2.str3, in this
442
     *            case version = str3; 3) other, vresion =-2
443
     */
444
    public static int getVersionFromString(String str)
445
            throws NumberFormatException
446
    {
447
        int version = -1;
448
        String versionString = null;
449
        int dotNumber = 0;//count how many dots in given string
450
        int indexOfLastDot = 0;
451

    
452
        for (int i = 0; i < str.length(); i++) {
453
            if (str.charAt(i) == separator) {
454
                dotNumber++;//count how many dots
455
                indexOfLastDot = i;//keep the last dot postion
456
            }
457
        }//for
458

    
459
        //The string formatt is wrong, because it has more than two or less
460
        // than
461
        //one seperator
462
        if (dotNumber > 2 || dotNumber < 1) {
463
            version = -2;
464
        } else if (dotNumber == 2 && (indexOfLastDot != (str.length() - 1)))
465
        //the case for str1.str2.str3
466
        {
467
            versionString = str.substring((indexOfLastDot + 1), str.length());
468
            version = Integer.parseInt(versionString);
469
        } else if (dotNumber == 1) //the case for str1.str2
470
        {
471
            version = -1;
472
        }
473

    
474
        return version;
475
    }//getVersionFromString
476

    
477
    /**
478
     * Utility method to get version string from a given string
479
     *
480
     * @param string, the given string should be these two format: 1)
481
     *            str1.str2(no version) version=null; 2) str1.str2.str3, in
482
     *            this case version = str3; 3) other, vresion =null;
483
     */
484
    public static String getRevisionStringFromString(String str)
485
            throws NumberFormatException
486
    {
487
        // String to store the version
488
        String versionString = null;
489
        int dotNumber = 0;//count how many dots in given string
490
        int indexOfLastDot = 0;
491

    
492
        for (int i = 0; i < str.length(); i++) {
493
            if (str.charAt(i) == separator) {
494
                dotNumber++;//count how many dots
495
                indexOfLastDot = i;//keep the last dot postion
496
            }
497
        }//for
498

    
499
        //The string formatt is wrong, because it has more than two or less
500
        // than
501
        //one seperator
502
        if (dotNumber > 2 || dotNumber < 1) {
503
            versionString = null;
504
        } else if (dotNumber == 2 && (indexOfLastDot != (str.length() - 1))) {
505
            //the case for str1.str2.str3
506
            // indexOfLastDot != (str.length() -1) means get rid of str1.str2.
507
            versionString = str.substring((indexOfLastDot + 1), str.length());
508
        } else if (dotNumber == 1) //the case for str1.str2 or str1.str2.
509
        {
510
            versionString = null;
511
        }
512

    
513
        return versionString;
514
    }//getVersionFromString
515

    
516
    /**
517
     * This method will get docid from an AccessionNumber. There is no
518
     * assumption the accessnumber will be str1.str2.str3. It can be more. So
519
     * we think the docid will be get rid of last part
520
     */
521
    public static String getDocIdFromAccessionNumber(String accessionNumber)
522
    {
523
        String docid = null;
524
        if (accessionNumber == null) { return docid; }
525
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
526
        docid = accessionNumber.substring(0, indexOfLastSeperator);
527
        logMetacat.info("after parsing accessionnumber, docid is "
528
                + docid);
529
        return docid;
530
    }
531

    
532
    /**
533
     * This method will get inline data id without the revision number.
534
     * So if inlineData.1.2 is passed as input, inlineData.2 is returned.
535
     */
536
    public static String getInlineDataIdWithoutRev(String accessionNumber)
537
    {
538
        String docid = null;
539
        if (accessionNumber == null) { return docid; }
540
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
541
        String version = accessionNumber.substring(indexOfLastSeperator,
542
                                                   accessionNumber.length());
543
        accessionNumber = accessionNumber.substring(0, indexOfLastSeperator);
544
        indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
545
        docid = accessionNumber.substring(0, indexOfLastSeperator) + version;
546
        logMetacat.info("after parsing accessionnumber, docid is "
547
                                 + docid);
548

    
549
        return docid;
550
    }
551

    
552
    /**
553
     * This method will call both getDocIdFromString and
554
     * getDocIdFromAccessionNumber. So first, if the string looks str1.str2,
555
     * the docid will be str1.str2. If the string is str1.str2.str3, the docid
556
     * will be str1.str2. If the string is str1.str2.str3.str4 or more, the
557
     * docid will be str1.str2.str3. If the string look like str1, null will be
558
     * returned
559
     *
560
     */
561
    public static String getSmartDocId(String str)
562
    {
563
        String docid = null;
564
        //call geDocIdFromString first.
565
        docid = getDocIdFromString(str);
566
        // If docid is null, try to call getDocIdFromAccessionNumber
567
        // it will handle the seperator more than2
568
        if (docid == null) {
569
            docid = getDocIdFromAccessionNumber(str);
570
        }
571
        logMetacat.info("The docid get from smart docid getor is "
572
                + docid);
573
        return docid;
574
    }
575

    
576
    /**
577
     * This method will get revision from an AccessionNumber. There is no
578
     * assumption the accessnumber will be str1.str2.str3. It can be more. So
579
     * we think the docid will be get rid of last part
580
     */
581
    public static int getRevisionFromAccessionNumber(String accessionNumber)
582
            throws NumberFormatException
583
    {
584
        String rev = null;
585
        int revNumber = -1;
586
        if (accessionNumber == null) { return revNumber; }
587
        int indexOfLastSeperator = accessionNumber.lastIndexOf(separator);
588
        rev = accessionNumber.substring(indexOfLastSeperator + 1,
589
                accessionNumber.length());
590
        revNumber = Integer.parseInt(rev);
591
        logMetacat.info("after parsing accessionnumber, rev is "
592
                + revNumber);
593
        return revNumber;
594
    }
595

    
596
    /**
597
     * Method to get the name of local replication server
598
     */
599
    public static String getLocalReplicationServerName()
600
    {
601
        String replicationServerName = null;
602
        // String serverHost = null;
603
        // serverHost = getProperty("server");
604
        // append "context/servlet/replication" to the host name
605
        try {
606
        replicationServerName = 
607
        	SystemUtil.getSecureServer() 
608
        	+ FileUtil.getFS()
609
			+ PropertyService.getProperty("application.context")
610
			+ "/servlet/replication";
611
        } catch (PropertyNotFoundException pnfe) {
612
        	logMetacat.error("Could not get local replication server name " 
613
        			+ "because property could not be found: " + pnfe.getMessage());
614
        }
615
        return replicationServerName;
616

    
617
    }
618

    
619
    /**
620
     * Method to get docidwithrev from eml2 inline data id The eml inline data
621
     * id would look like eml.200.2.3
622
     */
623
    public static String getDocIdWithoutRevFromInlineDataID(String inlineDataID)
624
    {
625
        String docidWithoutRev = null;
626
        if (inlineDataID == null) { return docidWithoutRev; }
627
        char charSeperator = separator;
628
        int targetNumberOfSeperator = 2;// we want to know his index
629
        int numberOfSeperator = 0;
630
        for (int i = 0; i < inlineDataID.length(); i++) {
631
            // meet seperator, increase number of seperator
632
            if (inlineDataID.charAt(i) == charSeperator) {
633
                numberOfSeperator++;
634
            }
635
            // if number of seperator reach the target one, record the index(i)
636
            // and get substring and terminate the loop
637
            if (numberOfSeperator == targetNumberOfSeperator) {
638
                docidWithoutRev = inlineDataID.substring(0, i);
639
                break;
640
            }
641
        }
642

    
643
        logMetacat.info("Docid without rev from inlinedata id: "
644
                + docidWithoutRev);
645
        return docidWithoutRev;
646

    
647
    }
648

    
649
    /**
650
     * Revise stack change a stack to opposite order
651
     */
652
    public static Stack<NodeRecord> reviseStack(Stack<NodeRecord> stack)
653
    {
654
        Stack result = new Stack();
655
        // make sure the parameter is correct
656
        if (stack == null || stack.isEmpty()) {
657
            result = stack;
658
            return result;
659
        }
660

    
661
        while (!stack.isEmpty()) {
662
            Object obj = stack.pop();
663
            result.push(obj);
664
        }
665
        return result;
666
    }
667

    
668
    /** A method to replace whitespace in url */
669
    public static String replaceWhiteSpaceForURL(String urlHasWhiteSpace)
670
    {
671
        StringBuffer newUrl = new StringBuffer();
672
        String whiteSpaceReplace = "%20";
673
        if (urlHasWhiteSpace == null || urlHasWhiteSpace.trim().equals("")) { return null; }
674

    
675
        for (int i = 0; i < urlHasWhiteSpace.length(); i++) {
676
            char ch = urlHasWhiteSpace.charAt(i);
677
            if (!Character.isWhitespace(ch)) {
678
                newUrl.append(ch);
679
            } else {
680
                //it is white sapce, replace it by %20
681
                newUrl = newUrl.append(whiteSpaceReplace);
682
            }
683

    
684
        }//for
685
        logMetacat.info("The new string without space is:"
686
                + newUrl.toString());
687
        return newUrl.toString();
688

    
689
    }// replaceWhiteSpaceForUR
690

    
691
    /**
692
	 * Writes debug information into a file. In metacat.properties, if property
693
	 * application.writeDebugToFile is set to true, the debug information will be written to
694
	 * debug file, which value is the property application.debugOutputFile in
695
	 * metacat.properties.
696
	 * 
697
	 */
698
	public static void writeDebugToFile(String debugInfo) {
699
		String debug = "false";
700
		try {
701
			debug = PropertyService.getProperty("application.writeDebugToFile");
702
			if (debug != null && debug.equalsIgnoreCase("true")) {
703
				File outputFile = 
704
					new File(PropertyService.getProperty("application.debugOutputFile"));
705
				FileOutputStream fos = new FileOutputStream(outputFile, true);
706
				PrintWriter pw = new PrintWriter(fos);
707
				pw.println(debugInfo);
708
				pw.flush();
709
				pw.close();
710
				fos.close();
711
			}
712
		} catch (PropertyNotFoundException pnfe) {
713
			// only log debug to file warning once
714
			if (!debugErrorDisplayed) {
715
				logMetacat.warn("Could not get debug property.  Write debug to " 
716
						+ "file is set to false: " + pnfe.getMessage());
717
				debugErrorDisplayed = true;
718
			}
719
		} catch (Exception io) {
720
			logMetacat.warn("Error in MetacatUtil.writeDebugToFile "
721
					+ io.getMessage());
722
		}
723
	}
724
    
725
   /**
726
	 * Writes debug information into a file in delimitered format
727
	 * 
728
	 * @param debugInfo
729
	 *            the debug information
730
	 * @param newLine
731
	 *            append the debug info to a line or not
732
	 */
733
	public static void writeDebugToDelimiteredFile(String debugInfo, boolean newLine) {
734
		String debug = "false";
735
		try {
736
			debug = PropertyService.getProperty("application.writeDebugToFile");
737
			if (debug != null && debug.equalsIgnoreCase("true")) {
738
				File outputFile = new File(PropertyService
739
						.getProperty("application.delimiteredOutputFile"));
740
				FileOutputStream fos = new FileOutputStream(outputFile, true);
741
				PrintWriter pw = new PrintWriter(fos);
742
				if (newLine) {
743
					pw.println(debugInfo);
744
				} else {
745
					pw.print(debugInfo);
746
				}
747
				pw.flush();
748
				pw.close();
749
				fos.close();
750
			}
751
		} catch (PropertyNotFoundException pnfe) {
752
			// only log debug to file warning once
753
			if (!debugErrorDisplayed) {
754
				logMetacat.warn("Could not get delimited debug property. Write debug to " 
755
						+ "file is set to false: " + pnfe.getMessage());
756
				debugErrorDisplayed = true;
757
			}
758
		} catch (Exception io) {
759
			logMetacat.warn("Eorr in writeDebugToDelimiteredFile "
760
					+ io.getMessage());
761
		}
762
	}
763

    
764
	/**
765
	 * Write the uploaded file to disk for temporary storage before moving it to
766
	 * its final Metacat location.
767
	 * 
768
	 * @param filePart
769
	 *            the FilePart object containing the file form element
770
	 * @param fileName
771
	 *            the name of the file to be written to disk
772
	 * @return tempFilePath a String containing location of temporary file
773
	 */
774
    public static String writeTempUploadFile (FilePart filePart, String fileName) throws IOException {
775
        String tempFilePath = null;
776
        String tempDirPath = null;
777
        try {
778
        	tempDirPath = PropertyService.getProperty("application.tempDir") + FileUtil.getFS() + "uploads";
779
        } catch (PropertyNotFoundException pnfe) {
780
        	logMetacat.warn("Temp property not found.  An attempt will be made " 
781
        			+ "to use system temp directory: " + pnfe.getMessage());
782
        }
783
        long fileSize;
784
        File tempFile;
785
        File tempDir;
786

    
787
        if ((fileName == null) || fileName.equals("")) {
788
            return tempFilePath;
789
        }
790
				
791
        // the tempfilepath token isn't set, use Java default
792
		if (tempDirPath == null) {
793
			String javaTempDir = System.getProperty("java.io.tempdir");
794
			if (javaTempDir == null) {
795
				// no paths set, use unix default
796
				tempDirPath = "/tmp";
797
			} else {
798
				tempDirPath = javaTempDir;
799
			}
800
		}
801

    
802
        tempDir = new File(tempDirPath);
803

    
804
		// Create the temporary directory if it doesn't exist
805
		try {
806
			if (!tempDir.exists()) {
807
				tempDir.mkdirs();
808
			}
809
		} catch (SecurityException e) {
810
			throw new IOException("Can't create directory: " + tempDir.getPath() + ". Error: "
811
					+ e.getMessage());
812
		}
813

    
814
		tempFile = new File(tempDirPath, fileName);
815
		fileSize = filePart.writeTo(tempFile);
816
		tempFilePath = tempDirPath + File.separator + fileName;
817

    
818
		if (fileSize == 0) {
819
			logMetacat.warn("Uploaded file '" + fileName + "'is empty!");
820
		}
821

    
822
        logMetacat.debug("Temporary file is: " + tempFilePath);
823

    
824
        return tempFilePath;
825
    }
826

    
827
    /**
828
	 * 
829
	 * Copy a file between two locations specified as strings. Fails if either
830
	 * path cannot be created. Based on the public domain FileCopy class in
831
	 * _Java in a Nutshell_.
832
	 * 
833
	 * @param sourceName
834
	 *            the source file to read from disk
835
	 * @param destName
836
	 *            the destination file on disk
837
	 */
838
    public static void copyFile(String sourceName, String destName) throws IOException {
839

    
840
        File sourceFile = new File(sourceName);
841
        File destFile = new File(destName);
842
        FileInputStream source = null;
843
        FileOutputStream dest = null;
844
        byte[] buffer;
845
        int bytesRead;
846

    
847
        try {
848
            if (!sourceFile.exists() || !sourceFile.isFile()) {
849
                logMetacat.error("File copy: no such source" +
850
                                 " file: " + sourceName);
851
            }
852
            if (!sourceFile.canRead()) {
853
                logMetacat.error("File copy: source file " +
854
                                 "is unreadable: " + sourceName);
855
            }
856

    
857
            if (destFile.exists()) {
858
                if (destFile.isFile()) {
859
                    if (!destFile.canWrite()) {
860
                        logMetacat.error("File copy: destination " +
861
                                         "file is unwriteable: " + destFile);
862
                    }
863
                } else {
864
                    logMetacat.error("File copy: destination file " +
865
                                     "is not a file: " + destFile);
866
                }
867
            } else {
868
                File parentDir = parent(destFile);
869

    
870
                if (!parentDir.exists())
871
                {
872
                    logMetacat.error("File copy: destination diretory " +
873
                                     " doesn't exist: " + destName);
874
                }
875
                if (!parentDir.canWrite()) {
876
                    logMetacat.error("File copy: destination directory " +
877
                                     " is unwritable: " + destName);
878
                }
879
            }
880

    
881
            // Verbose error checking done, copy the file object
882
            source = new FileInputStream(sourceFile);
883
            dest = new FileOutputStream(destFile);
884
            buffer = new byte[1024];
885

    
886
            while (true) {
887
                bytesRead = source.read(buffer);
888
                if (bytesRead == -1) {
889
                    break;
890
                }
891
                dest.write(buffer, 0, bytesRead);
892
            }
893
        }
894
        finally {
895
            if (source != null) {
896
                try { source.close(); } catch (IOException e) { ; }
897
            }
898
            if (dest != null) {
899
                try { dest.close(); } catch (IOException e) { ; }
900
            }
901
        }
902
    }
903

    
904
    private static File parent(File f) {
905
        String dirname = f.getParent();
906
        if (dirname == null) {
907
            if (f.isAbsolute()) return new File(File.separator);
908
            else return new File(System.getProperty("user.dir"));
909
        }
910
        return new File(dirname);
911
    }
912

    
913
	/**
914
	 * Reports whether metacat is fully configured.
915
	 * 
916
	 * @return a boolean that is true if all sections are configured and 
917
	 * false otherwise
918
	 */
919
	public static boolean isMetacatConfigured() {
920
		boolean metacatConfigured = false;
921
		try {			
922
			metacatConfigured = PropertyService.arePropertiesConfigured()
923
					&& AuthUtil.isAuthConfigured()
924
					&& SkinUtil.areSkinsConfigured()
925
					&& DatabaseUtil.isDatabaseConfigured()
926
					&& GeoserverUtil.isGeoserverConfigured()
927
					&& isBackupDirConfigured();
928
		} catch (MetacatUtilException ue) {
929
			logMetacat.error("Could not determine if metacat is configured due to utility exception: "
930
					+ ue.getMessage());
931
		} catch (PropertyNotFoundException pnfe) {
932
			logMetacat.error("Could not determine if metacat is configured due to property exception: "
933
					+ pnfe.getMessage());
934
		}
935

    
936
		return metacatConfigured;
937
	}
938

    
939
	/**
940
	 * Check if the application.backupDir property is populated in
941
	 * metacat.properties and that it points to a writable directory.
942
	 * 
943
	 * @return false if the application.backupDir property does not point to a
944
	 *         writable directory.
945
	 */
946
	public static boolean isBackupDirConfigured() throws MetacatUtilException, PropertyNotFoundException {
947
		String backupDir = PropertyService.getProperty("application.backupDir");
948
		if (backupDir == null || backupDir.equals("")) {
949
			return false;
950
		}		
951
		if (FileUtil.getFileStatus(backupDir) < FileUtil.EXISTS_READ_WRITABLE) {
952
			return false;
953
		}	
954
		return true;
955
	}
956
		
957
	/**
958
	 * Reports whether the metacat configuration utility should be run. Returns
959
	 * false if 
960
	 *   -- dev.runConfiguration=false and 
961
	 *   -- backup properties file exists 
962
	 * Note that dev.runConfiguration should only be set to false when reinstalling the 
963
	 * same version of the application in development.
964
	 * 
965
	 * @return a boolean that is false if dev.runConfiguration is false and the
966
	 *         backup properties file exists.
967
	 */
968
	public static boolean bypassConfiguration() throws MetacatUtilException, ServiceException {
969
		try {
970
			// If the system is not configured to do bypass, return false.
971
			if (!PropertyService.doBypass()) {
972
				return false;
973
			}
974

    
975
			// Get the most likely backup files.  If these cannot be found, we 
976
			// cannot do the configuration bypass.
977
			String ExternalBaseDir = SystemUtil.discoverExternalDir();
978
			if (ExternalBaseDir == null) {
979
				logMetacat.error("bypassConfiguration: Could not find backup directory.");
980
				// could not find backup files ... force the configuration
981
				return false;
982
			}
983
			String realContext = ServiceService.getRealApplicationContext();
984
			PropertyService.setRecommendedExternalDir(ExternalBaseDir);
985
			PropertyService.setProperty("application.backupDir", 
986
					ExternalBaseDir + FileUtil.getFS() + "." + realContext);
987

    
988
			// Refresh the property service and skin property service.  This will pick up 
989
			// the backup directory and populate backup properties in caches.
990
			ServiceService.refreshService("PropertyService");
991
			ServiceService.refreshService("SkinPropertyService");
992

    
993
			// Call bypassConfiguration to make sure backup properties get persisted 
994
			// to active properties for both main and skin properties.
995
			PropertyService.bypassConfiguration();
996
			SkinPropertyService.bypassConfiguration();
997

    
998
			return true;
999
		} catch (GeneralPropertyException gpe) {
1000
			throw new MetacatUtilException("Property error while discovering backup directory: "
1001
					+ gpe.getMessage());
1002
		} catch (MetacatUtilException mue) {
1003
			throw new MetacatUtilException("Utility error while discovering backup directory: "
1004
					+ mue.getMessage());
1005
		}
1006

    
1007
	}
1008
		
1009
}
(6-6/12)