[Major] refactored use of log4j to slf4j
This commit is contained in:
parent
2fc807fe11
commit
3f5bf2d334
14
pom.xml
14
pom.xml
|
@ -7,6 +7,7 @@
|
|||
<packaging>jar</packaging>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>ch.eitchnet.utils</name>
|
||||
<description>These utils contain project independent helper classes and utilities for reuse</description>
|
||||
<url>https://github.com/eitch/ch.eitchnet.utils</url>
|
||||
|
||||
<properties>
|
||||
|
@ -82,9 +83,15 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -132,7 +139,6 @@
|
|||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
<!--mainClass>ch.eitchnet.App</mainClass -->
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
|
|
@ -24,7 +24,8 @@ import java.io.FileInputStream;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.eitchnet.utils.helper.FileHelper;
|
||||
import ch.eitchnet.utils.helper.StringHelper;
|
||||
|
@ -37,7 +38,7 @@ import ch.eitchnet.utils.helper.StringHelper;
|
|||
*/
|
||||
public class RmiFileHandler {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RmiFileHandler.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(RmiFileHandler.class);
|
||||
|
||||
/**
|
||||
* DEF_PART_SIZE = default part size which is set to 1048576 bytes (1 MiB)
|
||||
|
|
|
@ -25,7 +25,8 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.eitchnet.utils.helper.FileHelper;
|
||||
import ch.eitchnet.utils.helper.StringHelper;
|
||||
|
@ -36,7 +37,7 @@ import ch.eitchnet.utils.helper.StringHelper;
|
|||
*/
|
||||
public class RmiHelper {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RmiHelper.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(RmiHelper.class);
|
||||
|
||||
/**
|
||||
* @param rmiFileClient
|
||||
|
|
|
@ -36,7 +36,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper class for dealing with files
|
||||
|
@ -45,7 +46,7 @@ import org.apache.log4j.Logger;
|
|||
*/
|
||||
public class FileHelper {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FileHelper.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(FileHelper.class);
|
||||
|
||||
/**
|
||||
* Reads the contents of a file into a string. Note, no encoding is checked. It is expected to be UTF-8
|
||||
|
@ -55,7 +56,7 @@ public class FileHelper {
|
|||
* @return the contents of a file as a string
|
||||
*/
|
||||
public static final String readFileToString(File file) {
|
||||
|
||||
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
|
||||
|
@ -195,7 +196,8 @@ public class FileHelper {
|
|||
String fromFileMD5 = StringHelper.getHexString(FileHelper.hashFileMd5(fromFile));
|
||||
String toFileMD5 = StringHelper.getHexString(FileHelper.hashFileMd5(toFile));
|
||||
if (!fromFileMD5.equals(toFileMD5)) {
|
||||
FileHelper.logger.error("Copying failed, as MD5 sums are not equal: " + fromFileMD5 + " / " + toFileMD5);
|
||||
FileHelper.logger.error("Copying failed, as MD5 sums are not equal: " + fromFileMD5 + " / "
|
||||
+ toFileMD5);
|
||||
toFile.delete();
|
||||
|
||||
return false;
|
||||
|
@ -204,8 +206,8 @@ public class FileHelper {
|
|||
|
||||
// cleanup if files are not the same length
|
||||
if (fromFile.length() != toFile.length()) {
|
||||
FileHelper.logger.error("Copying failed, as new files are not the same length: " + fromFile.length() + " / "
|
||||
+ toFile.length());
|
||||
FileHelper.logger.error("Copying failed, as new files are not the same length: " + fromFile.length()
|
||||
+ " / " + toFile.length());
|
||||
toFile.delete();
|
||||
|
||||
return false;
|
||||
|
@ -213,7 +215,7 @@ public class FileHelper {
|
|||
|
||||
} catch (Exception e) {
|
||||
|
||||
FileHelper.logger.error(e, e);
|
||||
FileHelper.logger.error(e.getMessage(), e);
|
||||
return false;
|
||||
|
||||
} finally {
|
||||
|
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012
|
||||
*
|
||||
* This file is part of ch.eitchnet.java.utils
|
||||
*
|
||||
* ch.eitchnet.java.utils 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.
|
||||
*
|
||||
* ch.eitchnet.java.utils 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 ch.eitchnet.java.utils. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.utils.helper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.log4j.BasicConfigurator;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
|
||||
/**
|
||||
* A simple configurator to configure log4j, with fall back default configuration
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class Log4jConfigurator {
|
||||
|
||||
/**
|
||||
* system property used to override the log4j configuration file
|
||||
*/
|
||||
public static final String PROP_FILE_LOG4J = "rsp.log4j.properties";
|
||||
|
||||
/**
|
||||
* default log4j configuration file
|
||||
*/
|
||||
public static final String FILE_LOG4J = "log4j.properties";
|
||||
|
||||
/**
|
||||
* runtime log4j configuration file which is a copy of the original file but has any place holders overwritten
|
||||
*/
|
||||
public static final String FILE_LOG4J_TEMP = "log4j.properties.tmp";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Log4jConfigurator.class);
|
||||
private static Log4jPropertyWatchDog watchDog;
|
||||
|
||||
/**
|
||||
* Configures log4j with the default {@link ConsoleAppender}
|
||||
*/
|
||||
public static synchronized void configure() {
|
||||
Log4jConfigurator.cleanupOldWatchdog();
|
||||
BasicConfigurator.resetConfiguration();
|
||||
BasicConfigurator.configure(new ConsoleAppender(Log4jConfigurator.getDefaulLayout()));
|
||||
Logger.getRootLogger().setLevel(Level.INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default layout: %d %5p [%t] %C{1} %M - %m%n
|
||||
*
|
||||
* @return the default layout
|
||||
*/
|
||||
public static PatternLayout getDefaulLayout() {
|
||||
return new PatternLayout("%d %5p [%t] %C{1} %M - %m%n");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Loads the log4j configuration
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This file is configurable through the {@link Log4jConfigurator#PROP_FILE_LOG4J} system property, but uses the
|
||||
* default {@link Log4jConfigurator#FILE_LOG4J} file, if no configuration option is set. The path used is
|
||||
* <user.dir>/config/ whereas <user.dir> is a system property
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Any properties in the properties are substituted using
|
||||
* {@link StringHelper#replaceProperties(Properties, Properties)} and then the configuration file is written to a
|
||||
* new file <user.dir>/tmp/ {@link Log4jConfigurator#FILE_LOG4J_TEMP} and then finally
|
||||
* {@link PropertyConfigurator#configureAndWatch(String)} is called so that the configuration is loaded and log4j
|
||||
* watches the temporary file for configuration changes
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void loadLog4jConfiguration() {
|
||||
|
||||
// get a configured log4j properties file, or use default
|
||||
// RSPConfigConstants.FILE_LOG4J
|
||||
String fileLog4j = SystemHelper.getProperty(Log4jConfigurator.class.getName(),
|
||||
Log4jConfigurator.PROP_FILE_LOG4J, Log4jConfigurator.FILE_LOG4J);
|
||||
|
||||
// get the root directory
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String configDir = userDir + "/config/";
|
||||
|
||||
String pathNameToLog4j = configDir + fileLog4j;
|
||||
File log4JPath = new File(pathNameToLog4j);
|
||||
|
||||
try {
|
||||
|
||||
// load the log4j.properties file
|
||||
if (!log4JPath.exists())
|
||||
throw new RuntimeException("The log4j configuration file does not exist at "
|
||||
+ log4JPath.getAbsolutePath());
|
||||
|
||||
// now perform the loading
|
||||
Log4jConfigurator.loadLog4jConfiguration(log4JPath);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
Log4jConfigurator.configure();
|
||||
Log4jConfigurator.logger.error(e, e);
|
||||
Log4jConfigurator.logger.error("Log4j COULD NOT BE INITIALIZED. Please check the log4j configuration file exists at "
|
||||
+ log4JPath.getAbsolutePath());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Loads the given log4j configuration
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Any properties in the properties are substituted using
|
||||
* {@link StringHelper#replaceProperties(Properties, Properties)} and then the configuration file is written to a
|
||||
* new file <user.dir>/tmp/ {@link Log4jConfigurator#FILE_LOG4J_TEMP} and then finally
|
||||
* {@link PropertyConfigurator#configureAndWatch(String)} is called so that the configuration is loaded and log4j
|
||||
* watches the temporary file for configuration changes
|
||||
* </p>
|
||||
*
|
||||
* @param log4jConfigPath
|
||||
*/
|
||||
public static synchronized void loadLog4jConfiguration(File log4jConfigPath) {
|
||||
|
||||
if (log4jConfigPath == null)
|
||||
throw new RuntimeException("log4jConfigPath may not be null!");
|
||||
|
||||
// first clean up any old watch dog in case of a programmatic re-load of the configuration
|
||||
Log4jConfigurator.cleanupOldWatchdog();
|
||||
|
||||
// get the root directory
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String tmpDir = userDir + "/tmp/";
|
||||
|
||||
String pathNameToLog4jTemp = tmpDir + Log4jConfigurator.FILE_LOG4J_TEMP;
|
||||
Properties log4jProperties = new Properties();
|
||||
FileInputStream fin = null;
|
||||
FileOutputStream fout = null;
|
||||
|
||||
try {
|
||||
|
||||
fin = new FileInputStream(log4jConfigPath);
|
||||
log4jProperties.load(fin);
|
||||
fin.close();
|
||||
|
||||
// replace any variables
|
||||
StringHelper.replaceProperties(log4jProperties, System.getProperties());
|
||||
|
||||
// write this as the temporary log4j file
|
||||
File logsFileDir = new File(tmpDir);
|
||||
if (!logsFileDir.exists() && !logsFileDir.mkdirs())
|
||||
throw new RuntimeException("Could not create log path " + logsFileDir.getAbsolutePath());
|
||||
|
||||
fout = new FileOutputStream(pathNameToLog4jTemp);
|
||||
log4jProperties.store(fout, "Running instance log4j configuration " + new Date());
|
||||
fout.close();
|
||||
|
||||
// XXX if the server is in a web context, then we may not use the
|
||||
// FileWatchDog
|
||||
BasicConfigurator.resetConfiguration();
|
||||
Log4jConfigurator.watchDog = new Log4jPropertyWatchDog(pathNameToLog4jTemp);
|
||||
Log4jConfigurator.watchDog.start();
|
||||
|
||||
Log4jConfigurator.logger.info("Log4j is configured to use and watch file " + pathNameToLog4jTemp);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
Log4jConfigurator.configure();
|
||||
Log4jConfigurator.logger.error(e, e);
|
||||
Log4jConfigurator.logger.error("Log4j COULD NOT BE INITIALIZED. Please check the log4j configuration file at "
|
||||
+ log4jConfigPath);
|
||||
|
||||
} finally {
|
||||
if (fin != null) {
|
||||
try {
|
||||
fin.close();
|
||||
} catch (IOException e) {
|
||||
Log4jConfigurator.logger.error("Exception closing input file: " + e, e);
|
||||
}
|
||||
}
|
||||
if (fout != null) {
|
||||
try {
|
||||
fout.close();
|
||||
} catch (IOException e) {
|
||||
Log4jConfigurator.logger.error("Exception closing output file: " + e, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Loads the log4j configuration file as a class resource by calling {@link Class#getResourceAsStream(String)} for
|
||||
* the given class
|
||||
* </p>
|
||||
*
|
||||
* @param clazz
|
||||
*/
|
||||
public static synchronized void loadLog4jConfigurationAsResource(Class<?> clazz) {
|
||||
|
||||
try {
|
||||
|
||||
if (clazz == null)
|
||||
throw new RuntimeException("clazz may not be null!");
|
||||
|
||||
InputStream resourceAsStream = clazz.getResourceAsStream("/" + Log4jConfigurator.FILE_LOG4J);
|
||||
if (resourceAsStream == null) {
|
||||
throw new RuntimeException("The resource '" + Log4jConfigurator.FILE_LOG4J + "' could not be found for class "
|
||||
+ clazz.getName());
|
||||
}
|
||||
|
||||
// load the properties from the input stream
|
||||
Properties log4jProperties = new Properties();
|
||||
log4jProperties.load(resourceAsStream);
|
||||
|
||||
// and then
|
||||
Log4jConfigurator.loadLog4jConfiguration(log4jProperties);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log4jConfigurator.configure();
|
||||
Log4jConfigurator.logger.error(e, e);
|
||||
Log4jConfigurator.logger.error("Log4j COULD NOT BE INITIALIZED. Please check that the log4j configuration file '"
|
||||
+ Log4jConfigurator.FILE_LOG4J + "' exists as a resource for class " + clazz.getName()
|
||||
+ " and is a valid properties configuration");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Loads the given log4j configuration. Log4j is configured with the given properties. The only change is that
|
||||
* {@link StringHelper#replaceProperties(Properties, Properties)} is used to replace any properties
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* No property watch dog is loaded
|
||||
* </p>
|
||||
*
|
||||
* @param log4jProperties
|
||||
* the properties to use for the log4j configuration
|
||||
*/
|
||||
public static synchronized void loadLog4jConfiguration(Properties log4jProperties) {
|
||||
|
||||
try {
|
||||
|
||||
if (log4jProperties == null)
|
||||
throw new RuntimeException("log4jProperties may not be null!");
|
||||
|
||||
// first clean up any old watch dog in case of a programmatic re-load of the configuration
|
||||
Log4jConfigurator.cleanupOldWatchdog();
|
||||
|
||||
// replace any variables
|
||||
StringHelper.replaceProperties(log4jProperties, System.getProperties());
|
||||
|
||||
// now configure log4j
|
||||
PropertyConfigurator.configure(log4jProperties);
|
||||
Log4jConfigurator.logger.info("Log4j is configured using the given properties.");
|
||||
|
||||
} catch (Exception e) {
|
||||
Log4jConfigurator.configure();
|
||||
Log4jConfigurator.logger.error(e, e);
|
||||
Log4jConfigurator.logger.error("Log4j COULD NOT BE INITIALIZED. The given log4jProperties seem not to be valid!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup a running watch dog
|
||||
*/
|
||||
public static synchronized void cleanupOldWatchdog() {
|
||||
// clean up an old watch dog
|
||||
if (Log4jConfigurator.watchDog != null) {
|
||||
Log4jConfigurator.logger.info("Stopping old Log4j watchdog.");
|
||||
Log4jConfigurator.watchDog.interrupt();
|
||||
try {
|
||||
Log4jConfigurator.watchDog.join(1000l);
|
||||
} catch (InterruptedException e) {
|
||||
Log4jConfigurator.logger.error("Oops. Could not terminate an old WatchDog.");
|
||||
} finally {
|
||||
Log4jConfigurator.watchDog = null;
|
||||
}
|
||||
Log4jConfigurator.logger.info("Done.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012
|
||||
*
|
||||
* This file is part of ch.eitchnet.java.utils
|
||||
*
|
||||
* ch.eitchnet.java.utils 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.
|
||||
*
|
||||
* ch.eitchnet.java.utils 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 ch.eitchnet.java.utils. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.utils.helper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class Log4jPropertyWatchDog extends Thread {
|
||||
|
||||
/**
|
||||
* The default delay between every file modification check, set to 60 seconds.
|
||||
*/
|
||||
public static final long DEFAULT_DELAY = 60000;
|
||||
|
||||
/**
|
||||
* The name of the file to observe for changes.
|
||||
*/
|
||||
protected String filename;
|
||||
|
||||
/**
|
||||
* The delay to observe between every check. By default set {@link #DEFAULT_DELAY}.
|
||||
*/
|
||||
protected long delay = Log4jPropertyWatchDog.DEFAULT_DELAY;
|
||||
|
||||
protected File file;
|
||||
protected long lastModif = 0;
|
||||
protected boolean warnedAlready = false;
|
||||
protected boolean interrupted = false;
|
||||
|
||||
/**
|
||||
* @param filename
|
||||
*/
|
||||
protected Log4jPropertyWatchDog(String filename) {
|
||||
super("FileWatchdog");
|
||||
this.filename = filename;
|
||||
this.file = new File(filename);
|
||||
setDaemon(true);
|
||||
checkAndConfigure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay to observe between each check of the file changes.
|
||||
*/
|
||||
public void setDelay(long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected void checkAndConfigure() {
|
||||
boolean fileExists;
|
||||
try {
|
||||
fileExists = this.file.exists();
|
||||
} catch (SecurityException e) {
|
||||
LogLog.warn("Was not allowed to read check file existance, file:[" + this.filename + "].");
|
||||
this.interrupted = true; // there is no point in continuing
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileExists) {
|
||||
long l = this.file.lastModified(); // this can also throw a SecurityException
|
||||
if (l > this.lastModif) { // however, if we reached this point this
|
||||
this.lastModif = l; // is very unlikely.
|
||||
doOnChange();
|
||||
this.warnedAlready = false;
|
||||
}
|
||||
} else {
|
||||
if (!this.warnedAlready) {
|
||||
LogLog.debug("[" + this.filename + "] does not exist.");
|
||||
this.warnedAlready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link PropertyConfigurator#configure(String)} with the <code>filename</code> to reconfigure log4j.
|
||||
*/
|
||||
public void doOnChange() {
|
||||
PropertyConfigurator propertyConfigurator = new PropertyConfigurator();
|
||||
propertyConfigurator.doConfigure(this.filename, LogManager.getLoggerRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
while (!this.interrupted) {
|
||||
try {
|
||||
Thread.sleep(this.delay);
|
||||
} catch (InterruptedException e) {
|
||||
// no interruption expected
|
||||
this.interrupted = true;
|
||||
}
|
||||
checkAndConfigure();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,14 +24,15 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class ProcessHelper {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ProcessHelper.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProcessHelper.class);
|
||||
|
||||
public static ProcessResult runCommand(String command) {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
|
@ -40,8 +41,7 @@ public class ProcessHelper {
|
|||
|
||||
final Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
final BufferedReader errorStream = new BufferedReader(
|
||||
new InputStreamReader(process.getErrorStream()));
|
||||
final BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
Thread errorIn = new Thread("errorIn") {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -50,8 +50,7 @@ public class ProcessHelper {
|
|||
};
|
||||
errorIn.start();
|
||||
|
||||
final BufferedReader inputStream = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
final BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
Thread infoIn = new Thread("infoIn") {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -69,8 +68,7 @@ public class ProcessHelper {
|
|||
return new ProcessResult(returnValue, sb.toString(), null);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to perform command: "
|
||||
+ e.getLocalizedMessage(), e);
|
||||
throw new RuntimeException("Failed to perform command: " + e.getLocalizedMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
ProcessHelper.logger.error("Interrupted!");
|
||||
sb.append("[FATAL] Interrupted");
|
||||
|
@ -78,12 +76,10 @@ public class ProcessHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static ProcessResult runCommand(File workingDirectory,
|
||||
String... commandAndArgs) {
|
||||
public static ProcessResult runCommand(File workingDirectory, String... commandAndArgs) {
|
||||
|
||||
if (!workingDirectory.exists())
|
||||
throw new RuntimeException("Working directory does not exist at "
|
||||
+ workingDirectory.getAbsolutePath());
|
||||
throw new RuntimeException("Working directory does not exist at " + workingDirectory.getAbsolutePath());
|
||||
if (commandAndArgs == null || commandAndArgs.length == 0)
|
||||
throw new RuntimeException("No command passed!");
|
||||
|
||||
|
@ -97,8 +93,7 @@ public class ProcessHelper {
|
|||
|
||||
final Process process = processBuilder.start();
|
||||
|
||||
final BufferedReader errorStream = new BufferedReader(
|
||||
new InputStreamReader(process.getErrorStream()));
|
||||
final BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
Thread errorIn = new Thread("errorIn") {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -107,8 +102,7 @@ public class ProcessHelper {
|
|||
};
|
||||
errorIn.start();
|
||||
|
||||
final BufferedReader inputStream = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
final BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
Thread infoIn = new Thread("infoIn") {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -126,8 +120,7 @@ public class ProcessHelper {
|
|||
return new ProcessResult(returnValue, sb.toString(), null);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to perform command: "
|
||||
+ e.getLocalizedMessage(), e);
|
||||
throw new RuntimeException("Failed to perform command: " + e.getLocalizedMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
ProcessHelper.logger.error("Interrupted!");
|
||||
sb.append("[FATAL] Interrupted");
|
||||
|
@ -147,16 +140,14 @@ public class ProcessHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static void readStream(StringBuffer sb, String prefix,
|
||||
BufferedReader bufferedReader) {
|
||||
private static void readStream(StringBuffer sb, String prefix, BufferedReader bufferedReader) {
|
||||
String line;
|
||||
try {
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
sb.append(prefix + line + "\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
String msg = "Faild to read from " + prefix + " stream: "
|
||||
+ e.getLocalizedMessage();
|
||||
String msg = "Faild to read from " + prefix + " stream: " + e.getLocalizedMessage();
|
||||
sb.append("[FATAL] " + msg + "\n");
|
||||
}
|
||||
}
|
||||
|
@ -173,11 +164,9 @@ public class ProcessHelper {
|
|||
String pdfFile = pdfPath.getAbsolutePath();
|
||||
if (pdfFile.charAt(0) == '/')
|
||||
pdfFile = pdfFile.substring(1);
|
||||
processResult = ProcessHelper.runCommand("rundll32 url.dll,FileProtocolHandler "
|
||||
+ pdfFile);
|
||||
processResult = ProcessHelper.runCommand("rundll32 url.dll,FileProtocolHandler " + pdfFile);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unexpected OS: "
|
||||
+ SystemHelper.osName);
|
||||
throw new UnsupportedOperationException("Unexpected OS: " + SystemHelper.osName);
|
||||
}
|
||||
|
||||
ProcessHelper.logProcessResult(processResult);
|
||||
|
@ -187,14 +176,11 @@ public class ProcessHelper {
|
|||
if (processResult.returnValue == 0) {
|
||||
ProcessHelper.logger.info("Process executed successfully");
|
||||
} else if (processResult.returnValue == -1) {
|
||||
ProcessHelper.logger.error("Process execution failed:\n"
|
||||
+ processResult.processOutput);
|
||||
ProcessHelper.logger.error(processResult.t, processResult.t);
|
||||
ProcessHelper.logger.error("Process execution failed:\n" + processResult.processOutput);
|
||||
ProcessHelper.logger.error(processResult.t.getMessage(), processResult.t);
|
||||
} else {
|
||||
ProcessHelper.logger.info("Process execution was not successful with return value:"
|
||||
+ processResult.returnValue
|
||||
+ "\n"
|
||||
+ processResult.processOutput);
|
||||
+ processResult.returnValue + "\n" + processResult.processOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,465 +1,466 @@
|
|||
/*
|
||||
* Copyright (c) 2012
|
||||
*
|
||||
* This file is part of ch.eitchnet.java.utils
|
||||
*
|
||||
* ch.eitchnet.java.utils 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.
|
||||
*
|
||||
* ch.eitchnet.java.utils 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 ch.eitchnet.java.utils. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.utils.helper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* A helper class to perform different actions on {@link String}s
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class StringHelper {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(StringHelper.class);
|
||||
|
||||
/**
|
||||
* Hex char table for fast calculating of hex value
|
||||
*/
|
||||
static final byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
|
||||
(byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
|
||||
(byte) 'f' };
|
||||
|
||||
/**
|
||||
* Converts each byte of the given byte array to a HEX value and returns the concatenation of these values
|
||||
*
|
||||
* @param raw
|
||||
* the bytes to convert to String using numbers in hexadecimal
|
||||
*
|
||||
* @return the encoded string
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static String getHexString(byte[] raw) throws RuntimeException {
|
||||
try {
|
||||
byte[] hex = new byte[2 * raw.length];
|
||||
int index = 0;
|
||||
|
||||
for (byte b : raw) {
|
||||
int v = b & 0xFF;
|
||||
hex[index++] = StringHelper.HEX_CHAR_TABLE[v >>> 4];
|
||||
hex[index++] = StringHelper.HEX_CHAR_TABLE[v & 0xF];
|
||||
}
|
||||
|
||||
return new String(hex, "ASCII");
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Something went wrong while converting to HEX: " + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array of a given string by converting each character of the string to a number base 16
|
||||
*
|
||||
* @param encoded
|
||||
* the string to convert to a byt string
|
||||
*
|
||||
* @return the encoded byte stream
|
||||
*/
|
||||
public static byte[] fromHexString(String encoded) {
|
||||
if ((encoded.length() % 2) != 0)
|
||||
throw new IllegalArgumentException("Input string must contain an even number of characters.");
|
||||
|
||||
final byte result[] = new byte[encoded.length() / 2];
|
||||
final char enc[] = encoded.toCharArray();
|
||||
for (int i = 0; i < enc.length; i += 2) {
|
||||
StringBuilder curr = new StringBuilder(2);
|
||||
curr.append(enc[i]).append(enc[i + 1]);
|
||||
result[i / 2] = (byte) Integer.parseInt(curr.toString(), 16);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the MD5 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a
|
||||
* Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashMd5(String string) {
|
||||
return StringHelper.hashMd5(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the MD5 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array to
|
||||
* a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashMd5(byte[] bytes) {
|
||||
return StringHelper.hash("MD5", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a
|
||||
* Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha1(String string) {
|
||||
return StringHelper.hashSha1(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array
|
||||
* to a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha1(byte[] bytes) {
|
||||
return StringHelper.hash("SHA-1", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA-256 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to
|
||||
* a Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha256(String string) {
|
||||
return StringHelper.hashSha256(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array
|
||||
* to a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha256(byte[] bytes) {
|
||||
return StringHelper.hash("SHA-256", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash of an algorithm
|
||||
*
|
||||
* @param algorithm
|
||||
* the algorithm to use
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hash(String algorithm, byte[] bytes) {
|
||||
try {
|
||||
|
||||
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||
byte[] hashArray = digest.digest(bytes);
|
||||
|
||||
return hashArray;
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Algorithm " + algorithm + " does not exist!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the length of a String. Does not shorten it when it is too long, but lengthens it, depending on the
|
||||
* options set: adding the char at the beginning or appending it at the end
|
||||
*
|
||||
* @param value
|
||||
* string to normalize
|
||||
* @param length
|
||||
* length string must have
|
||||
* @param beginning
|
||||
* add at beginning of value
|
||||
* @param c
|
||||
* char to append when appending
|
||||
* @return the new string
|
||||
*/
|
||||
public static String normalizeLength(String value, int length, boolean beginning, char c) {
|
||||
return StringHelper.normalizeLength(value, length, beginning, false, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the length of a String. Shortens it when it is too long, giving out a logger warning, or lengthens it,
|
||||
* depending on the options set: appending the char at the beginning or the end
|
||||
*
|
||||
* @param value
|
||||
* string to normalize
|
||||
* @param length
|
||||
* length string must have
|
||||
* @param beginning
|
||||
* append at beginning of value
|
||||
* @param shorten
|
||||
* allow shortening of value
|
||||
* @param c
|
||||
* char to append when appending
|
||||
* @return the new string
|
||||
*/
|
||||
public static String normalizeLength(String value, int length, boolean beginning, boolean shorten, char c) {
|
||||
|
||||
if (value.length() == length)
|
||||
return value;
|
||||
|
||||
if (value.length() < length) {
|
||||
|
||||
String tmp = value;
|
||||
while (tmp.length() != length) {
|
||||
if (beginning) {
|
||||
tmp = c + tmp;
|
||||
} else {
|
||||
tmp = tmp + c;
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
|
||||
} else if (shorten) {
|
||||
|
||||
StringHelper.logger.warn("Shortening length of value: " + value);
|
||||
StringHelper.logger.warn("Length is: " + value.length() + " max: " + length);
|
||||
|
||||
return value.substring(0, length);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #replacePropertiesIn(Properties, String)}, with {@link System#getProperties()} as input
|
||||
*
|
||||
* @return a new string with all defined system properties replaced or if an error occurred the original value is
|
||||
* returned
|
||||
*/
|
||||
public static String replaceSystemPropertiesIn(String value) {
|
||||
return StringHelper.replacePropertiesIn(System.getProperties(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the given string searching for occurrences of ${...} sequences. Theses sequences are replaced with a
|
||||
* {@link Properties#getProperty(String)} value if such a value exists in the properties map. If the value of the
|
||||
* sequence is not in the properties, then the sequence is not replaced
|
||||
*
|
||||
* @param properties
|
||||
* the {@link Properties} in which to get the value
|
||||
* @param value
|
||||
* the value in which to replace any system properties
|
||||
*
|
||||
* @return a new string with all defined properties replaced or if an error occurred the original value is returned
|
||||
*/
|
||||
public static String replacePropertiesIn(Properties properties, String alue) {
|
||||
|
||||
// get a copy of the value
|
||||
String tmpValue = alue;
|
||||
|
||||
// get first occurrence of $ character
|
||||
int pos = -1;
|
||||
int stop = 0;
|
||||
|
||||
// loop on $ character positions
|
||||
while ((pos = tmpValue.indexOf('$', pos + 1)) != -1) {
|
||||
|
||||
// if pos+1 is not { character then continue
|
||||
if (tmpValue.charAt(pos + 1) != '{') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find end of sequence with } character
|
||||
stop = tmpValue.indexOf('}', pos + 1);
|
||||
|
||||
// if no stop found, then break as another sequence should be able to start
|
||||
if (stop == -1) {
|
||||
StringHelper.logger.error("Sequence starts at offset " + pos + " but does not end!");
|
||||
tmpValue = alue;
|
||||
break;
|
||||
}
|
||||
|
||||
// get sequence enclosed by pos and stop
|
||||
String sequence = tmpValue.substring(pos + 2, stop);
|
||||
|
||||
// make sure sequence doesn't contain $ { } characters
|
||||
if (sequence.contains("$") || sequence.contains("{") || sequence.contains("}")) {
|
||||
StringHelper.logger.error("Enclosed sequence in offsets " + pos + " - " + stop
|
||||
+ " contains one of the illegal chars: $ { }: " + sequence);
|
||||
tmpValue = alue;
|
||||
break;
|
||||
}
|
||||
|
||||
// sequence is good, so see if we have a property for it
|
||||
String property = properties.getProperty(sequence, "");
|
||||
|
||||
// if no property exists, then log and continue
|
||||
if (property.isEmpty()) {
|
||||
// logger.warn("No system property found for sequence " + sequence);
|
||||
continue;
|
||||
}
|
||||
|
||||
// property exists, so replace in value
|
||||
tmpValue = tmpValue.replace("${" + sequence + "}", property);
|
||||
}
|
||||
|
||||
return tmpValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #replaceProperties(Properties, Properties)} with null as the second argument. This allows for
|
||||
* replacing all properties with itself
|
||||
*
|
||||
* @param properties
|
||||
* the properties in which the values must have any ${...} replaced by values of the respective key
|
||||
*/
|
||||
public static void replaceProperties(Properties properties) {
|
||||
StringHelper.replaceProperties(properties, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks every value in the {@link Properties} and then then replaces any ${...} variables with keys in this
|
||||
* {@link Properties} value using {@link StringHelper#replacePropertiesIn(Properties, String)}
|
||||
*
|
||||
* @param properties
|
||||
* the properties in which the values must have any ${...} replaced by values of the respective key
|
||||
* @param altProperties
|
||||
* if properties does not contain the ${...} key, then try these alternative properties
|
||||
*/
|
||||
public static void replaceProperties(Properties properties, Properties altProperties) {
|
||||
|
||||
for (Object keyObj : properties.keySet()) {
|
||||
String key = (String) keyObj;
|
||||
String property = properties.getProperty(key);
|
||||
String newProperty = StringHelper.replacePropertiesIn(properties, property);
|
||||
|
||||
// try first properties
|
||||
if (!property.equals(newProperty)) {
|
||||
// logger.info("Key " + key + " has replaced property " + property + " with new value " + newProperty);
|
||||
properties.put(key, newProperty);
|
||||
} else if (altProperties != null) {
|
||||
|
||||
// try alternative properties
|
||||
newProperty = StringHelper.replacePropertiesIn(altProperties, property);
|
||||
if (!property.equals(newProperty)) {
|
||||
// logger.info("Key " + key + " has replaced property " + property + " from alternative properties with new value " + newProperty);
|
||||
properties.put(key, newProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper method with which it is possible to print the location in the two given strings where they start
|
||||
* to differ. The length of string returned is currently 40 characters, or less if either of the given strings are
|
||||
* shorter. The format of the string is 3 lines. The first line has information about where in the strings the
|
||||
* difference occurs, and the second and third lines contain contexts
|
||||
*
|
||||
* @param s1
|
||||
* the first string
|
||||
* @param s2
|
||||
* the second string
|
||||
*
|
||||
* @return the string from which the strings differ with a length of 40 characters within the original strings
|
||||
*/
|
||||
public static String printUnequalContext(String s1, String s2) {
|
||||
|
||||
byte[] bytes1 = s1.getBytes();
|
||||
byte[] bytes2 = s2.getBytes();
|
||||
int i = 0;
|
||||
for (; i < bytes1.length; i++) {
|
||||
if (i > bytes2.length)
|
||||
break;
|
||||
|
||||
if (bytes1[i] != bytes2[i])
|
||||
break;
|
||||
}
|
||||
|
||||
int maxContext = 40;
|
||||
int start = Math.max(0, (i - maxContext));
|
||||
int end = Math.min(i + maxContext, (Math.min(bytes1.length, bytes2.length)));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Strings are not equal! Start of inequality is at " + i + ". Showing " + maxContext
|
||||
+ " extra characters and start and end:\n");
|
||||
sb.append("context s1: " + s1.substring(start, end) + "\n");
|
||||
sb.append("context s2: " + s2.substring(start, end) + "\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given number of milliseconds to a time like 0.000s/ms
|
||||
*
|
||||
* @param millis
|
||||
* the number of milliseconds
|
||||
*
|
||||
* @return format the given number of milliseconds to a time like 0.000s/ms
|
||||
*/
|
||||
public static String formatMillisecondsDuration(final long millis) {
|
||||
if (millis > 1000) {
|
||||
return String.format("%.3fs", (((double) millis) / 1000)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
return millis + "ms"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given number of nanoseconds to a time like 0.000s/ms/us/ns
|
||||
*
|
||||
* @param nanos
|
||||
* the number of nanoseconds
|
||||
*
|
||||
* @return format the given number of nanoseconds to a time like 0.000s/ms/us/ns
|
||||
*/
|
||||
public static String formatNanoDuration(final long nanos) {
|
||||
if (nanos > 1000000000) {
|
||||
return String.format("%.3fs", (((double) nanos) / 1000000000)); //$NON-NLS-1$
|
||||
} else if (nanos > 1000000) {
|
||||
return String.format("%.3fms", (((double) nanos) / 1000000)); //$NON-NLS-1$
|
||||
} else if (nanos > 1000) {
|
||||
return String.format("%.3fus", (((double) nanos) / 1000)); //$NON-NLS-1$
|
||||
} else {
|
||||
return nanos + "ns"; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply returns true if the value is null, or empty
|
||||
*
|
||||
* @param value
|
||||
* the value to check
|
||||
*
|
||||
* @return true if the value is null, or empty
|
||||
*/
|
||||
public static boolean isEmpty(String value) {
|
||||
return value == null || value.isEmpty();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2012
|
||||
*
|
||||
* This file is part of ch.eitchnet.java.utils
|
||||
*
|
||||
* ch.eitchnet.java.utils 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.
|
||||
*
|
||||
* ch.eitchnet.java.utils 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 ch.eitchnet.java.utils. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.utils.helper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A helper class to perform different actions on {@link String}s
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class StringHelper {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(StringHelper.class);
|
||||
|
||||
/**
|
||||
* Hex char table for fast calculating of hex value
|
||||
*/
|
||||
static final byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
|
||||
(byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
|
||||
(byte) 'f' };
|
||||
|
||||
/**
|
||||
* Converts each byte of the given byte array to a HEX value and returns the concatenation of these values
|
||||
*
|
||||
* @param raw
|
||||
* the bytes to convert to String using numbers in hexadecimal
|
||||
*
|
||||
* @return the encoded string
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static String getHexString(byte[] raw) throws RuntimeException {
|
||||
try {
|
||||
byte[] hex = new byte[2 * raw.length];
|
||||
int index = 0;
|
||||
|
||||
for (byte b : raw) {
|
||||
int v = b & 0xFF;
|
||||
hex[index++] = StringHelper.HEX_CHAR_TABLE[v >>> 4];
|
||||
hex[index++] = StringHelper.HEX_CHAR_TABLE[v & 0xF];
|
||||
}
|
||||
|
||||
return new String(hex, "ASCII");
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Something went wrong while converting to HEX: " + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array of a given string by converting each character of the string to a number base 16
|
||||
*
|
||||
* @param encoded
|
||||
* the string to convert to a byt string
|
||||
*
|
||||
* @return the encoded byte stream
|
||||
*/
|
||||
public static byte[] fromHexString(String encoded) {
|
||||
if ((encoded.length() % 2) != 0)
|
||||
throw new IllegalArgumentException("Input string must contain an even number of characters.");
|
||||
|
||||
final byte result[] = new byte[encoded.length() / 2];
|
||||
final char enc[] = encoded.toCharArray();
|
||||
for (int i = 0; i < enc.length; i += 2) {
|
||||
StringBuilder curr = new StringBuilder(2);
|
||||
curr.append(enc[i]).append(enc[i + 1]);
|
||||
result[i / 2] = (byte) Integer.parseInt(curr.toString(), 16);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the MD5 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a
|
||||
* Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashMd5(String string) {
|
||||
return StringHelper.hashMd5(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the MD5 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array to
|
||||
* a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashMd5(byte[] bytes) {
|
||||
return StringHelper.hash("MD5", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to a
|
||||
* Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha1(String string) {
|
||||
return StringHelper.hashSha1(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array
|
||||
* to a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha1(byte[] bytes) {
|
||||
return StringHelper.hash("SHA-1", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA-256 Hash of a string Use {@link StringHelper#getHexString(byte[])} to convert the byte array to
|
||||
* a Hex String which is printable
|
||||
*
|
||||
* @param string
|
||||
* the string to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha256(String string) {
|
||||
return StringHelper.hashSha256(string.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SHA1 Hash of a byte array Use {@link StringHelper#getHexString(byte[])} to convert the byte array
|
||||
* to a Hex String which is printable
|
||||
*
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hashSha256(byte[] bytes) {
|
||||
return StringHelper.hash("SHA-256", bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash of an algorithm
|
||||
*
|
||||
* @param algorithm
|
||||
* the algorithm to use
|
||||
* @param bytes
|
||||
* the bytes to hash
|
||||
*
|
||||
* @return the hash or null, if an exception was thrown
|
||||
*/
|
||||
public static byte[] hash(String algorithm, byte[] bytes) {
|
||||
try {
|
||||
|
||||
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||
byte[] hashArray = digest.digest(bytes);
|
||||
|
||||
return hashArray;
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Algorithm " + algorithm + " does not exist!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the length of a String. Does not shorten it when it is too long, but lengthens it, depending on the
|
||||
* options set: adding the char at the beginning or appending it at the end
|
||||
*
|
||||
* @param value
|
||||
* string to normalize
|
||||
* @param length
|
||||
* length string must have
|
||||
* @param beginning
|
||||
* add at beginning of value
|
||||
* @param c
|
||||
* char to append when appending
|
||||
* @return the new string
|
||||
*/
|
||||
public static String normalizeLength(String value, int length, boolean beginning, char c) {
|
||||
return StringHelper.normalizeLength(value, length, beginning, false, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the length of a String. Shortens it when it is too long, giving out a logger warning, or lengthens it,
|
||||
* depending on the options set: appending the char at the beginning or the end
|
||||
*
|
||||
* @param value
|
||||
* string to normalize
|
||||
* @param length
|
||||
* length string must have
|
||||
* @param beginning
|
||||
* append at beginning of value
|
||||
* @param shorten
|
||||
* allow shortening of value
|
||||
* @param c
|
||||
* char to append when appending
|
||||
* @return the new string
|
||||
*/
|
||||
public static String normalizeLength(String value, int length, boolean beginning, boolean shorten, char c) {
|
||||
|
||||
if (value.length() == length)
|
||||
return value;
|
||||
|
||||
if (value.length() < length) {
|
||||
|
||||
String tmp = value;
|
||||
while (tmp.length() != length) {
|
||||
if (beginning) {
|
||||
tmp = c + tmp;
|
||||
} else {
|
||||
tmp = tmp + c;
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
|
||||
} else if (shorten) {
|
||||
|
||||
StringHelper.logger.warn("Shortening length of value: " + value);
|
||||
StringHelper.logger.warn("Length is: " + value.length() + " max: " + length);
|
||||
|
||||
return value.substring(0, length);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #replacePropertiesIn(Properties, String)}, with {@link System#getProperties()} as input
|
||||
*
|
||||
* @return a new string with all defined system properties replaced or if an error occurred the original value is
|
||||
* returned
|
||||
*/
|
||||
public static String replaceSystemPropertiesIn(String value) {
|
||||
return StringHelper.replacePropertiesIn(System.getProperties(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the given string searching for occurrences of ${...} sequences. Theses sequences are replaced with a
|
||||
* {@link Properties#getProperty(String)} value if such a value exists in the properties map. If the value of the
|
||||
* sequence is not in the properties, then the sequence is not replaced
|
||||
*
|
||||
* @param properties
|
||||
* the {@link Properties} in which to get the value
|
||||
* @param value
|
||||
* the value in which to replace any system properties
|
||||
*
|
||||
* @return a new string with all defined properties replaced or if an error occurred the original value is returned
|
||||
*/
|
||||
public static String replacePropertiesIn(Properties properties, String alue) {
|
||||
|
||||
// get a copy of the value
|
||||
String tmpValue = alue;
|
||||
|
||||
// get first occurrence of $ character
|
||||
int pos = -1;
|
||||
int stop = 0;
|
||||
|
||||
// loop on $ character positions
|
||||
while ((pos = tmpValue.indexOf('$', pos + 1)) != -1) {
|
||||
|
||||
// if pos+1 is not { character then continue
|
||||
if (tmpValue.charAt(pos + 1) != '{') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find end of sequence with } character
|
||||
stop = tmpValue.indexOf('}', pos + 1);
|
||||
|
||||
// if no stop found, then break as another sequence should be able to start
|
||||
if (stop == -1) {
|
||||
StringHelper.logger.error("Sequence starts at offset " + pos + " but does not end!");
|
||||
tmpValue = alue;
|
||||
break;
|
||||
}
|
||||
|
||||
// get sequence enclosed by pos and stop
|
||||
String sequence = tmpValue.substring(pos + 2, stop);
|
||||
|
||||
// make sure sequence doesn't contain $ { } characters
|
||||
if (sequence.contains("$") || sequence.contains("{") || sequence.contains("}")) {
|
||||
StringHelper.logger.error("Enclosed sequence in offsets " + pos + " - " + stop
|
||||
+ " contains one of the illegal chars: $ { }: " + sequence);
|
||||
tmpValue = alue;
|
||||
break;
|
||||
}
|
||||
|
||||
// sequence is good, so see if we have a property for it
|
||||
String property = properties.getProperty(sequence, "");
|
||||
|
||||
// if no property exists, then log and continue
|
||||
if (property.isEmpty()) {
|
||||
// logger.warn("No system property found for sequence " + sequence);
|
||||
continue;
|
||||
}
|
||||
|
||||
// property exists, so replace in value
|
||||
tmpValue = tmpValue.replace("${" + sequence + "}", property);
|
||||
}
|
||||
|
||||
return tmpValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #replaceProperties(Properties, Properties)} with null as the second argument. This allows for
|
||||
* replacing all properties with itself
|
||||
*
|
||||
* @param properties
|
||||
* the properties in which the values must have any ${...} replaced by values of the respective key
|
||||
*/
|
||||
public static void replaceProperties(Properties properties) {
|
||||
StringHelper.replaceProperties(properties, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks every value in the {@link Properties} and then then replaces any ${...} variables with keys in this
|
||||
* {@link Properties} value using {@link StringHelper#replacePropertiesIn(Properties, String)}
|
||||
*
|
||||
* @param properties
|
||||
* the properties in which the values must have any ${...} replaced by values of the respective key
|
||||
* @param altProperties
|
||||
* if properties does not contain the ${...} key, then try these alternative properties
|
||||
*/
|
||||
public static void replaceProperties(Properties properties, Properties altProperties) {
|
||||
|
||||
for (Object keyObj : properties.keySet()) {
|
||||
String key = (String) keyObj;
|
||||
String property = properties.getProperty(key);
|
||||
String newProperty = StringHelper.replacePropertiesIn(properties, property);
|
||||
|
||||
// try first properties
|
||||
if (!property.equals(newProperty)) {
|
||||
// logger.info("Key " + key + " has replaced property " + property + " with new value " + newProperty);
|
||||
properties.put(key, newProperty);
|
||||
} else if (altProperties != null) {
|
||||
|
||||
// try alternative properties
|
||||
newProperty = StringHelper.replacePropertiesIn(altProperties, property);
|
||||
if (!property.equals(newProperty)) {
|
||||
// logger.info("Key " + key + " has replaced property " + property + " from alternative properties with new value " + newProperty);
|
||||
properties.put(key, newProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper method with which it is possible to print the location in the two given strings where they start
|
||||
* to differ. The length of string returned is currently 40 characters, or less if either of the given strings are
|
||||
* shorter. The format of the string is 3 lines. The first line has information about where in the strings the
|
||||
* difference occurs, and the second and third lines contain contexts
|
||||
*
|
||||
* @param s1
|
||||
* the first string
|
||||
* @param s2
|
||||
* the second string
|
||||
*
|
||||
* @return the string from which the strings differ with a length of 40 characters within the original strings
|
||||
*/
|
||||
public static String printUnequalContext(String s1, String s2) {
|
||||
|
||||
byte[] bytes1 = s1.getBytes();
|
||||
byte[] bytes2 = s2.getBytes();
|
||||
int i = 0;
|
||||
for (; i < bytes1.length; i++) {
|
||||
if (i > bytes2.length)
|
||||
break;
|
||||
|
||||
if (bytes1[i] != bytes2[i])
|
||||
break;
|
||||
}
|
||||
|
||||
int maxContext = 40;
|
||||
int start = Math.max(0, (i - maxContext));
|
||||
int end = Math.min(i + maxContext, (Math.min(bytes1.length, bytes2.length)));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Strings are not equal! Start of inequality is at " + i + ". Showing " + maxContext
|
||||
+ " extra characters and start and end:\n");
|
||||
sb.append("context s1: " + s1.substring(start, end) + "\n");
|
||||
sb.append("context s2: " + s2.substring(start, end) + "\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given number of milliseconds to a time like 0.000s/ms
|
||||
*
|
||||
* @param millis
|
||||
* the number of milliseconds
|
||||
*
|
||||
* @return format the given number of milliseconds to a time like 0.000s/ms
|
||||
*/
|
||||
public static String formatMillisecondsDuration(final long millis) {
|
||||
if (millis > 1000) {
|
||||
return String.format("%.3fs", (((double) millis) / 1000)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
return millis + "ms"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given number of nanoseconds to a time like 0.000s/ms/us/ns
|
||||
*
|
||||
* @param nanos
|
||||
* the number of nanoseconds
|
||||
*
|
||||
* @return format the given number of nanoseconds to a time like 0.000s/ms/us/ns
|
||||
*/
|
||||
public static String formatNanoDuration(final long nanos) {
|
||||
if (nanos > 1000000000) {
|
||||
return String.format("%.3fs", (((double) nanos) / 1000000000)); //$NON-NLS-1$
|
||||
} else if (nanos > 1000000) {
|
||||
return String.format("%.3fms", (((double) nanos) / 1000000)); //$NON-NLS-1$
|
||||
} else if (nanos > 1000) {
|
||||
return String.format("%.3fus", (((double) nanos) / 1000)); //$NON-NLS-1$
|
||||
} else {
|
||||
return nanos + "ns"; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply returns true if the value is null, or empty
|
||||
*
|
||||
* @param value
|
||||
* the value to check
|
||||
*
|
||||
* @return true if the value is null, or empty
|
||||
*/
|
||||
public static boolean isEmpty(String value) {
|
||||
return value == null || value.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
*/
|
||||
package ch.eitchnet.utils.helper;
|
||||
|
||||
|
||||
/**
|
||||
* A helper class for {@link System} methods
|
||||
*
|
||||
|
@ -74,7 +73,7 @@ public class SystemHelper {
|
|||
sb.append(SystemHelper.javaVersion);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String getUserDir() {
|
||||
return System.getProperty("user.dir");
|
||||
}
|
||||
|
@ -92,7 +91,8 @@ public class SystemHelper {
|
|||
}
|
||||
|
||||
public static boolean is32bit() {
|
||||
return SystemHelper.osArch.equals("x86") || SystemHelper.osArch.equals("i386") || SystemHelper.osArch.equals("i686");
|
||||
return SystemHelper.osArch.equals("x86") || SystemHelper.osArch.equals("i386")
|
||||
|| SystemHelper.osArch.equals("i686");
|
||||
}
|
||||
|
||||
public static boolean is64bit() {
|
||||
|
@ -112,7 +112,8 @@ public class SystemHelper {
|
|||
}
|
||||
|
||||
public static String getMemorySummary() {
|
||||
return "Memory available " + SystemHelper.getMaxMemory() + " / Used: " + SystemHelper.getUsedMemory() + " / Free:" + SystemHelper.getFreeMemory();
|
||||
return "Memory available " + SystemHelper.getMaxMemory() + " / Used: " + SystemHelper.getUsedMemory()
|
||||
+ " / Free:" + SystemHelper.getFreeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
*/
|
||||
package ch.eitchnet.utils.objectfilter;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class is a cache for objects whose operations (additions, modifications, removals) are first collected and then
|
||||
|
@ -40,7 +41,7 @@ import org.apache.log4j.Logger;
|
|||
*/
|
||||
public class ObjectCache<T extends ITransactionObject> {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(ObjectCache.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(ObjectCache.class);
|
||||
|
||||
/**
|
||||
* id The unique ID of this object in this session
|
||||
|
@ -72,8 +73,8 @@ public class ObjectCache<T extends ITransactionObject> {
|
|||
this.operation = operation;
|
||||
|
||||
if (ObjectCache.logger.isDebugEnabled()) {
|
||||
ObjectCache.logger.debug("Instanciated Cache: ID" + this.id + " / " + key + " OP: " + this.operation + " / "
|
||||
+ object.toString());
|
||||
ObjectCache.logger.debug("Instanciated Cache: ID" + this.id + " / " + key + " OP: " + this.operation
|
||||
+ " / " + object.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,8 @@ public class ObjectCache<T extends ITransactionObject> {
|
|||
*/
|
||||
public void setOperation(Operation newOperation) {
|
||||
if (ObjectCache.logger.isDebugEnabled()) {
|
||||
ObjectCache.logger.debug("Updating Operation of ID " + this.id + " from " + this.operation + " to " + newOperation);
|
||||
ObjectCache.logger.debug("Updating Operation of ID " + this.id + " from " + this.operation + " to "
|
||||
+ newOperation);
|
||||
}
|
||||
this.operation = newOperation;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class implements a filter where modifications to an object are collected, and only the most recent action and
|
||||
|
@ -79,10 +80,10 @@ import org.apache.log4j.Logger;
|
|||
* @param <T>
|
||||
*/
|
||||
public class ObjectFilter<T extends ITransactionObject> {
|
||||
|
||||
|
||||
// XXX think about removing the generic T, as there is no sense in it
|
||||
|
||||
private final static Logger logger = Logger.getLogger(ObjectFilter.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(ObjectFilter.class);
|
||||
|
||||
private HashMap<Long, ObjectCache<T>> cache = new HashMap<Long, ObjectCache<T>>();
|
||||
private HashSet<String> keySet = new HashSet<String>();
|
||||
|
|
Loading…
Reference in New Issue