/*
* Copyright (C) 2008 Universidade Federal de Campina Grande
*
* This file is part of OurGrid.
*
* OurGrid is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.ourgrid.common.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import org.ourgrid.discoveryservice.DiscoveryServiceConstants;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLoggerFactory;
import br.edu.ufcg.lsd.commune.identification.ServiceID;
/**
* This is a auxiliar class that incloses many util functionalities related to
* strings.
*/
public class StringUtil {
public static final int VARCHAR_MAX_LENGTH = 255;
private static final String USER_SERVER_SEPARATOR = "@";
private static final String COMMUNE_ADDRESS_SEPARATOR = ";";
static CommuneLogger logger = CommuneLoggerFactory.getInstance().gimmeALogger(StringUtil.class);
/**
* Writes the given string into the given file.
*
* @param file The file where the string have to be written (appended).
* @param s the string to be written into the file
* @throws IOException If the file could not be used (created) or any other
* I/O problem at the open, writte or close moment.
*/
public static void writeStringOnFile( String file, String s ) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream( file, true );
fos.write( s.getBytes() );
} finally {
if ( fos != null ) {
fos.close();
}
}
}
/**
* Replaces at the a String a patter to another.
*
* @param str The String where will be made the changes.
* @param subOld The pattern that will be removed.
* @param subNew The pattern that will be inserted.
* @return the new string with the changes made if any was necessary, or the
* same string if any changes was needed.
*/
public static String replace( String str, String subOld, String subNew ) {
int i = str.indexOf( subOld );
if ( i == -1 ) {
return str;
}
StringBuffer stb = new StringBuffer( str );
stb.replace( i, i + subOld.length(), subNew );
return replace( stb.toString(), subOld, subNew );
}
/**
* Receives an array of String and returns a simple string of all separeted
* by a ","
*/
public static String passToString( String[ ] orig ) {
String attrib = new String();
if ( orig.length != 0 ) {
attrib = orig[0];
for ( int i = 1; i < orig.length; i++ ) {
attrib += ", " + orig[i];
}
} else
attrib = "";
return attrib;
}
/**
*
* @param file
* @return
* @throws IOException
*/
public static StringBuffer readFile(File file) throws IOException {
BufferedReader reader = null;
StringWriter result = new StringWriter();
PrintWriter writer = new PrintWriter(result);
try {
reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
writer.println(line);
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
throw e;
}
}
}
return result.getBuffer();
}
/**
* Receives a simple String and returns a array containing all words of the
* String supressed the "," - it is the delimiter
*
* @param strToArray string that must be transformed to an array.
* @return an array of strings based on the string parameter.
*/
public static String[ ] passToArrayStr( String strToArray ) {
String[ ] returnArray = {};
if ( strToArray == null ) {
return returnArray;
}
StringTokenizer noComma = new StringTokenizer( strToArray, "," );
returnArray = new String[ noComma.countTokens() ];
for ( int i = 0; noComma.hasMoreTokens(); returnArray[i++] = noComma.nextToken().trim() ) {
// Trim over all tokens
}
return returnArray;
}
/**
* Inserts a white space at a specific point.
*
* @param expr the string where the space have to be inserted.
* @param i the specific point where the space have to be inserted
* @return the changed string if the position is valid or the same string
* otherwise.
*/
public static String insertSpace( String expr, int i ) {
StringBuffer str = new StringBuffer( expr );
try {
str.insert( i, " " );
} catch ( StringIndexOutOfBoundsException sobex ) {
// do nothing, returns the string like it was received.
}
return str.toString();
}
/**
* This method fills value with the characters at right.
*
* @param value - The string to be filled with white space caracters
* @param character - The character to be used in the filling of the string
* @param numChars - The number of characters to insert in the string.
*/
public static String fillWithChars( String value, char character, int numChars ) {
StringBuffer formatted = new StringBuffer();
formatted.append( value );
for ( int i = 0; i < numChars; i++ ) {
formatted.append( character );
}
return formatted.toString();
}
/**
* Insert spaces in the sentence expr. This is necessary in order to
* StringTokenizer can function properlly when matching sentence of the
* task.
*
* @param expr The sentence that spaces will be inserted
* @return The modified sentence (with spaces)
*/
public static String insertSpaces( String expr ) {
if ( expr != null ) {
for ( int i = 0; i < expr.length(); i++ ) {
if ((expr.charAt(i) == '(')) {
if ((i != (expr.length() - 1)) && (expr.charAt(i + 1) != ' ')) {
expr = insertSpace(expr, i + 1);
}
if ((i >= 1) && (expr.charAt(i - 1) != ' ')) {
expr = insertSpace(expr, i);
}
i++;
} else if ( (expr.charAt( i ) == ')') && (i != 0) && (expr.charAt( i - 1 ) != ' ') ) {
expr = insertSpace( expr, i );
i++;
} else if ( (expr.charAt( i ) == '&') || (expr.charAt( i ) == '|') ) { // Symbol
// can
// be
// &&
// or
// ||
int skip = 1;
boolean changedAhead = false;
if ( (i != (expr.length() - 2)) && (expr.charAt( i + 2 ) != ' ') ) {
expr = insertSpace( expr, i + 2 );
skip++;
changedAhead = true;
}
if ( (i != 0) && (expr.charAt( i - 1 ) != ' ') && changedAhead ) {
expr = insertSpace( expr, i );
skip++;
} else if ( (i != 0) && (expr.charAt( i - 1 ) != ' ') ) {
expr = insertSpace( expr, i );
skip++;
}
i += skip;
} else if ( (expr.charAt( i ) == '=') || (expr.charAt( i ) == '<') || (expr.charAt( i ) == '>')
|| (expr.charAt( i ) == '!') ) {
int skip = 1;
if ( expr.charAt( i + 1 ) == '=' ) { // Symbol can be ==
// or
// >=
// or <=
if ( (i != (expr.length() - 2)) && (expr.charAt( i + 2 ) != ' ') ) {
expr = insertSpace( expr, i + 2 );
skip++;
}
if ( (i != 0) && (expr.charAt( i - 1 ) != ' ') ) {
expr = insertSpace( expr, i );
skip++;
}
} else { // Symbol can be only < or >
if ( i != (expr.length() - 1) && (expr.charAt( i + 1 ) != ' ') ) {
expr = insertSpace( expr, i + 1 );
}
if ( (i != 0) && (expr.charAt( i - 1 ) != ' ') ) {
expr = insertSpace( expr, i );
skip++;
}
}
i += skip;
}
}
}
return expr;
}
/**
* This method does a job that is expected to be done by the shell: it
* converts variables to String literals.
*
* @param stringWithVariables A string with 0 or more variables.
* @return A String without any variables.
*/
public static String replaceVariables( String stringWithVariables, Map<String, String> envVars ) {
String stringWithoutVariables = stringWithVariables;
if ( envVars != null ) {
Set<Entry<String, String>> entries = envVars.entrySet();
for (Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
stringWithoutVariables = StringUtil.replace( stringWithoutVariables, "$" + key, value);
}
}
return stringWithoutVariables;
}
/**
* This method parse a permissions file from stringo to int
*
* @param permStr The file permission as drwxrwxrwx
* @return int
*/
public static int parsePermissionString( String permStr ) {
int perm_o = 0;
int perm_g = 0;
int perm_u = 0;
if ( permStr.charAt( 0 ) == 'r' )
perm_o = perm_o + 4;
if ( permStr.charAt( 1 ) == 'w' )
perm_o = perm_o + 2;
if ( permStr.charAt( 2 ) == 'x' )
perm_o = perm_o + 1;
if ( permStr.charAt( 3 ) == 'r' )
perm_g = perm_g + 4;
if ( permStr.charAt( 4 ) == 'w' )
perm_g = perm_g + 2;
if ( permStr.charAt( 5 ) == 'x' )
perm_g = perm_g + 1;
if ( permStr.charAt( 6 ) == 'r' )
perm_u = perm_u + 4;
if ( permStr.charAt( 7 ) == 'w' )
perm_u = perm_u + 2;
if ( permStr.charAt( 8 ) == 'x' )
perm_u = perm_u + 1;
return (perm_o * 100) + (perm_g * 10) + (perm_u);
}
/**
* Gets a array of string and return a string that contains the strings
* separated by commas
*
* @param strings The array of strings
* @return A string with strings separated by commas
*/
public static String getStringSeparatedByCommas( String[ ] strings ) {
StringBuffer strAttributes = new StringBuffer();
if ( strings == null ) {
return "";
}
for ( int indexStrings = 0; indexStrings < strings.length; indexStrings++ ) {
strAttributes.append( strings[indexStrings] );
strAttributes.append( "," );
}
if ( strAttributes.length() == 0 ) {
return "";
}
return strAttributes.substring( 0, strAttributes.length() - 1 );
}
/**
* Gets a array of strings after broken with the given delimitator
*
* @param string A string that will broken in an array of strings
* @param delimitator The delimitator between strings
* @return An array with the strings of "string" parameter
*/
public static String[ ] getArrayOfStrings( String string, String delimitator ) {
StringTokenizer strToken = new StringTokenizer( string, delimitator );
String[ ] strings = new String[ strToken.countTokens() ];
int indexStrings = 0;
while ( strToken.hasMoreTokens() ) {
strings[indexStrings] = (String) strToken.nextElement();
indexStrings++;
}
return strings;
}
private static final String SECONDS = "s";
private static final String MINUTES = "m";
private static final String HOURS = "h";
private static final String DAYS = "d";
/**
* Converts an amount of time (in seconds) in an user-friendly text.
*
* @param timeInSeconds The amount of time (in seconds).
* @return A <code>String</code> with the amount of time in ( <i>ww</i> d
* <i>xx</i> h <i>yy</i> m <i>zz</i> s)
*/
public static String getTimeAsText( long timeInSeconds ) {
if ( timeInSeconds == 0 )
return timeInSeconds + SECONDS;
long seconds = timeInSeconds;
long minutes = 0;
long hours = 0;
long days = 0;
if ( seconds >= 60 ) {
minutes = seconds / 60;
seconds %= 60;
if ( minutes >= 60 ) {
hours = minutes / 60;
minutes %= 60;
if ( hours >= 24 ) {
days = hours / 24;
hours %= 24;
}
}
}
String duration = "" + (days > 0 ? days + DAYS + " " : "") + (hours > 0 ? hours + HOURS + " " : "")
+ (minutes > 0 ? minutes + MINUTES + " " : "") + (seconds > 0 ? seconds + SECONDS + " " : "");
return duration.trim();
}
/**
* Returns a random String of numbers and letters (lower and upper case)
* of the specified length. The method uses the Random class that is
* built-in to Java which is suitable for low to medium grade security uses.
* This means that the output is only pseudo random, i.e., each number is
* mathematically generated so is not truly random.<p>
* <p/>
* The specified length must be at least one. If not, the method will return
* null.
*
* @param length the desired length of the random String to return.
* @return a random String of numbers and letters of the specified length.
*/
public static String randomString(int length) {
if (length < 1) {
return null;
}
// Create a char buffer to put random letters and numbers in.
char[] randBuffer = new char[length];
for (int i = 0; i < randBuffer.length; i++) {
randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
}
return new String(randBuffer);
}
/**
* Pseudo-random number generator object for use with randomString().
* The Random class is not considered to be cryptographically secure, so
* only use these random Strings for low to medium security applications.
*/
private static Random randGen = new Random();
/** Array of numbers and letters of mixed case. Numbers appear in the list
* twice so that there is a more equal chance that a number will be picked.
* We can use the array to get a random number or letter by picking a random
* array index.
*/
private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
public static String concatAddresses(
Set<String> addresses) {
StringBuilder sb = new StringBuilder();
for (String address : addresses) {
sb.append(address).append(';');
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
/**
* Returns a {@link ServiceID} list of DiscoveryService identifications.
* It parses an {@link String} in the following pattern:
* dsuser1@dsserver1;dsuser2@dsserver2
*
* @param networkString
* @return
*/
public static List<ServiceID> splitDiscoveryServiceAddresses(String networkString) {
List<ServiceID> dsIDs = new LinkedList<ServiceID>();
String[] addresses = networkString.split(COMMUNE_ADDRESS_SEPARATOR);
for (String address : addresses) {
String[] splitAddress = splitAddress(address);
if (splitAddress.length != 2) {
logger.warn("Parsing Discovery Service addresses: [" + address
+ "] is not a valid commune address.");
continue;
}
ServiceID dsServiceID = new ServiceID(splitAddress[0], splitAddress[1],
DiscoveryServiceConstants.MODULE_NAME, DiscoveryServiceConstants.DS_OBJECT_NAME );
dsIDs.add(dsServiceID);
}
return dsIDs;
}
public static ServiceID userAtServerToServiceID(String userAtServer){
if(userAtServer == null){
return null;
}
String[] splitAddress = splitAddress(userAtServer);
ServiceID dsServiceID = new ServiceID(splitAddress[0], splitAddress[1],
DiscoveryServiceConstants.MODULE_NAME, DiscoveryServiceConstants.DS_OBJECT_NAME );
return dsServiceID;
}
public static String[] splitAddress(String address) {
return address.split(USER_SERVER_SEPARATOR);
}
public static String addressToUserAtServer(String serviceId){
return serviceId.split("/")[0];
}
public static String addressToContainerID(String address) {
String[] split = address.split("/");
return split[0] + "/" + split[1];
}
public static String userAtServerToAddress(String userAtServer,
String moduleName, String objectName) {
return userAtServer + "/" + moduleName + "/" + objectName;
}
public static String deploymentIDToContainerID(String deploymentID) {
return addressToContainerID(deploymentID);
}
public static String deploymentIDToAddress(String workerDeploymentID) {
return workerDeploymentID == null ? null : workerDeploymentID.substring(0, workerDeploymentID.lastIndexOf('/'));
}
public static String deploymentIDToUserAtServer(String workerID) {
return addressToUserAtServer(deploymentIDToAddress(workerID));
}
public static String joinStrings(String delim, Collection<String> info) {
StringBuilder sb = new StringBuilder();
Iterator<String> iterator = info.iterator();
if (iterator.hasNext()) {
sb.append(iterator.next());
while (iterator.hasNext()){
sb.append(delim);
sb.append(iterator.next());
}
}
return sb.toString();
}
public static String shrink(String varchar) {
if (varchar == null) {
return null;
}
return varchar.substring(0, varchar.length() > StringUtil.VARCHAR_MAX_LENGTH ?
StringUtil.VARCHAR_MAX_LENGTH : varchar.length());
}
}