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: 2008-12-26 13:09:47 -0800 (Fri, 26 Dec 2008) $'
10
 * '$Revision: 4699 $'
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.MetaCatServlet;
46
import edu.ucsb.nceas.metacat.NodeRecord;
47
import edu.ucsb.nceas.metacat.service.PropertyService;
48
import edu.ucsb.nceas.metacat.service.ServiceException;
49
import edu.ucsb.nceas.metacat.service.ServiceService;
50
import edu.ucsb.nceas.metacat.service.SkinPropertyService;
51
import edu.ucsb.nceas.utilities.GeneralPropertyException;
52
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
53
import edu.ucsb.nceas.utilities.FileUtil;
54

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

    
61
    public static AbstractDatabase dbAdapter;
62

    
63
    public static Vector pathsForIndexing;
64
    
65
    private static boolean debug = true;
66
    
67
    private static boolean debugErrorDisplayed = false;
68
    
69
    private static Logger logMetacat = Logger.getLogger(MetacatUtil.class);
70
    private static char separator = '.';
71

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

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

    
94
        String temp = "";
95
        boolean ampflag = true;
96
        boolean poundflag = false;
97
        int arrcount = 0;
98

    
99
        if (query != null) {
100
            for (int i = 0; i < query.length(); i++) {
101

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

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

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

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

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

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

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

    
351

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

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

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

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

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

    
437
        return docId;
438
    }//getDocIdFromString
439

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

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

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

    
477
        return version;
478
    }//getVersionFromString
479

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

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

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

    
516
        return versionString;
517
    }//getVersionFromString
518

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

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

    
552
        return docid;
553
    }
554

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

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

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

    
620
    }
621

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

    
646
        logMetacat.info("Docid without rev from inlinedata id: "
647
                + docidWithoutRev);
648
        return docidWithoutRev;
649

    
650
    }
651

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

    
664
        while (!stack.isEmpty()) {
665
            Object obj = stack.pop();
666
            result.push(obj);
667
        }
668
        return result;
669
    }
670

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

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

    
687
        }//for
688
        logMetacat.info("The new string without space is:"
689
                + newUrl.toString());
690
        return newUrl.toString();
691

    
692
    }// replaceWhiteSpaceForUR
693

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

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

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

    
806
        tempDir = new File(tempDirPath);
807

    
808
        // Create the temporary directory if it doesn't exist
809
        try {
810
            if (!tempDir.exists()) {
811
                tempDir.mkdirs();
812
            }
813
        } catch (SecurityException e) {
814
            logMetacat.error("Can't create directory: " + tempDir.getPath() +
815
                             ". Error: " + e.getMessage());
816
        }
817
        try {
818
            tempFile = new File(tempDirPath, fileName);
819
            fileSize = filePart.writeTo(tempFile);
820
            tempFilePath = tempDirPath + File.separator + fileName;
821

    
822
            if (fileSize == 0) {
823
                logMetacat.error("Uploaded file '" + fileName + "'is empty!");
824
            }
825
        } catch (IOException e) {
826
            logMetacat.error("IO exception which writing temporary file: " +
827
                             tempFilePath + " " + e.getMessage());
828
        }
829

    
830
        logMetacat.info("Temporary file is: " + tempFilePath);
831

    
832
        return tempFilePath;
833
    }
834

    
835
    /**
836
	 * 
837
	 * Copy a file between two locations specified as strings. Fails if either
838
	 * path cannot be created. Based on the public domain FileCopy class in
839
	 * _Java in a Nutshell_.
840
	 * 
841
	 * @param sourceName
842
	 *            the source file to read from disk
843
	 * @param destName
844
	 *            the destination file on disk
845
	 */
