Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements system utility methods 
4
 *  Copyright: 2008 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Michael Daigle
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.IOException;
30
import java.util.Vector;
31
import java.util.regex.Matcher;
32
import java.util.regex.Pattern;
33
import javax.servlet.ServletContext;
34
import javax.servlet.http.HttpServletRequest;
35

    
36
import org.apache.log4j.Logger;
37

    
38
import edu.ucsb.nceas.metacat.MetaCatVersion;
39
import edu.ucsb.nceas.metacat.service.PropertyService;
40
import edu.ucsb.nceas.metacat.service.ServiceException;
41
import edu.ucsb.nceas.metacat.service.ServiceService;
42
import edu.ucsb.nceas.utilities.FileUtil;
43
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
44
import edu.ucsb.nceas.utilities.StringUtil;
45

    
46
public class SystemUtil {
47

    
48
	private static Logger logMetacat = Logger.getLogger(SystemUtil.class);
49
	private static String METACAT_SERVLET = "metacat";
50
	private static int OS_CLASS = 0;
51
	
52
	// Class of OS.  If we need more granularity, we should create a version
53
	// list and access it separately.
54
	public static int WIN_OS = 1;
55
	public static int LINUX_OS = 2;
56
	public static int MAC_OS = 3;
57
	public static int OTHER_OS = 4;
58
	
59
	/**
60
	 * private constructor - all methods are static so there is no no need to
61
	 * instantiate.
62
	 */
63
	private SystemUtil() {}
64

    
65
	/**
66
	 * Get the OS for this system.
67
	 * @return an integer representing the class of OS.  Possibilities are:
68
	 *     WIN_OS = 1;
69
	 *     LINUX_OS = 2;
70
	 *     MAC_OS = 3;
71
	 *     OTHER_OS = 4;
72
	 */
73
	public static int getOsClass() {
74
		if (OS_CLASS > 0) {
75
			return OS_CLASS;
76
		}
77
		
78
		String osName = System.getProperty("os.name");
79
		if (osName.startsWith("Windows")) {
80
			OS_CLASS =  WIN_OS;
81
		} else if (osName.startsWith("Linux")) {
82
			OS_CLASS =  LINUX_OS;
83
		} else if (osName.startsWith("Mac")) {
84
			OS_CLASS =  MAC_OS;
85
		} else if (osName.startsWith("Mac")) {
86
			OS_CLASS =  OTHER_OS;
87
		}
88
		
89
		return OS_CLASS;
90
	}
91
	
92
	/**
93
	 * Attempt to discover the server name. The name is retrieved from the http
94
	 * servlet request. This is used by configuration routines before the port
95
	 * has been populated in metacat.properties. it is possible the port that
96
	 * the user configures might be different than the name we get here. You
97
	 * should use getServerPort() instead of this method whenever possible.
98
	 * 
99
	 * @param request
100
	 *            the http servlet request we will use to find the server name
101
	 * 
102
	 * @return a string holding the server name
103
	 */
104
	public static String discoverServerName(HttpServletRequest request) {
105
		String serverName = request.getServerName();
106

    
107
		return serverName;
108
	}
109

    
110
	/**
111
	 * Attempt to discover the server port. The port is retrieved from the http
112
	 * servlet request. This is used by configuration routines before the port
113
	 * has been populated in metacat.properties. it is possible the port that
114
	 * the user configures might be different than the port we get here. You
115
	 * should use getServerPort() instead of this method whenever possible.
116
	 * 
117
	 * @param request
118
	 *            the http servlet request we will use to find the server port
119
	 * 
120
	 * @return a string holding the server port
121
	 */
122
	public static String discoverServerPort(HttpServletRequest request) {
123
		return Integer.toString(request.getServerPort());
124
	}
125
	
126
	/**
127
	 * Attempt to discover the server ssl port. The ssl port is assumed using
128
	 * the standard port. This is used by configuration routines before the port
129
	 * has been populated in metacat.properties. it is possible the prot that
130
	 * the user configures might be different than the port we get here. You
131
	 * should use getServerSSLPort() instead of this method whenever possible.
132
	 * 
133
	 * @param request
134
	 *            the http servlet request we will use to find the server port
135
	 * 
136
	 * @return a string holding the server ssl port
137
	 */
138
	public static String discoverServerSSLPort(HttpServletRequest request) {
139
		String serverPort = discoverServerPort(request);
140

    
141
		if (serverPort.length() == 4 && serverPort.charAt(0) == '8') {
142
			return "8443";
143
		}
144

    
145
		return "443";
146
	}
147

    
148
	/**
149
	 * Get the server URL which is made up of the server name + : + the http
150
	 * port number. Note that if the port is 80, it is left off.
151
	 * 
152
	 * @return string holding the server URL
153
	 */
154
	public static String getServerURL() throws PropertyNotFoundException {
155
		String ServerURL = "http://" + PropertyService.getProperty("server.name");
156
		String httpPort = PropertyService.getProperty("server.httpPort");
157
		if (!httpPort.equals("80")) {
158
			ServerURL += ":" + httpPort;
159
		}
160

    
161
		return ServerURL;
162
	}
163

    
164
	/**
165
	 * Get the secure server URL which is made up of the server name + : + the
166
	 * https port number. Note that if the port is 443, it is left off.
167
	 * 
168
	 * @return string holding the server URL
169
	 */
170
	public static String getSecureServerURL() throws PropertyNotFoundException {
171
		String ServerURL = "https://" + getSecureServer();
172
		return ServerURL;
173
	}
174
	
175
	/**
176
	 * Get the secure server  which is made up of the server name + : + the
177
	 * https port number. Note that if the port is 443, it is left off.
178
	 * NOTE: does NOT include "https://"
179
	 * @see getSecureServerURL()
180
	 * 
181
	 * @return string holding the secure server
182
	 */
183
	public static String getSecureServer() throws PropertyNotFoundException {
184
		String server = PropertyService.getProperty("server.name");
185
		String httpPort = PropertyService.getProperty("server.httpSSLPort");
186
		if (!httpPort.equals("443")) {
187
			server = server + ":" + httpPort;
188
		}
189

    
190
		return server;
191
	}
192

    
193
	/**
194
	 * Get the CGI URL which is made up of the server URL + file separator + the
195
	 * CGI directory
196
	 * 
197
	 * @return string holding the server URL
198
	 */
199
	public static String getCGI_URL() throws PropertyNotFoundException{
200
		return getContextURL() 
201
				+ PropertyService.getProperty("application.cgiDir");
202
	}
203

    
204
	/**
205
	 * Get the server URL with the context. This is made up of the server URL +
206
	 * file separator + the context
207
	 * 
208
	 * @return string holding the server URL with context
209
	 */
210
	public static String getContextURL() throws PropertyNotFoundException {
211
		return getServerURL() + "/"
212
				+ PropertyService.getProperty("application.context");
213
	}
214

    
215
	/**
216
	 * Get the servlet URL. This is made up of the server URL with context +
217
	 * file separator + the metacat servlet name
218
	 * 
219
	 * @return string holding the servlet URL
220
	 */
221
	public static String getServletURL() throws PropertyNotFoundException {
222
		return getContextURL() + "/" + METACAT_SERVLET;
223
	}
224

    
225
	/**
226
	 * Get the style skins URL. This is made up of the server URL with context +
227
	 * file separator + "style" + file separator + "skins"
228
	 * 
229
	 * @return string holding the style skins URL
230
	 */
231
	public static String getStyleSkinsURL() throws PropertyNotFoundException {
232
		return getContextURL() + "/" + "style" + "/" + "skins";
233
	}
234

    
235
	/**
236
	 * Get the style common URL. This is made up of the server URL with context +
237
	 * file separator + "style" + file separator + "common"
238
	 * 
239
	 * @return string holding the style common URL
240
	 */
241
	public static String getStyleCommonURL() throws PropertyNotFoundException {
242
		return getContextURL() + "/" + "style" + "/" + "common";
243
	}
244
	
245
	/**
246
	 * Get the metacat version by getting the string representation from
247
	 * metacat.properties and instantiating a MetaCatVersion object.
248
	 * The info is set in build.properties and then populated into metacat.properties
249
	 * at build time using Ant token replacement.
250
	 * 
251
	 * @return a MetaCatVersion object holding metacat version information
252
	 */
253
	public static MetaCatVersion getMetacatVersion() throws PropertyNotFoundException {
254
		String metacatVersionString = 
255
			PropertyService.getProperty("application.metacatVersion");
256
		return new MetaCatVersion(metacatVersionString);
257
	}
258
	
259
	/**
260
	 * Gets a string that holds some description about the release. Typically this is 
261
	 * used during release candidates for display purposes and might hold something
262
	 * like "Release Candidate 1".  Normally it is empty for final production release.
263
	 * The info is set in build.properties and then populated into metacat.properties
264
	 * at build time using Ant token replacement.
265
	 * 
266
	 * @return a MetaCatVersion object holding metacat version information
267
	 */
268
	public static String getMetacatReleaseInfo() throws PropertyNotFoundException {
269
		return PropertyService.getProperty("application.metacatReleaseInfo");
270
	}
271

    
272
	/**
273
	 * Get the context directory. This is made up of the deployment directory + file
274
	 * separator + context
275
	 * 
276
	 * @return string holding the context directory
277
	 */
278
	public static String getContextDir() throws PropertyNotFoundException {
279
		return PropertyService.getProperty("application.deployDir") + FileUtil.getFS()
280
				+ PropertyService.getProperty("application.context");
281
	}
282

    
283
	/**
284
	 * Attempt to discover the context for this application. This is a best
285
	 * guess scenario. It is used by configuration routines before the context
286
	 * has been populated in metacat.properties. You should always use
287
	 * getApplicationContext() instead of this method if possible.
288
	 * 
289
	 * @param servletContext
290
	 *            the servlet context we will use to find the application context
291
	 * 
292
	 * @return a string holding the context
293
	 */
294
	public static String discoverApplicationContext(ServletContext servletContext) {
295
		String applicationContext = "";
296
		String realPath = servletContext.getRealPath("/");
297

    
298
		if (realPath.charAt(realPath.length() - 1) == '/') {
299
			realPath = realPath.substring(0, realPath.length() - 1);
300
		}
301
		
302
		int lastSlashIndex = realPath.lastIndexOf('/');
303
		if (lastSlashIndex != -1) {
304
			applicationContext = realPath.substring(lastSlashIndex + 1);
305
		}
306
				
307
		logMetacat.debug("application context: " + applicationContext);
308

    
309
		return applicationContext;
310
	}
311
	
312
	/**
313
	 * Gets the stored backup location.  This location is held in a file at
314
	 * <user_home>/.<application_context>/backup-location
315
	 * 
316
	 * @return a string holding the backup location.  Null if none could be found.
317
	 */
318
	public static String getStoredBackupDir() throws UtilException {
319
		String applicationContext = null;
320
		try {
321
			applicationContext = ServiceService.getRealApplicationContext();
322
			// Check if there is a file at
323
			// <user_home>/<application_context>/backup-location. If so, it
324
			// should contain one line that is a file that points to a writable
325
			// directory. If that is true, use that value as the backup dir.
326
			String storedBackupFileLoc = getUserHomeDir() + FileUtil.getFS() + "."
327
					+ applicationContext + FileUtil.getFS() + "backup-location";
328
			if (FileUtil.getFileStatus(storedBackupFileLoc) >= FileUtil.EXISTS_READABLE) {
329
				String storedBackupDirLoc = FileUtil
330
						.readFileToString(storedBackupFileLoc);
331
				if (FileUtil.isDirectory(storedBackupDirLoc)
332
						&& FileUtil.getFileStatus(storedBackupDirLoc) > FileUtil.EXISTS_READABLE) {
333
					return storedBackupDirLoc;
334
				}
335
			}
336
		} catch (IOException ioe) {
337
			logMetacat.warn("I/O problem finding backup location: " + ioe.getMessage());
338
		} catch (ServiceException se) {
339
			logMetacat.warn("Could not get real application context: " + se.getMessage());
340
		}
341
		return null;
342
	}
343
	
344
	public static void writeStoredBackupFile(String backupPath) throws UtilException {
345
		String applicationContext = null;
346
		try {
347
			applicationContext = ServiceService.getRealApplicationContext();
348
			// Write the backup path to
349
			// <user_home>/.<application_context>/backup-location. 
350
			String storedBackupFileDir = getUserHomeDir() + FileUtil.getFS() + "." + applicationContext;
351
			String storedBackupFileLoc = storedBackupFileDir + FileUtil.getFS() + "backup-location";
352
			if (!FileUtil.isDirectory(storedBackupFileDir)) {
353
				FileUtil.createDirectory(storedBackupFileDir);
354
			}
355
			if (FileUtil.getFileStatus(storedBackupFileLoc) == FileUtil.DOES_NOT_EXIST) {
356
				FileUtil.createFile(storedBackupFileLoc);
357
			}		
358
			if (FileUtil.getFileStatus(storedBackupFileLoc) < FileUtil.EXISTS_READ_WRITABLE) {
359
				throw new UtilException("Stored backup location file is not writable: " + storedBackupFileLoc);
360
			}
361
			
362
			FileUtil.writeFile(storedBackupFileLoc, backupPath);
363
			
364
		} catch (IOException ioe) {
365
			logMetacat.warn("I/O proplem finding backup location: " + ioe.getMessage());
366
		} catch (ServiceException se) {
367
			logMetacat.warn("Could not get real application context: " + se.getMessage());
368
		}
369
	}
370
	
371
	/**
372
	 * Attempt to discover the external (to the metacat installation)
373
	 * directory where metacat will hold backup files.   This functionality 
374
	 * is used to populate the configuration utility initially.  The user 
375
	 * can change the directory manually, so you can't rely on this method 
376
	 * to give you the actual directory.  Here are the steps taken to discover
377
	 * the directory:
378
	 * 
379
     * -- 1) Look for an existing hidden (.<application_context>) directory in a default system directory.  Get 
380
	 *       the default base directory for the OS.  (See application.windowsBackupBaseDir and 
381
	 *       application.linuxBackupBaseDir in metacat.properties.)  If a directory called 
382
	 *       <base_dir>/metacat/.<application_context> exists, return <base_dir>/metacat.
383
	 * -- 2) Otherwise, look for an existing hidden (.metacat) directory in the user directory. If a directory 
384
	 *       called <user_dir>/metacat/.<application_context> exists for the user that started tomcat, 
385
	 *       return <user_dir>/metacat.
386
	 * -- 3) Otherwise, look for an existing metacat directory in a default system directory.  Get 
387
	 *       the default base directory for the OS.  (See application.windowsBackupBaseDir and 
388
	 *       application.linuxBackupBaseDir in metacat.properties.)  If a directory called 
389
	 *       <base_dir>/metacat exists, return <base_dir>/metacat.
390
	 * -- 4) Otherwise, look for an existing metacat directory in the user directory. If a directory 
391
	 *       called <user_dir>/metacat/ exists for the user that started tomcat, return <user_dir>/metacat.
392
	 * -- 5) Otherwise, is the <base_dir> writable by the user that started tomcat?  If so, return 
393
	 *       <base_dir>/metacat
394
	 * -- 6) Does the <user_home> exist?  If so, return <user_home>/metacat
395
	 * -- 7) Otherwise, return null
396
	 *    
397
	 * @return a string holding the backup directory path
398
	 */
399
	public static String discoverExternalDir() throws UtilException {
400
		String applicationContext = null; 
401
		
402
		try {
403
			applicationContext = ServiceService.getRealApplicationContext();
404
			
405
			// Set the default location using the os
406
			String systemDir = "";
407
			if (getOsClass() == WIN_OS) {
408
				systemDir = PropertyService.getProperty("application.windowsBackupBaseDir");
409
			} else {
410
				systemDir = PropertyService.getProperty("application.linuxBackupBaseDir");
411
			}	
412
			String systemMetacatDir = systemDir + FileUtil.getFS() + "metacat";
413
			String systemBackupDir = systemMetacatDir + FileUtil.getFS() + "."
414
					+ applicationContext;
415

    
416
			String userHomeDir = getUserHomeDir();
417
			String userHomeMetacatDir = userHomeDir + FileUtil.getFS() + "metacat";
418
			String userHomeBackupDir = userHomeMetacatDir + FileUtil.getFS() + "." + applicationContext;
419

    
420
			// If <system_dir>/metacat/.<application_context> exists writable, 
421
			// return <system_dir>/metacat
422
			if ((FileUtil.getFileStatus(systemBackupDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
423
				return systemMetacatDir;
424
			}
425

    
426
			// Otherwise if <user_dir>/metacat/.<application_context> exists writable, return
427
			// <user_dir>/metacat
428
			if ((FileUtil.getFileStatus(userHomeBackupDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
429
				return userHomeMetacatDir;
430
			}
431

    
432
			// Otherwise if <system_dir>/metacat exists writable, create 
433
			// <system_dir>/metacat/.<application_context> and return <system_dir>/metacat
434
			if ((FileUtil.getFileStatus(systemMetacatDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
435
				// go ahead and create the backup hidden dir
436
				FileUtil.createDirectory(systemBackupDir);
437
				return systemMetacatDir;
438
			}
439

    
440
			// Otherwise if <user_dir>/metacat exists writable, create 
441
			// <user_dir>/metacat/.<application_context> and return <user_dir>/metacat
442
			if ((FileUtil.getFileStatus(userHomeMetacatDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
443
				// go ahead and create the backup hidden dir
444
				FileUtil.createDirectory(userHomeBackupDir);
445
				return userHomeMetacatDir;
446
			}
447
			
448
			// Otherwise if <system_dir> exists, create 
449
			// <system_dir>/metacat/.<application_context> and return <system_dir>/metacat
450
			if ((FileUtil.getFileStatus(systemDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
451
				// go ahead and create the backup hidden dir
452
				FileUtil.createDirectory(systemBackupDir);
453
				return systemMetacatDir;
454
			}
455

    
456
			// Otherwise if <user_dir> exists, return <user_dir> create 
457
			// <user_dir>/metacat/.<application_context> and return <user_dir>/metacat
458
			if ((FileUtil.getFileStatus(userHomeDir) >= FileUtil.EXISTS_READ_WRITABLE)) {
459
				// go ahead and create the backup hidden dir
460
				FileUtil.createDirectory(userHomeBackupDir);
461
				return userHomeMetacatDir;
462
			}
463

    
464
		} catch (IOException ioe) {
465
			logMetacat.warn("I/O proplem finding backup location: " + ioe.getMessage());
466
		} catch (ServiceException se) {
467
			logMetacat.warn("Could not get real application context: " + se.getMessage());
468
		} catch (PropertyNotFoundException pnfe) {
469
			logMetacat.warn("Could not get default backup base dir property: "
470
					+ pnfe.getMessage());
471
		}
472
	
473
		// Otherwise, return userHomeDir
474
		return null;
475
	}
476
	
477
	/**
478
	 * Store the location of the backup file location into a file at 
479
	 * <user_home>/<application_dir>/backup-location
480
	 * 
481
	 * @param externalDir the backup file location.
482
	 */
483
	public static void storeExternalDirLocation(String externalDir) {
484
		if (getUserHomeDir() != null) {
485
			String applicationContext = null;
486
			String storedBackupLocDir = null;
487
			String storedBackupLocFile = null;
488
			try {
489
				applicationContext = ServiceService.getRealApplicationContext();
490
				storedBackupLocDir = getUserHomeDir() + FileUtil.getFS() + "."
491
						+ applicationContext;
492
				storedBackupLocFile = storedBackupLocDir + FileUtil.getFS()
493
						+ "backup-location";
494
			
495
				FileUtil.createDirectory(storedBackupLocDir);
496
				FileUtil.writeFile(storedBackupLocFile, externalDir);
497
			} catch (IOException ioe) {
498
				logMetacat.error("I/O error while trying to write stored backup directory: "
499
							+ storedBackupLocFile + " : " + ioe.getMessage());
500
			} catch (ServiceException se) {
501
				logMetacat.error("Could not get real application directory while trying to write "
502
							+ "stored backup directory: "+ storedBackupLocFile + " : " + se.getMessage());
503
			}
504
		} else {
505
			logMetacat.warn("Could not write out stored backup directory." 
506
					+ " User directory does not exist");
507
		}
508
	}
509

    
510
	/**
511
	 * Get the style skins directory. This is made up of the tomcat directory
512
	 * with context + file separator + "style" + file separator + "skins"
513
	 * 
514
	 * @return string holding the style skins directory
515
	 */
516
	public static String getStyleSkinsDir() throws PropertyNotFoundException {
517
		return getContextDir() + FileUtil.getFS() + "style" + FileUtil.getFS()
518
				+ "skins";
519
	}
520

    
521
	/**
522
	 * Get the SQL directory. This is made up of the context directory + file
523
	 * separator + sql
524
	 * 
525
	 * @return string holding the sql directory
526
	 */
527
	public static String getSQLDir() throws PropertyNotFoundException {
528
		return getContextDir() + FileUtil.getFS() + "WEB-INF" + FileUtil.getFS() + "sql";
529
	}
530

    
531
	/**
532
	 * Get the default style URL from metacat.properties.
533
	 * 
534
	 * @return string holding the default style URL
535
	 */
536
	public static String getDefaultStyleURL() throws PropertyNotFoundException {
537
		return getStyleCommonURL() + "/"
538
				+ PropertyService.getProperty("application.default-style");
539
	}
540

    
541
	/**
542
	 * Attempt to discover the deployment directory for this application. This is a
543
	 * best guess scenario. It is used by configuration routines before the
544
	 * deployment directory has been populated in metacat.properties. 
545
	 * 
546
	 * @param request
547
	 *            the http servlet request we will use to find the tomcat directory
548
	 * 
549
	 * @return a string holding the web application directory
550
	 */
551
	public static String discoverDeployDir(HttpServletRequest request) {
552
		ServletContext servletContext = request.getSession()
553
				.getServletContext();
554
		String realPath = servletContext.getRealPath(".");
555
		String contextPath = request.getContextPath();
556
		
557
		logMetacat.debug("realPath: " + realPath);
558
		logMetacat.debug("contextPath: " + contextPath);
559

    
560
		Pattern pattern = Pattern.compile(contextPath + "/\\.$");
561
		Matcher matcher = pattern.matcher(realPath);
562
		
563
		if (matcher.find()) {
564
			realPath = matcher.replaceFirst("");
565
		}
566
		
567
		return realPath;
568
	}
569
	
570
	/**
571
	 * Get the current user's home directory
572
	 * 
573
	 * @return a string holding the home directory
574
	 */
575
	public static String getUserHomeDir() {
576
		return System.getProperty("user.home");
577
	}
578
	
579
	/**
580
	 * Get a list of xml paths that need to be indexed
581
	 */
582
	public static Vector<String> getPathsForIndexing() throws UtilException {
583
		Vector <String> indexPaths = null;
584
		try {
585
			indexPaths = 
586
				StringUtil.toVector(PropertyService.getProperty("xml.indexPaths"), ',');
587
		} catch (PropertyNotFoundException pnfe) {
588
			throw new UtilException("could not get index paths: " + pnfe.getMessage());
589
		}
590
		
591
		return indexPaths;
592
	}
593
 }
(11-11/12)