how to read property files from external storage - java

I have a jar file that I run from the console. In the program itself, I have to read data from the property file, which should be in the same folder as my jar file. How can i do this ?
my code which does not work correctly:
public class ReadProperties {
String propPath = System.getProperty("app.properties");
private String message;
private String userName;
ReadProperties() {
readProperties();
}
private void readProperties() {
final FileInputStream in;
try {
in = new FileInputStream(propPath);
Properties myProps = new Properties();
myProps.load(in);
message = myProps.getProperty(Constants.MESSAGE);
userName = myProps.getProperty(Constants.USERNAME);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getMessage() {
return message;
}
public String getUserName() {
return userName;
}
}

Note that the way you have coded above requires a system property to mark the file to load, passed as:
java -Dapp.properties=somefile.properties
If you intended a file called "app.properties" this requires a change to the declaration of propPath without System.getProperty
Your file handling should use try with resources to clean up afterwards with automatic close, and not hide any exception:
try (FileInputStream in = new FileInputStream(propPath)) {
// load here
}
You could provide default property values after exception, or handle by add throws IOException to the method, or append code to adapt as a runtime exception so that is is reported:
catch (Exception e) {
throw new UncheckedIOException(e);
}

Related

How to check if file or console is associated with Standard Output?

I am using following code to redirect standard out and standard error out to Log file depending on the boolean value of a variable.
if (logToFile==true){
java.io.File outputFile = new java.io.File(logFilePath);
System.setOut(new java.io.PrintStream(new java.io.FileOutputStream(outputFile, true), true));
System.setErr(new java.io.PrintStream(new java.io.FileOutputStream(outputFile, true), true));
}
Moving further down my code, I want to find out whether my standard out and error out are associated with file - only then I would want to log few things. And over there, I don't have access to logToFile variable.
Is there any way to find out whether the standard out and error out are associated with file or the default console currently? And if they are associated to file then can we get the file path?
Moving further down my code, I want to find out whether my standard out and error out are associated with file - only then I would want to log few things. And over there, I don't have access to logToFile variable.
What about storing the value of logToFile in a static variable, like for example:
if (logToFile) {
StandardStreams.redirectToFile(new File(logFilePath));
}
public class StandardStreams {
private static boolean redirectedToFile;
public static void redirectToFile(File file) throws FileNotFoundException {
PrintStream stream = new PrintStream(new FileOutputStream(file, true), true);
System.setOut(stream);
System.setErr(stream);
redirectedToFile = true;
}
public static boolean areRedirectedToFile() {
return redirectedToFile;
}
}
And then:
if (StandardStreams.areRedirectedToFile()) {
// Log few things
}
Is there any way to find out whether the standard out and error out are associated with file or the default console currently? And if they are associated to file then can we get the file path?
Create your own PrintStream:
class ConsoleLinkedFile extends PrintStream {
private final File file;
ConsoleLinkedFile(File file) throws FileNotFoundException {
super(new FileOutputStream(file, true), true);
this.file = file;
}
File getFile() {
return file;
}
}
if (logToFile) {
PrintStream stream = new ConsoleLinkedFile(new File(logFilePath));
System.setOut(stream);
System.setErr(stream);
}
To find out and retrieve the file path:
public static Optional<File> getFileIfRedirected(PrintStream stream) {
if (stream instanceof ConsoleLinkedFile) {
ConsoleLinkedFile linkedFile = (ConsoleLinkedFile) stream;
return Optional.of(linkedFile.getFile());
}
return Optional.empty();
}
if (getFileIfRedirected(System.out).isPresent()) {
// Log few things
}
Note that the same PrintStream can be shared between standard input and standard error.
If you cannot create your own PrintStream, then you need to use reflection:
private static final VarHandle OUT, PATH;
static {
final Class<?> OUT_class = FilterOutputStream.class;
final Class<?> PATH_class = FileOutputStream.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
OUT = MethodHandles.privateLookupIn(OUT_class, lookup)
.findVarHandle(OUT_class, "out", OutputStream.class);
PATH = MethodHandles.privateLookupIn(PATH_class, lookup)
.findVarHandle(PATH_class, "path", String.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private static Optional<String> getFileIfRedirected(PrintStream stream) {
Object out = OUT.get(stream);
if (out instanceof BufferedOutputStream) {
out = OUT.get(out);
}
return Optional.ofNullable((String) PATH.get(out));
}
VarHandle is faster than java.lang.reflect. In Java 8, you can use the latter:
private static final Field OUT, PATH;
static {
try {
OUT = FilterOutputStream.class.getDeclaredField("out");
OUT.setAccessible(true);
PATH = FileOutputStream.class.getDeclaredField("path");
PATH.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}

Unable to read Windows file even when it has "Read" permission set through java

I am trying to set permissions for a file to the Administrators group from java in windows.
Below is my code:
public static void main(String[] args) throws IOException {
final Path path = Paths.get("C:/Dev/dummy/test");
FileAttribute<?> permissions = new FileAttribute<List<AclEntry>>() {
public String name() {
return "acl:acl";
}
public List<AclEntry> value() {
try {
return get600ACL(path.getFileSystem());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
Files.createFile(path, permissions);
}
private static List<AclEntry> get600ACL(FileSystem fileSystem) throws IOException {
List<AclEntry> aclEntryList = new ArrayList<AclEntry>();
AclEntry.Builder acl3 = AclEntry.newBuilder();
acl3.setPermissions(EnumSet.of(
AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_DATA, AclEntryPermission.WRITE_ATTRIBUTES,
AclEntryPermission.SYNCHRONIZE, AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_NAMED_ATTRS,
AclEntryPermission.DELETE, AclEntryPermission.WRITE_NAMED_ATTRS, AclEntryPermission.APPEND_DATA, AclEntryPermission.EXECUTE, AclEntryPermission.DELETE,
AclEntryPermission.DELETE_CHILD, AclEntryPermission.ADD_FILE, AclEntryPermission.ADD_SUBDIRECTORY, AclEntryPermission.LIST_DIRECTORY, AclEntryPermission.WRITE_ACL,
AclEntryPermission.WRITE_ATTRIBUTES, AclEntryPermission.WRITE_DATA, AclEntryPermission.WRITE_OWNER
));
GroupPrincipal grp2 = fileSystem.getUserPrincipalLookupService().lookupPrincipalByGroupName("Administrators");
acl3.setPrincipal(grp2);
acl3.setType(AclEntryType.ALLOW);
AclEntry entry3 = acl3.build();
aclEntryList.add(entry3);
return aclEntryList;
}
After creating file, the permissions are proper as seen in this image
But when I create a new user, give him Administrator permissions and try to open the file, it says user has no read permissions.
Can someone tell me where I am going wrong here?

Store execution result in java in properties file

I wrote a code in java to run some scripts which can return different result depending on the environment setup. I would like to store the result of every execution. I try with properties file but every time it executes, it overwrites the previous result in config.properties. I did a research but not find any most likely example. This is my code to return properties file. The value which will be different are TCpassed and TCfailed on every execution.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class ExecutionProperties {
public void setConfigProperties(int tcPassed, int tcFailed){
Properties prop = new Properties();
OutputStream output = null;
try {
output = new FileOutputStream("config.properties");
// set the properties value
prop.setProperty("TCpassed", ""+ tcPassed);
prop.setProperty("TCfailed", ""+ tcFailed);
// save properties to project root folder
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Is it possible to get the execution time and store it in config.properties in order to differentiate with the previous result?
Thanks before
You can use append mode using constructor FileOutputStream("config.properties", true)
Sample properties file after couple of execution
#Mon May 04 13:03:29 IST 2015
TCpassed=1
TCfailed=1
#Mon May 04 13:04:03 IST 2015
TCpassed=1
TCfailed=1
Property file are usually key value pairs, e.g.
TCpassed=9
TCfailed=1
So if you want to store the result of every execution, you need a different key for every execution.
And if you want to append to the property file, you can:
Load the property file as Properties object;
Add new entry to the Properties object;
Write the Properties Object back to the file;
Here is an example:
public static void appendTestResult(File propertyFile, int tcPassed, int tcFailed) {
try {
Properties properties = loadProperties(propertyFile);
String testId = getTestID();
properties.setProperty("TCpassed_" + testId, String.valueOf(tcPassed));
properties.setProperty("TCfailed_" + testId, String.valueOf(tcFailed));
saveProperties(propertyFile, properties);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void saveProperties(File propertyFile, Properties properties) throws IOException {
OutputStream outputStream = null;
try {
outputStream = FileUtils.openOutputStream(propertyFile);
properties.store(outputStream, "new test");
} finally {
IOUtils.closeQuietly(outputStream);
}
}
public static Properties loadProperties(File propertyFile) throws IOException {
InputStream inputStream = null;
try {
inputStream = FileUtils.openInputStream(propertyFile);
Properties properties = new Properties();
properties.load(inputStream);
return properties;
} finally {
IOUtils.closeQuietly(inputStream);
}
}
public static String getTestID() {
return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
}

Eclipse won't read a config file

I have an Eclipse web project. I have a file called deploy.properties in the root directory which doesn't seem to get read. I have a feeling that I may need to add the file to the "build path" (like a jar), but this is just a guess, when I try to do this there is no option for adding files to the build path so that makes me think I am wrong about that.
Line 89 is this one props.load(stream);
My stack trace looks like this:
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Properties.java:365)
at java.util.Properties.load(Properties.java:293)
at sempedia.dao.Dao.getConfigFile(Dao.java:89)
at sempedia.dao.Dao.<clinit>(Dao.java:17) 89
And the class looks like this:
public class Dao {
private static final String configFileLocation = "/deploy.properties";
private static final Properties configFile = getConfigFile(configFileLocation);
private static final String host = configFile.getProperty("mysql.host");
private static final String port = configFile.getProperty("mysql.port");
private static final String db = configFile.getProperty("mysql.db");
private static final String user = configFile.getProperty("mysql.user");
private static final String pwd = configFile.getProperty("mysql.pwd");
public static String getHost() { return host; }
public static String getPort() { return port; }
public static String getDb() { return db; }
public static String getUser() { return user; }
public static String getPwd() { return pwd; }
public static Connection getCon() {
Connection con = null;
try {
String url = "jdbc:mysql://" + host + ":" + port + "/" + db;
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection(url, user, pwd);
} catch (SQLException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return con;
}
private static Properties getConfigFile(String fileName) {
Properties props = new Properties();
try {
InputStream stream = Dao.class.getResourceAsStream(fileName);
props.load(stream);
} catch (IOException e) {
System.err.println("Error opening configuration file");
System.exit(1);
}
return props;
}
}
Keep in mind that when you read files in your eclipse project, the default location is in your source directory (if this is a web application, that translates to your classes directory later). So my advice is to try moving the file from the project root directory to your "src" directory and retrying.
Method Dao.class.getResourceAsStream(fileName) returns null as the inputstream if the target file doesn't exist in the classpath - that's why the NullPointerException.
You should either catch it (now you only catch IOException) or test input stream before calling props.load(stream) for null;
Now what root directory do you mean? System root, app source root, app working directory? System root would be a rather bad place to put your config files.
Address it with "deploy.properties" (without the slash at the beginning) and place it in the root of your classpath ("classes", "bin" - or whatever you call it).
If you place it in the default package level of your source directory - either in the source, or a directory that you have added as a source directory, it will be copied to the classpath during compile like this:
/app
/src
/config
deploy.properties
and now add config directory to the project as a source directory.

Does reading properties files multiple times consume lots memory?

I have a class which reads a properties file. Please see below.
The method readProperties() is called many times when the application is running, does that mean there is a memory issue here?
public class PropertyReader {
private static Properties configKeyValuePairs = null;
private static String configPropertiesFileName = "Config.properties";
static void readProperties() throws FileNotFoundException, IOException {
configKeyValuePairs = new Properties();
InputStream input = ConfigReader.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
input.close();
}
static String getUserName(){
//return user name which is from the properties file.
}
}
Assuming your properties file never changes, you can do the following:
public class MyApplicationConfiguration {
private static Properties configKeyValuePairs = new Properties();
private static String configPropertiesFileName = "Config.properties";
static {
InputStream input = null;
try {
input = MyApplicationConfiguration.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
} catch (IOException e) {
// Deal with not being able to load config, could be a fatal error!
} finally {
if (input != null) {
input.close();
}
}
}
public static String getUsername() {
// ...
}
// Implement getters for other configuration key-value pairs
// DO NOT let configKeyValuePairs be returned to anyone
}
Load the properties object once, and store it a class member.
I find it hard to believe that you will have memory issues because of it.
If you find out that you do, then you can always comeback and rethink it, but don't prematurely optimize a problem that probably doesn't exist.
Yes, there could be a very big memory problem, depending on whether or not there are calling classes that hold a reference to the newly created properties object.
Try something like this:
public class PropertyReader {
private static Properties configKeyValuePairs = null;
private static final String configPropertiesFileName = "Config.properties";
public static void readProperties() throws FileNotFoundException, IOException {
if(null == configKeyValuePairs){
InputStream input;
synchronized(PropertyReader.class){
try{
configKeyValuePairs = new Properties();
input = PropertyReader.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
}finally{
//this can still throw ioexception!
if(null != input){
input.close();
}
}
}
}
}

Categories