/*
* Copyright 1999-2010 University of Chicago
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/
package org.globus.util;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.globus.common.CoGProperties;
public class Util {
private static final String CHMOD = "chmod";
private static final String DMSG =
"Destroyed by Java Globus Proxy Destroy\r\n";
/**
* Attempts to create a new file in an atomic way.
* If the file already exists, it if first deleted.
*
* @param filename the name of file to create.
* @return the created file.
* @throws SecurityException if the existing file cannot be deleted.
* @throws IOException if an I/O error occurred.
*/
public static File createFile(String filename)
throws SecurityException, IOException {
File f = new File(filename);
if (!f.createNewFile()) {
if (!destroy(f)) {
throw new SecurityException(
"Could not destroy existing file");
}
if (!f.createNewFile()) {
throw new SecurityException(
"Failed to atomically create new file");
}
}
return f;
}
/**
* Sets permissions on a given file to be only accessible by the current
* user.
*
* @see #setFilePermissions(String, int)
*/
public static boolean setOwnerAccessOnly(String file) {
return setFilePermissions(file, 600);
}
/**
* Sets permissions on a given file. The permissions
* are set using the <i>chmod</i> command and will only
* work on Linux/Unix machines. <i>Chmod</i> command must be in the path.
* <BR><BR><B>Note: </B><I>
* This function executes an external program; thus, its behavior is
* influenced by environment variables such as the caller's PATH and the
* environment variables that control dynamic loading. Care should be
* used if calling this function from a program that will be run as a
* Unix setuid program, or in any other manner in which the owner of the
* Unix process does not completely control its runtime environment.
* </I>
*
* @param file the file to set the permissions of.
* @param mode the Unix style permissions.
* @return true, if change was successful, otherwise false.
* It can return false, in many instances, e.g. when file
* does not exits, when chmod is not found, or other error
* occurs.
*/
public static boolean setFilePermissions(String file, int mode) {
// since this will not work on Windows
if (ConfigUtil.getOS() == ConfigUtil.WINDOWS_OS) {
return false;
}
Runtime runtime = Runtime.getRuntime();
String [] cmd = new String[] { CHMOD,
String.valueOf(mode),
file };
Process process = null;
try {
process = runtime.exec(cmd, null);
return (process.waitFor() == 0) ? true : false;
} catch(Exception e) {
return false;
} finally {
if (process != null) {
try {
process.getErrorStream().close();
} catch (IOException e) {}
try {
process.getInputStream().close();
} catch (IOException e) {}
try {
process.getOutputStream().close();
} catch (IOException e) {}
}
}
}
/**
* Overwrites the contents of the file with a random
* string and then deletes the file.
*
* @param file file to remove
*/
public static boolean destroy(String file) {
return destroy(new File(file));
}
/**
* Overwrites the contents of the file with a random
* string and then deletes the file.
*
* @param file file to remove
*/
public static boolean destroy(File file) {
if (!file.exists()) return false;
RandomAccessFile f = null;
long size = file.length();
try {
f = new RandomAccessFile(file, "rw");
long rec = size/DMSG.length();
int left = (int)(size - rec*DMSG.length());
while(rec != 0) {
f.write(DMSG.getBytes(), 0, DMSG.length());
rec--;
}
if (left > 0) {
f.write(DMSG.getBytes(), 0, left);
}
} catch(Exception e) {
return false;
} finally {
try {
if (f != null) f.close();
} catch(Exception e) {}
}
return file.delete();
}
/**
* Displays a prompt and then reads in the input from System.in.
*
* @param prompt the prompt to be displayed
* @return <code>String</code> the input read in (entered after the prompt)
*/
public static String getInput(String prompt) {
System.out.print(prompt);
try {
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in));
return in.readLine();
} catch(IOException e) {
return null;
}
}
/**
* Displays a prompt and then reads in private input from System.in.
* Characters typed by the user are replaced with a space on the screen.
*
* @param prompt the prompt to be displayed
* @return <code>String</code> the input read in (entered after the prompt)
*/
public static String getPrivateInput(String prompt) {
System.out.print(prompt);
PrivateInputThread privateInput = new PrivateInputThread();
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in));
privateInput.start();
try {
return in.readLine();
} catch(Exception e) {
return null;
} finally {
privateInput.kill();
}
}
/**
* A helper thread to mask private user input.
*/
private static class PrivateInputThread extends Thread {
private volatile boolean stopThread = false;
public void kill() {
this.stopThread = true;
}
public void run() {
while(!this.stopThread) {
System.out.print("\b ");
try {
sleep(1);
} catch(InterruptedException e) { }
}
}
}
/**
* Quotifies a specified string.
* The entire string is encompassed by double quotes and each
* " is replaced with \", \ is replaced with \\.
*
* @param str the string to quotify
* @return quotified and escaped string
*/
public static String quote(String str) {
int len = str.length();
StringBuffer buf = new StringBuffer(len+2);
buf.append("\"");
char c;
for (int i=0;i<len;i++) {
c = str.charAt(i);
if (c == '"' || c == '\\') {
buf.append("\\");
}
buf.append(c);
}
buf.append("\"");
return buf.toString();
}
/**
* Dequotifies a specified string.
* The quotes are removed and each \" is replaced with " and
* each \\ is replaced with \.
*
* @param str the string to dequotify.
* @return unquotified string.
*/
public static String unquote(String str)
throws Exception {
int len = str.length();
StringBuffer buf = new StringBuffer(len);
boolean inQuotes = false;
char c;
int i = 0;
if (str.charAt(i) == '"') {
inQuotes = true;
i++;
}
while(i < len) {
c = str.charAt(i);
if (inQuotes) {
if (c == '"') {
inQuotes = false;
} else if (c == '\\') {
buf.append(str.charAt(++i));
} else {
buf.append(c);
}
} else {
if (c == '\r') {
if (str.charAt(i++) != '\n') {
throw new Exception("Malformed string.");
}
} else if (c == '"') {
inQuotes = true;
i++;
} else {
buf.append(c);
}
}
i++;
}
return buf.toString();
}
/**
* The function decodes URL-encoded strings into a regular string.
* This function is mostly copied from the Java source code.
* To convert to a <code>String</code>, each character is examined in turn:
* <ul>
* <li>The remaining characters are represented by 3-character
* strings which begin with the percent sign,
* "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
* hexadecimal representation of the lower 8-bits of the character.
* </ul>
*/
public static String decode(String s) {
StringBuffer sb = new StringBuffer();
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '%':
try {
sb.append((char)Integer.parseInt(
s.substring(i+1,i+3),16));
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
i += 2;
break;
default:
sb.append(c);
break;
}
}
// Undo conversion to external encoding
String result = sb.toString();
try {
byte[] inputBytes = result.getBytes("8859_1");
result = new String(inputBytes);
} catch (UnsupportedEncodingException e) {
// The system should always have 8859_1
}
return result;
}
/**
* Generates string representation of given time specified
* as long. The format is: [days][,][h][,][min][,][sec]
*
*/
public static String formatTimeSec(long time) {
StringBuffer str = new StringBuffer();
if (time < 60) {
str.append(time + " sec");
return str.toString();
}
int days = (int) time / 86400;
if (days != 0) {
str.append(days + " days");
time -= days * 86400;
}
int hours = (int) time / 3600;
if (hours != 0) {
if (str.length() != 0) str.append(", ");
str.append(hours + " h");
time -= hours * 3600;
}
int mins = (int) time / 60;
if (mins != 0) {
if (str.length() != 0) str.append(", ");
str.append(mins + " min");
time -= mins * 60;
}
int sec = (int) time;
if (sec != 0) {
if (str.length() != 0) str.append(", ");
str.append(sec + " sec");
}
return str.toString();
}
/**
* Returns the ip address of the local machine.
* If the 'ip' system property is defined it is returned,
* otherwise, the local ip address is lookup using the
* <code>InetAddress</code> class. In case the lookup
* fails, the address 127.0.0.1 is returned.
*
* @return local ip address
*/
public static String getLocalHostAddress() {
String ipAddr = CoGProperties.getDefault().getIPAddress();
if (ipAddr == null) {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
return "127.0.0.1";
}
} else {
return ipAddr;
}
}
}