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-02-18 16:30:06 -0800 (Wed, 18 Feb 2009) $'
10
 * '$Revision: 4812 $'
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.ServiceException;
48
import edu.ucsb.nceas.metacat.service.ServiceService;
49
import edu.ucsb.nceas.metacat.service.SkinPropertyService;
50
import edu.ucsb.nceas.utilities.GeneralPropertyException;
51
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
52
import edu.ucsb.nceas.utilities.FileUtil;
53

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

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

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

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

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

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

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

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

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

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

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

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

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

    
346

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

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

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

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

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

    
432
        return docId;
433
    }//getDocIdFromString
434

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

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

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

    
472
        return version;
473
    }//getVersionFromString
474

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

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

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

    
511
        return versionString;
512
    }//getVersionFromString
513

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

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

    
547
        return docid;
548
    }
549

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

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

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

    
615
    }
616

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

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

    
645
    }
646

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

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

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

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

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

    
687
    }// replaceWhiteSpaceForUR
688

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

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

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

    
800
        tempDir = new File(tempDirPath);
801

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

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

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

    
820
        logMetacat.debug("Temporary file is: " + tempFilePath);
821

    
822
        return tempFilePath;
823
    }
824

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

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

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

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

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

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

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

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

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

    
934
		return metacatConfigured;
935
	}
936

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

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

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

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

    
996
			return true;
997
		} catch (GeneralPropertyException gpe) {
998
			throw new UtilException("Property error while discovering backup directory: "
999
					+ gpe.getMessage());
1000
		}
1001

    
1002
	}
1003
		
1004
}
(5-5/12)