package com.compomics.util.io;
import com.compomics.util.enumeration.CompomicsTools;
import org.apache.log4j.*;
import java.io.*;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
/**
* This class holds all user properties for ms_lims.
*
* Created by IntelliJ IDEA.
* User: kenny
* Date: Feb 22, 2010
* Time: 1:27:41 PM
*/
public class PropertiesManager {
// Class specific log4j logger for PropertiesManager instances.
Logger logger = Logger.getLogger(PropertiesManager.class);
/**
* The singleton instance of the ms properties.
*/
private static PropertiesManager singleton = null;
/**
* This folder is located in the user home directory and captures the user properties of ms_lims.
*/
private File iHomeFolder;
/**
* This private constructor manages a single instance to access the properties.
*/
private PropertiesManager() {
// Get the user home directory.
File lHome = FileSystemAccessor.getHomeFolder();
iHomeFolder = new File(lHome, ".compomics");
if (!iHomeFolder.exists()) {
iHomeFolder.mkdir();
}
}
/**
* Get the application folder that contains the appropriate properties.
*
* @param aTool The tool for which the properties are requested.
* @return File (Directory) that contains the properties.
*/
public File getApplicationFolder(CompomicsTools aTool) {
// Make the folder for the required application, if non-existing.
File iApplicationFolder = new File(iHomeFolder, aTool.getName());
if (!iApplicationFolder.exists()) {
iApplicationFolder.mkdir();
}
return iApplicationFolder;
}
/**
* Get the singleton instance to access properties of Computational Omics tools.
*
* @return The PropertiesManger to access user properties in their home directory.
*/
public static PropertiesManager getInstance() {
if (singleton == null) {
singleton = new PropertiesManager();
}
return singleton;
}
/**
* DO NOT RUN. For testing purpose.
*
* @param args the arguments
*/
public static void main(String[] args) {
new PropertiesManager();
}
/**
* Get a Properties instance for the parameter properties filename.
*
* @param aTool the name of the tool
* @param aPropertiesFileName - e.g.: "mascotdaemon.properties"
* @return Properties instance of the given properties file. Null if the filename was not found.
*/
public Properties getProperties(CompomicsTools aTool, String aPropertiesFileName) {
Properties lProperties = new Properties();
InputStream is;
try {
// Always get the properties from the classpath. the requested properties are not found,
// we will try to read the properties from the the classpath.
is = getResource(aPropertiesFileName);
Properties lClassPathProperties = new Properties();
lClassPathProperties.load(is);
is.close();
Object lVersion = lClassPathProperties.get("version");
String lClassPathVersion = null;
if (lVersion != null) {
lClassPathVersion = lVersion.toString();
}
// Make a filename filter for '.properties' files.
FilenameFilter lPropertiesFileNameFilter = new FilenameFilter() {
public boolean accept(final File dir, final String name) {
return name.endsWith(".properties");
}
};
// Get the application folder.
File lApplicationFolder = getApplicationFolder(aTool);
// Get all the properties files in the mslims folder.
File[] lPropertiesFiles = lApplicationFolder.listFiles(lPropertiesFileNameFilter);
// Iterate and try to match the requested file.
File lRequestedPropertiesFile = null;
boolean lPropertiesFound = false;
for (int i = 0; i < lPropertiesFiles.length; i++) {
File lLastFile = lPropertiesFiles[i];
if (lLastFile.getName().equals(aPropertiesFileName)) {
lRequestedPropertiesFile = lLastFile;
lPropertiesFound = true;
break;
}
}
// Verify that the properties have been found.
if (lPropertiesFound == true) {
// Create the properties via a file inputstream.
is = new FileInputStream(lRequestedPropertiesFile);
lProperties.load(is);
is.close();
} else {
// And, write the content of this properties file to the user home directory for the next request.
try {
File lOutput;
lOutput = getFile(aTool, aPropertiesFileName);
if (!lOutput.exists()) {
lOutput.createNewFile();
}
FileOutputStream fos = new FileOutputStream(lOutput);
BufferedOutputStream bos = new BufferedOutputStream(fos);
lClassPathProperties.store(bos, aPropertiesFileName + " properties file");
fos.flush();
fos.close();
bos.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
// During updates, for each property that was is in the classpathversion,
// but not in the local properties - store the entry to the local file.
Set lClassPathPropertyKeySet = lClassPathProperties.keySet();
boolean lRequireDiskUpdate = false;
for (Iterator lIterator = lClassPathPropertyKeySet.iterator(); lIterator.hasNext();) {
Object lClasspathKey = lIterator.next();
if (lProperties.get(lClasspathKey) == null) {
lProperties.put(lClasspathKey, lClassPathProperties.get(lClasspathKey));
lRequireDiskUpdate = true;
}
}
if (lClassPathVersion != null) {
// Always keep the version up to date with the classpathversion.
lProperties.put("version", lClassPathVersion);
lRequireDiskUpdate = true;
}
// If required, then update the properties file on disk!
if(lRequireDiskUpdate){
storeProperties(aPropertiesFileName, aTool, lProperties);
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
return lProperties;
}
/**
* Private method that attempts to return an inputstream resource for a given filename.
*
* @param aResourceFilename
* @return InputStream (null if not found)
*/
private InputStream getResource(final String aResourceFilename) {
InputStream is;
is = ClassLoader.getSystemResourceAsStream(aResourceFilename);
if (is == null) {
is = this.getClass().getClassLoader().getResourceAsStream(aResourceFilename);
}
return is;
}
/**
* Update the content of a user properties instance to the ms_lims properties directory.
*
* @param aTool The name of the tool.
* @param aNewProperties The Properties instance.
* @param aPropertiesFileName The properties filename (e.g., dbconnection.properties)
*/
public void updateProperties(final CompomicsTools aTool, final String aPropertiesFileName, final Properties aNewProperties) {
// First get the existing properties.
Properties lProperties = getProperties(aTool, aPropertiesFileName);
// Then iterate over the new properties.
Iterator lUpdatedProperties = aNewProperties.keySet().iterator();
while (lUpdatedProperties.hasNext()) {
// Replace existing entries, include old entries.
Object aKey = lUpdatedProperties.next();
lProperties.put(aKey, aNewProperties.get(aKey));
}
storeProperties(aPropertiesFileName, aTool, lProperties);
}
/**
* Returns the File handler for the given compomics tool and filename.
* @param aTool
* @param aPropertiesFileName
* @return the File handler for the given compomics tool and filename
*/
private File getFile(CompomicsTools aTool, String aPropertiesFileName) {
return new File(getApplicationFolder(aTool), aPropertiesFileName);
}
/**
* Store the given Properties instance to the given direction.
* @param aPropertiesFileName
* @param aTool
* @param lProperties
*/
private void storeProperties(String aPropertiesFileName, CompomicsTools aTool, Properties lProperties) {
File lOutput = getFile(aTool, aPropertiesFileName);
try {
if (!lOutput.exists()) {
lOutput.createNewFile();
}
FileOutputStream fos = new FileOutputStream(lOutput);
BufferedOutputStream bos = new BufferedOutputStream(fos);
lProperties.store(bos, aPropertiesFileName + " properties file");
fos.flush();
fos.close();
bos.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
/**
* This method will delete the log4j log file in the folder of the package and will create a log file in the
* CompomicsTools specific .compomics folder
*
* @param aLogger The logger
* @param aCompomicsTools The tool
*/
public void updateLog4jConfiguration(final org.apache.log4j.Logger aLogger, CompomicsTools aCompomicsTools) {
Properties props = new Properties();
try {
InputStream configStream = getResource("log4j.properties");
props.load(configStream);
configStream.close();
} catch (IOException e) {
System.out.println("Error: Cannot load configuration file ");
}
String lFileKey = "log4j.appender.file.File";
String lOldLogFileName = props.getProperty(lFileKey);
String lNewLogFileName = getApplicationFolder(aCompomicsTools).getAbsolutePath() + File.separator + aCompomicsTools.getName() + "-log4j.log";
RollingFileAppender lRollingFileAppender = (RollingFileAppender) aLogger.getParent().getAppender("file");
lRollingFileAppender.setFile(lNewLogFileName);
lRollingFileAppender.activateOptions();
lRollingFileAppender.setThreshold(Priority.WARN);
File lOldLogFile = new File(lOldLogFileName);
if (lOldLogFile.exists()) {
lOldLogFile.delete();
}
// Make all remaining System.err go into the logger as well.
PrintStream stderrStream = System.err;
PrintStream newStderrStream = new PrintStream(stderrStream) {
@Override
public void println(Object x) {
if (x instanceof Throwable) {
Throwable t = (Throwable) x;
aLogger.error(t.getMessage());
StackTraceElement[] lElements = t.getStackTrace();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lElements.length; i++) {
StackTraceElement lElement = lElements[i];
sb.append(lElement.toString() + "\n");
}
aLogger.error(sb.toString());
}
super.println(x);
}
};
System.setErr(newStderrStream);
}
}