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: leinfelder $'
9
 *     '$Date: 2014-04-24 13:28:01 -0700 (Thu, 24 Apr 2014) $'
10
 * '$Revision: 8748 $'
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.InputStream;
34
import java.io.PrintWriter;
35
import java.net.MalformedURLException;
36
import java.util.Hashtable;
37
import java.util.Vector;
38

    
39
import org.apache.commons.fileupload.FileItem;
40
import org.apache.commons.io.IOUtils;
41
import org.apache.log4j.Logger;
42

    
43
import com.oreilly.servlet.multipart.FilePart;
44

    
45
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
46
import edu.ucsb.nceas.metacat.properties.PropertyService;
47
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
48
import edu.ucsb.nceas.utilities.FileUtil;
49

    
50
/**
51
 * A suite of utility classes for the metadata catalog server
52
 */
53
public class MetacatUtil
54
{
55

    
56
    public static final String XMLFORMAT = "xml";	
57
    public static AbstractDatabase dbAdapter;
58
    
59
    private static boolean debugErrorDisplayed = false;
60
    
61
    private static Logger logMetacat = Logger.getLogger(MetacatUtil.class);
62

    
63
    /**
64
     * Utility method to parse the query part of a URL into parameters. This
65
     * method assumes the format of the query part of the url is an ampersand
66
     * separated list of name/value pairs, with equal signs separating the name
67
     * from the value (e.g., name=tom&zip=99801 ). Returns a has of the name
68
     * value pairs, hashed on name.
69
     */
70
    public static Hashtable<String,String> parseQuery(String query)
71
            throws MalformedURLException
72
    {
73
        String[][] params = new String[200][2];
74
        Hashtable<String,String> parameters = new Hashtable<String,String>();
75

    
76
        String temp = "";
77
        boolean ampflag = true;
78
        boolean poundflag = false;
79
        int arrcount = 0;
80

    
81
        if (query != null) {
82
            for (int i = 0; i < query.length(); i++) {
83

    
84
                // go throught the remainder of the query one character at a
85
                // time.
86
                if (query.charAt(i) == '=') {
87
                    // if the current char is a # then the preceding should be
88
                    // a name
89
                    if (!poundflag && ampflag) {
90
                        params[arrcount][0] = temp.trim();
91
                        temp = "";
92
                    } else {
93
                        //if there are two #s or &s in a row throw an
94
                        // exception.
95
                        throw new MalformedURLException(
96
                                "metacatURL: Two parameter names "
97
                                        + "not allowed in sequence");
98
                    }
99
                    poundflag = true;
100
                    ampflag = false;
101
                } else if (query.charAt(i) == '&' || i == query.length() - 1) {
102
                    //the text preceding the & should be the param value.
103
                    if (i == query.length() - 1) {
104
                        //if at the end of the string grab the last value and
105
                        // append it.
106
                        if (query.charAt(i) != '=') {
107
                            //ignore an extra & on the end of the string
108
                            temp += query.charAt(i);
109
                        }
110
                    }
111

    
112
                    if (!ampflag && poundflag) {
113
                        params[arrcount][1] = temp.trim();
114
                        parameters
115
                                .put(params[arrcount][0], params[arrcount][1]);
116
                        temp = "";
117
                        arrcount++; //increment the array to the next row.
118
                    } else {
119
                        //if there are two =s or &s in a row through an
120
                        // exception
121
                        throw new MalformedURLException(
122
                                "metacatURL: Two parameter values "
123
                                        + "not allowed in sequence");
124
                    }
125
                    poundflag = false;
126
                    ampflag = true;
127
                } else {
128
                    //get the next character in the string
129
                    temp += query.charAt(i);
130
                }
131
            }
132
        }
133
        return parameters;
134
    }
135
  
136
    public static Vector<String> getOptionList(String optiontext)
137
    {
138
        Vector<String> optionsVector = new Vector<String>();
139
        if (optiontext.indexOf(",") == -1) {
140
            optionsVector.addElement(optiontext);
141
            return optionsVector;
142
        }
143

    
144
        while (optiontext.indexOf(",") != -1) {
145
            String s = optiontext.substring(0, optiontext.indexOf(","));
146
            optionsVector.addElement(s.trim());
147
            optiontext = optiontext.substring(optiontext.indexOf(",") + 1,
148
                    optiontext.length());
149
            if (optiontext.indexOf(",") == -1) { //catch the last list entry
150
                optionsVector.addElement(optiontext.trim());
151
            }
152
        }
153
        return optionsVector;
154
    }
155

    
156
    /** Normalizes a string read from DB. So it will be compatible to HTML */
157
    public static String normalize(String s)
158
    {
159
        StringBuffer str = new StringBuffer();
160

    
161
             int len = (s != null) ? s.length() : 0;
162
             for (int i = 0; i < len; i++) {
163
                 char ch = s.charAt(i);
164
                 switch (ch) {
165
                     case '<': {
166
                         str.append("&lt;");
167
                         break;
168
                     }
169
                     case '>': {
170
                         str.append("&gt;");
171
                         break;
172
                     }
173
                     case '&': {
174
                         /*
175
                          * patch provided by Johnoel Ancheta from U of Hawaii
176
                          */
177
                         // check if & is for a character reference &#xnnnn;
178
                         if (i + 1 < len - 1 && s.charAt(i + 1) == '#') {
179
                             str.append("&#");
180
                             i += 2;
181

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

    
277
    /**
278
     * Method to get the name of local replication server
279
     */
280
    public static String getLocalReplicationServerName()
281
    {
282
        String replicationServerName = null;
283
        // String serverHost = null;
284
        // serverHost = getProperty("server");
285
        // append "context/servlet/replication" to the host name
286
        try {
287
        replicationServerName = 
288
        	SystemUtil.getSecureServer() 
289
        	+ "/" 
290
			+ PropertyService.getProperty("application.context")
291
			+ "/servlet/replication";
292
        } catch (PropertyNotFoundException pnfe) {
293
        	logMetacat.error("Could not get local replication server name " 
294
        			+ "because property could not be found: " + pnfe.getMessage());
295
        }
296
        return replicationServerName;
297

    
298
    }
299

    
300
    /** A method to replace whitespace in url */
301
    public static String replaceWhiteSpaceForURL(String urlHasWhiteSpace)
302
    {
303
        StringBuffer newUrl = new StringBuffer();
304
        String whiteSpaceReplace = "%20";
305
        if (urlHasWhiteSpace == null || urlHasWhiteSpace.trim().equals("")) { return null; }
306

    
307
        for (int i = 0; i < urlHasWhiteSpace.length(); i++) {
308
            char ch = urlHasWhiteSpace.charAt(i);
309
            if (!Character.isWhitespace(ch)) {
310
                newUrl.append(ch);
311
            } else {
312
                //it is white sapce, replace it by %20
313
                newUrl = newUrl.append(whiteSpaceReplace);
314
            }
315

    
316
        }//for
317
        logMetacat.info("The new string without space is:"
318
                + newUrl.toString());
319
        return newUrl.toString();
320

    
321
    }// replaceWhiteSpaceForUR
322

    
323
    /**
324
	 * Writes debug information into a file. In metacat.properties, if property
325
	 * application.writeDebugToFile is set to true, the debug information will be written to
326
	 * debug file, which value is the property application.debugOutputFile in
327
	 * metacat.properties.
328
	 * 
329
	 */
330
	public static void writeDebugToFile(String debugInfo) {
331
		String debug = "false";
332
		try {
333
			debug = PropertyService.getProperty("application.writeDebugToFile");
334
			if (debug != null && debug.equalsIgnoreCase("true")) {
335
				File outputFile = 
336
					new File(PropertyService.getProperty("application.debugOutputFile"));
337
				FileOutputStream fos = new FileOutputStream(outputFile, true);
338
				PrintWriter pw = new PrintWriter(fos);
339
				pw.println(debugInfo);
340
				pw.flush();
341
				pw.close();
342
				fos.close();
343
			}
344
		} catch (PropertyNotFoundException pnfe) {
345
			// only log debug to file warning once
346
			if (!debugErrorDisplayed) {
347
				logMetacat.warn("Could not get debug property.  Write debug to " 
348
						+ "file is set to false: " + pnfe.getMessage());
349
				debugErrorDisplayed = true;
350
			}
351
		} catch (Exception io) {
352
			logMetacat.warn("Error in MetacatUtil.writeDebugToFile "
353
					+ io.getMessage());
354
		}
355
	}
356
    
357
   /**
358
	 * Writes debug information into a file in delimitered format
359
	 * 
360
	 * @param debugInfo
361
	 *            the debug information
362
	 * @param newLine
363
	 *            append the debug info to a line or not
364
	 */
365
	public static void writeDebugToDelimiteredFile(String debugInfo, boolean newLine) {
366
		String debug = "false";
367
		try {
368
			debug = PropertyService.getProperty("application.writeDebugToFile");
369
			if (debug != null && debug.equalsIgnoreCase("true")) {
370
				File outputFile = new File(PropertyService
371
						.getProperty("application.delimiteredOutputFile"));
372
				FileOutputStream fos = new FileOutputStream(outputFile, true);
373
				PrintWriter pw = new PrintWriter(fos);
374
				if (newLine) {
375
					pw.println(debugInfo);
376
				} else {
377
					pw.print(debugInfo);
378
				}
379
				pw.flush();
380
				pw.close();
381
				fos.close();
382
			}
383
		} catch (PropertyNotFoundException pnfe) {
384
			// only log debug to file warning once
385
			if (!debugErrorDisplayed) {
386
				logMetacat.warn("Could not get delimited debug property. Write debug to " 
387
						+ "file is set to false: " + pnfe.getMessage());
388
				debugErrorDisplayed = true;
389
			}
390
		} catch (Exception io) {
391
			logMetacat.warn("Eorr in writeDebugToDelimiteredFile "
392
					+ io.getMessage());
393
		}
394
	}
395

    
396
	/**
397
	 * Write the uploaded file to disk for temporary storage before moving it to
398
	 * its final Metacat location.
399
	 * 
400
	 * @param filePart
401
	 *            the FilePart object containing the file form element
402
	 * @param fileName
403
	 *            the name of the file to be written to disk
404
	 * @return tempFilePath a String containing location of temporary file
405
	 */
406
    public static File writeTempUploadFile (FileItem fi, String fileName) throws Exception {
407
        File tempFile = null;
408
        String tempDirPath = null;
409
        try {
410
        	tempDirPath = PropertyService.getProperty("application.tempDir") + FileUtil.getFS() + "uploads";
411
        } catch (PropertyNotFoundException pnfe) {
412
        	logMetacat.warn("Temp property not found.  An attempt will be made " 
413
        			+ "to use system temp directory: " + pnfe.getMessage());
414
        }
415
        long fileSize;
416
        File tempDir;
417

    
418
        if ((fileName == null) || fileName.equals("")) {
419
            return tempFile;
420
        }
421
				
422
        // the tempfilepath token isn't set, use Java default
423
		if (tempDirPath == null) {
424
			String javaTempDir = System.getProperty("java.io.tempdir");
425
			if (javaTempDir == null) {
426
				// no paths set, use unix default
427
				tempDirPath = "/tmp";
428
			} else {
429
				tempDirPath = javaTempDir;
430
			}
431
		}
432

    
433
        tempDir = new File(tempDirPath);
434

    
435
		// Create the temporary directory if it doesn't exist
436
		try {
437
			if (!tempDir.exists()) {
438
				tempDir.mkdirs();
439
			}
440
		} catch (SecurityException e) {
441
			throw new IOException("Can't create directory: " + tempDir.getPath() + ". Error: "
442
					+ e.getMessage());
443
		}
444

    
445
		//tempFile = new File(tempDirPath, fileName);
446
		tempFile = File.createTempFile("upload", ".tmp", tempDir);
447
		fi.write(tempFile);
448
		fileSize = fi.getSize();
449

    
450
		if (fileSize == 0) {
451
			logMetacat.warn("Uploaded file '" + fileName + "'is empty!");
452
		}
453

    
454
        logMetacat.debug("Temporary file is: " + tempFile.getAbsolutePath());
455

    
456
        return tempFile;
457
    }
458

    
459
    /**
460
	 * 
461
	 * Copy a file between two locations specified as strings. Fails if either
462
	 * path cannot be created. Based on the public domain FileCopy class in
463
	 * _Java in a Nutshell_.
464
	 * 
465
	 * @param sourceName
466
	 *            the source file to read from disk
467
	 * @param destName
468
	 *            the destination file on disk
469
	 */
470
    public static void copyFile(String sourceName, String destName) throws IOException {
471

    
472
        File sourceFile = new File(sourceName);
473
        File destFile = new File(destName);
474
        FileInputStream source = null;
475
        FileOutputStream dest = null;
476
        byte[] buffer;
477
        int bytesRead;
478

    
479
        try {
480
            if (!sourceFile.exists() || !sourceFile.isFile()) {
481
                logMetacat.error("File copy: no such source" +
482
                                 " file: " + sourceName);
483
            }
484
            if (!sourceFile.canRead()) {
485
                logMetacat.error("File copy: source file " +
486
                                 "is unreadable: " + sourceName);
487
            }
488

    
489
            if (destFile.exists()) {
490
                if (destFile.isFile()) {
491
                    if (!destFile.canWrite()) {
492
                        logMetacat.error("File copy: destination " +
493
                                         "file is unwriteable: " + destFile);
494
                    }
495
                } else {
496
                    logMetacat.error("File copy: destination file " +
497
                                     "is not a file: " + destFile);
498
                }
499
            } else {
500
                File parentDir = parent(destFile);
501

    
502
                if (!parentDir.exists())
503
                {
504
                    logMetacat.error("File copy: destination diretory " +
505
                                     " doesn't exist: " + destName);
506
                }
507
                if (!parentDir.canWrite()) {
508
                    logMetacat.error("File copy: destination directory " +
509
                                     " is unwritable: " + destName);
510
                }
511
            }
512

    
513
            // Verbose error checking done, copy the file object
514
            source = new FileInputStream(sourceFile);
515
            dest = new FileOutputStream(destFile);
516
            buffer = new byte[1024];
517

    
518
            while (true) {
519
                bytesRead = source.read(buffer);
520
                if (bytesRead == -1) {
521
                    break;
522
                }
523
                dest.write(buffer, 0, bytesRead);
524
            }
525
        }
526
        finally {
527
            if (source != null) {
528
                try { source.close(); } catch (IOException e) { ; }
529
            }
530
            if (dest != null) {
531
                try { dest.close(); } catch (IOException e) { ; }
532
            }
533
        }
534
    }
535

    
536
    private static File parent(File f) {
537
        String dirname = f.getParent();
538
        if (dirname == null) {
539
            if (f.isAbsolute()) return new File(File.separator);
540
            else return new File(System.getProperty("user.dir"));
541
        }
542
        return new File(dirname);
543
    }
544
}
(11-11/18)