846
    public static void copyFile(String sourceName, String destName) throws IOException {
847
        Logger logMetacat = Logger.getLogger(MetaCatServlet.class);
848

    
849
        File sourceFile = new File(sourceName);
850
        File destFile = new File(destName);
851
        FileInputStream source = null;
852
        FileOutputStream dest = null;
853
        byte[] buffer;
854
        int bytesRead;
855

    
856
        try {
857
            if (!sourceFile.exists() || !sourceFile.isFile()) {
858
                logMetacat.error("File copy: no such source" +
859
                                 " file: " + sourceName);
860
            }
861
            if (!sourceFile.canRead()) {
862
                logMetacat.error("File copy: source file " +
863
                                 "is unreadable: " + sourceName);
864
            }
865

    
866
            if (destFile.exists()) {
867
                if (destFile.isFile()) {
868
                    if (!destFile.canWrite()) {
869
                        logMetacat.error("File copy: destination " +
870
                                         "file is unwriteable: " + destFile);
871
                    }
872
                } else {
873
                    logMetacat.error("File copy: destination file " +
874
                                     "is not a file: " + destFile);
875
                }
876
            } else {
877
                File parentDir = parent(destFile);
878

    
879
                if (!parentDir.exists())
880
                {
881
                    logMetacat.error("File copy: destination diretory " +
882
                                     " doesn't exist: " + destName);
883
                }
884
                if (!parentDir.canWrite()) {
885
                    logMetacat.error("File copy: destination directory " +
886
                                     " is unwritable: " + destName);
887
                }
888
            }
889

    
890
            // Verbose error checking done, copy the file object
891
            source = new FileInputStream(sourceFile);
892
            dest = new FileOutputStream(destFile);
893
            buffer = new byte[1024];
894

    
895
            while (true) {
896
                bytesRead = source.read(buffer);
897
                if (bytesRead == -1) {
898
                    break;
899
                }
900
                dest.write(buffer, 0, bytesRead);
901
            }
902
        }
903
        finally {
904
            if (source != null) {
905
                try { source.close(); } catch (IOException e) { ; }
906
            }
907
            if (dest != null) {
908
                try { dest.close(); } catch (IOException e) { ; }
909
            }
910
        }
911
    }
912

    
913
    private static File parent(File f) {
914
        String dirname = f.getParent();
915
        if (dirname == null) {
916
            if (f.isAbsolute()) return new File(File.separator);
917
            else return new File(System.getProperty("user.dir"));
918
        }
919
        return new File(dirname);
920
    }
921

    
922
	/**
923
	 * Reports whether metacat is fully configured.
924
	 * 
925
	 * @return a boolean that is true if all sections are configured and 
926
	 * false otherwise
927
	 */
928
	public static boolean isMetacatConfigured() {
929
		boolean metacatConfigured = false;
930
		try {			
931
			metacatConfigured = PropertyService.arePropertiesConfigured()
932
					&& AuthUtil.isAuthConfigured()
933
					&& SkinUtil.areSkinsConfigured()
934
					&& DatabaseUtil.isDatabaseConfigured()
935
					&& GeoserverUtil.isGeoserverConfigured()
936
					&& isBackupDirConfigured();
937
		} catch (UtilException ue) {
938
			logMetacat.error("Could not determine if metacat is configured due to utility exception: "
939
					+ ue.getMessage());
940
		} catch (PropertyNotFoundException pnfe) {
941
			logMetacat.error("Could not determine if metacat is configured due to property exception: "
942
					+ pnfe.getMessage());
943
		}
944

    
945
		return metacatConfigured;
946
	}
947

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

    
985
			// Get the most likely backup files.  If these cannot be found, we 
986
			// cannot do the configuration bypass.
987
			String backupDir = SystemUtil.discoverExternalBaseDir();
988
			if (backupDir == null) {
989
				logMetacat.error("bypassConfiguration: Could not find backup directory.");
990
				// could not find backup files ... force the configuration
991
				return false;
992
			}
993
			PropertyService.setProperty("application.backupDir", backupDir);
994

    
995
			// Refresh the property service and skin property service.  This will pick up 
996
			// the backup directory and populate backup properties in caches.
997
			ServiceService.refreshService("PropertyService");
998
			ServiceService.refreshService("SkinPropertyService");
999

    
1000
			// Call bypassConfiguration to make sure backup properties get persisted 
1001
			// to active properties for both main and skin properties.
1002
			PropertyService.bypassConfiguration();
1003
			SkinPropertyService.bypassConfiguration();
1004

    
1005
			return true;
1006
		} catch (GeneralPropertyException gpe) {
1007
			throw new UtilException("Property error while discovering backup directory: "
1008
					+ gpe.getMessage());
1009
		}
1010

    
1011
	}
1012
		
1013
}
(5-5/12)