I have an Email class which is abstract. It has several children: AuthenticationEmail, MarketingEmail, etc. I want to initialize value of a field (which is final static) with a string stored in an external file.
At first I though I could use Spring's #Value but it turned out that the class needs to be a component. Then I tried the following code (static initialization and etc.):
public abstract class UserAccountAuthenticationEmail extends Email implements Serializable {
#Value("${email.address.from.authentication}")
private final static String SENDER_EMAIL_ADDRESS;
static {
Properties prop = new Properties();
String propFileName = "config.properties";
InputStream inputStream;
if (inputStream != null) {
prop.load(inputStream);
inputStream = getClass().getClassLoader().getResourceAsStream(propFileName);
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
}
#Override
public String getSender() {
return SENDER_EMAIL_ADDRESS;
}
}
It doesn't work either, as getClass is a non-static method and cannot be instantiated inside the static block.
How can I initialize the value of this variable from a file? and preferably only one time. Is there any standard method to do that? something like #Value, instead of manually reading from IO?
Hope it can help you. A static final variable can't be changed after the first initialization.
public class UserAccountAuthenticationEmail implements Serializable {
private final static String SENDER_EMAIL_ADDRESS =getVal();
public static String getVal() {
try {
Properties prop = new Properties();
String propFileName = "C:\\SMS\\config.properties";
InputStream inputStream;
inputStream = new FileInputStream(propFileName);
if (inputStream != null) {
prop.load(inputStream);
return prop.getProperty("email");
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
}
catch (Exception e){
e.printStackTrace();
}
return "";
}
public static void main(String[] args) {
System.out.println(SENDER_EMAIL_ADDRESS);
}
}
Fixed it this way:
private final static String DEFAULT_SENDER_EMAIL_ADDRESS;
static {
String value = "";
try {
Properties prop = new Properties();
String propFileName = "application.properties";
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(propFileName);
if (inputStream != null) {
prop.load(inputStream);
value = prop.getProperty("email.authentication.sender");
}
}
catch (Exception e){
e.printStackTrace();
}
DEFAULT_SENDER_EMAIL_ADDRESS = value;
}
public String getSender() {
return DEFAULT_SENDER_EMAIL_ADDRESS;
}
Related
I am going to run Socket Server via Singleton Pattern because I have multiple threads, and every time I call it, I want to use the same socket server. This is SocketSingleton.java class :
public class SocketSingleton {
private static ServerSocket serverSocket = null;
private SocketSingleton() {}
public static synchronized ServerSocket getServerSocket() throws IOException {
PropertiesKey prop = new PropertiesKey();
if (serverSocket == null) {
serverSocket = new ServerSocket(prop.getSocketPort());
}
return serverSocket;
}
}
But I've noticed that I should get my few values from configuration.properties like SOCKET_PORT=2203
I can get the values from configuration with the code bellow
public class PropertiesAlgorithmImpl implements PropertiesAlgorithm {
private static Properties defaultProps = new Properties();
static {
try {
String propertiesDirectory = "src/main/resources/configuration.properties";
FileInputStream in = new FileInputStream(propertiesDirectory);
if (in == null) {
System.out.println("Sorry, unable to find " + propertiesDirectory);
}
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public String getValuesFromProperties(String key) {
if (defaultProps.getProperty(key) != null) {
return defaultProps.getProperty(key);
}
return "Sorry, unable to find " + key ;
}
}
This is an enum of Socket Port.
public enum CONFIG { SOCKET_PORT}
public class PropertiesKey {
private PropertiesAlgorithm propertiesAlgorithm;
public int getSocketPort(){
propertiesAlgorithm = new PropertiesAlgorithmImpl();
return Integer.parseInt(propertiesAlgorithm.getValuesFromProperties(CONFIG.SOCKET_PORT.name()));
}
In the SocketSingleton class, I am calling socket port like this:
serverSocket = new ServerSocket(prop.getSocketPort());
What is the possible reason that I can't get the socket port parameters from configuration.properties?
I fixed the class bellow with input stream and it worked:
public class PropertiesAlgorithmImpl implements PropertiesAlgorithm {
private static final Logger logger = LoggerFactory.getLogger(PropertiesAlgorithmImpl.class);
private static Properties defaultProps = new Properties();
static {
String propertiesDirectory = "config.properties";
try (InputStream input = PropertiesAlgorithmImpl.class.getClassLoader().getResourceAsStream(propertiesDirectory)) {
if (input == null) {
logger.info("Sorry, unable to find " + propertiesDirectory);
}
defaultProps.load(input);
input.close();
} catch (Exception e) { logger.info(String.valueOf(e.getStackTrace())); }
}
public String getValuesFromProperties(String key) {
if (defaultProps.getProperty(key) != null) {
return defaultProps.getProperty(key);
}
logger.info("Sorry, unable to find " + key);
return "Sorry, unable to find " + key ;
}
can log4j2 use multiple config files. I wanna run my project and load one default config file - logger.xml and after that to check if there is a second configuration from another file logger_1.xml and to add it and not to override the first one.
Here is some dummy code. In short I wanna fill up the arrayList with file paths and then to load all of them.
public class LoggerConfiguratorManager
{
public static final String LOG4J_PATH = "etc/confs/logger.xml";
private static LoggerContext context = null;
private static final ConfigurationFactory factory = XmlConfigurationFactory.getInstance();
private static ConfigurationSource configurationSource = null;
private static Configuration configuration = null;
private static final ArrayList<String> registred_logger = new ArrayList<>();
private static void loadLoggerConfig(String logger_path)
{
InputStream is = null;
try
{
if(logger_path.endsWith(".xml"))
is = new FileInputStream(logger_path);
else
{
final ZipFile archive = new ZipFile(logger_path);
final ZipEntry logger_entry = archive.getEntry(LOG4J_PATH);
if(logger_entry == null) throw new IOException("Cannot find 'logger.xml' in " + logger_path);
is = archive.getInputStream(logger_entry);
}
configurationSource = new ConfigurationSource(is);
configuration = factory.getConfiguration(configurationSource);
}
catch(IOException ex)
{
System.err.println("=============================================================================");
System.err.println("=============================== LOGGER CONFIG ===============================");
System.err.println("=============================================================================");
System.err.println("=== [ERROR] " + ex);
}
finally
{
if (configurationSource != null)
{
context = Configurator.initialize(null, configurationSource);
context.start(configuration);
try { is.close(); } catch(IOException ex) { }
}
}
}
public static void load()
{
registred_logger.add(Globals.getClassLocation(LoggerConfiguratorManager.class));
for(final String conf : registred_logger)
loadLoggerConfig(conf);
}
public static void regLoggerConf(String conf_path) { registred_logger.add(conf_path); }
I would suggest doing instead:
public class LoggerConfiguratorManager {
private static final String LOG4J_PATH = "etc/confs/log4j2.xml";
private static final StringBuffer paths = new StringBuffer(LOG4J_PATH);
public static void registerConfiguration(String confPath) {
paths.append(",").append(confPath);
}
public static void initLog4j() {
Configurator.initializer("My Config", null, paths.toString(), null);
}
}
For a full working example please see https://github.com/rgoers/CompositeConfigurationExample.
I want to access the variable in package 1 from package 2.
Class file TestDriver.java from package 1
public class TestDriver {
private static TestDriver instance = new TestDriver();
private static int check;
private static int envt_num;
public static String envt,port,cpy_key;
public Connection con;
private ManageDBConnection mdbc;
private static String ENCRYPTION_KEY = "0123456789abcdef";
public void TestDriver(){
check = 20;
Properties prop = new Properties();
String propFileName = "properties/environment.properties";
try{
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(propFileName);
System.out.println(inputStream);
if (inputStream != null) {
prop.load(inputStream);
envt = prop.getProperty("envt");
port = prop.getProperty("port");
cpy_key = prop.getProperty("cpy_key");
System.out.println("http://"+envt+"/netprofile/");
//Original Login Link
/* Constants.driver.get("http://"+prop.getProperty("user").replaceAll("\\s","")+":"+NP_Decrypt.getPassword().replaceAll("\\s","")+"#"+envt+"/netprofile/");
inputStream.close();*/
//Added for Local Testing
String user = prop.getProperty("user");
String password = prop.getProperty("password");
Constants.driver.get("http://" + user + ":" + password + "#" + envt + "/test/");
// mdbc = new ManageDBConnection();
//con = mdbc.CreateConnection();
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
Class file Constants.java from package 2
public class Constants
{
static Properties prop = new Properties();
// propFileName = "properties/environment.properties";
//TestDriver testdriver = new TestDriver();
static String envt = TestDriver.envt;
static String cpy_key = TestDriver.cpy_key;
//public static final
public static final WebDriver driver = new FirefoxDriver();
public static final String InventorySummaryURL ="http://"+envt+"/test/npHome.do?cpyKey="+cpy_key+"&custId=&grpId=0";
public static final String HomeSummary ="http://"+envt+"/test/npIndex.do?cpyKey="+cpy_key+"&custId=&grpId=0";
public static final String UploadStatus ="http://"+envt+"/test/downloadModuleStatus.do?cpyKey="+cpy_key+"&custId=&grpId=0" ;
public static final String ProfileStatus ="http://"+envt+"/test/myProfileStatus.do?cpyKey="+cpy_key+"&custId=&grpId=0";
}
In Constants.java the value returned for envt and cpy_key is zero. I want the value from Package 1.
Main issue is that you're confusing static fields with instance fields, if the following variables:
private static final int check;
private static final int envt_num;
private static final String user, password;
public static String envt,port,cpy_key;
are the same across the JVM, don't modify them in a instance constructor, instead you can can create an static block to update the values of them and also, you can mark them as final if the are not supposed to be changed.
public final static String envt,port,cpy_key;
static {
Properties prop = new Properties();
String propFileName = "properties/environment.properties";
try{
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(propFileName);
System.out.println(inputStream);
if (inputStream != null) {
prop.load(inputStream);
envt = prop.getProperty("envt");
port = prop.getProperty("port");
cpy_key = prop.getProperty("cpy_key");
System.out.println("http://"+envt+"/netprofile/");
//Original Login Link
/* Constants.driver.get("http://"+prop.getProperty("user").replaceAll("\\s","")+":"+NP_Decrypt.getPassword().replaceAll("\\s","")+"#"+envt+"/netprofile/");
inputStream.close();*/
//Added for Local Testing
user = prop.getProperty("user");
password = prop.getProperty("password");
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
}
public void TestDriver(){
Constants.driver.get("http://" + user + ":" + password + "#" + envt + "/test/");
// mdbc = new ManageDBConnection();
//con = mdbc.CreateConnection();
}
The key is to separate what is static field vs what is an instance fields, the issue you had was the the static field wasn't being initialized when the class was loaded, but when the instance was created.
Jose Luis
The variables envt and cpy_key are declaired static but shouldn't be. By declaring a variable to be static, you are telling the compiler/outside developers that this class doesn't have to be instantiated before you use that variable.
In your code, the envt and cpy_key variables are only initialized in the constructor of the TestDriver class. When you reference them from another class without instantiating a TestDriver you are getting a null value which is sometimes mapped to 0.
What you can do is:
Remove the static identifier from the envt and cpy_key variables, since you need to instantiate the TestDriver class before they able to be used.
Move the initialization code out of the constructor and use a static initialization block
Example:
public class TestDriver {
private static TestDriver instance = new TestDriver();
private static int check;
private static int envt_num;
public static String envt,port,cpy_key;
public Connection con;
private ManageDBConnection mdbc;
private static String ENCRYPTION_KEY = "0123456789abcdef";
static {
check = 20;
Properties prop = new Properties();
String propFileName = "properties/environment.properties";
try{
InputStream inputStream = TestDriver.getClass().getClassLoader().getResourceAsStream(propFileName);
System.out.println(inputStream);
if (inputStream != null) {
prop.load(inputStream);
envt = prop.getProperty("envt");
port = prop.getProperty("port");
cpy_key = prop.getProperty("cpy_key");
System.out.println("http://"+envt+"/netprofile/");
//Original Login Link
/* Constants.driver.get("http://"+prop.getProperty("user").replaceAll("\\s","")+":"+NP_Decrypt.getPassword().replaceAll("\\s","")+"#"+envt+"/netprofile/");
inputStream.close();*/
//Added for Local Testing
String user = prop.getProperty("user");
String password = prop.getProperty("password");
Constants.driver.get("http://" + user + ":" + password + "#" + envt + "/test/");
// mdbc = new ManageDBConnection();
//con = mdbc.CreateConnection();
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
}catch(Exception e){
e.printStackTrace();
}
}
So that fixes your initialization problem, but that doesn't solve your bigger class design problem. You should figure out a better (more Object Oriented) way of handling data. You have two classes relying on each other's static variables. This is a baaaad plan. I would advise you to encapsulate the variables that need initializing and keep them in the TestDriver class. Constants classes really should only be for things that you know ahead of time (hash key labels, numerical constants, etc).
I've a swing application that has to connect to database for some resources, for this i used .properties file to store database properties and that can be read at runtime.
For this i am using the following code
public void readPropertiesFile(){
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
Properties prop = new Properties();
prop.load(is);
String URL = prop.getProperty("DB_URL");
String user = prop.getProperty("DB_USER");
String pwd = prop.getProperty("DB_PWD");
is.close();
/* code to use values read from the file*/
}catch(Exception e){
System.out.println("Failed to read from " + PROP_FILE + " file.");
}
}
but i've to call this method whenever i want to connect to the database (for Connection object).
I know the thing that now processing is fast enough to run these lines in micro seconds, but it's for my own knowledge that suggest me the ways through which i can store these DB values when application starts or the first time user try to connect to DB for any operation in such objects or variables or constants that will be usable until the application restarts and can be called directly without reading the file.
P.S. : I know that the DB values will not change oftentimes, and if it happens than i'll be happy to restart my application :)
by making these static fields in a separate class, they will not be loaded until the first time you access URL,USER, or PASSWORD.
public class DbProps {
public static final String URL;
public static final String USER;
public static final String PASSWORD;
static {
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
try {
Properties prop = new Properties();
prop.load(is);
URL = prop.getProperty("DB_URL");
USER = prop.getProperty("DB_USER");
PASSWORD = prop.getProperty("DB_PWD");
} finally {
is.close();
}
}catch(Exception e){
throw new RuntimeException("Failed to read from " + PROP_FILE + " file.", e);
}
}
}
You can nake a check condition which will check if it is first time then set the value other wise use the existing value
public static boolean isFirstTime = true;
public static String URL = true;
public static String user = true;
public static String pwd = true;
public void readPropertiesFile(){
if(isFirstTime){
try{
InputStream is = ReadValues.class.getResourceAsStream(PROP_FILE);
Properties prop = new Properties();
prop.load(is);
URL = prop.getProperty("DB_URL");
user = prop.getProperty("DB_USER");
pwd = prop.getProperty("DB_PWD");
isFirstTime = false;
is.close();
/* code to use values read from the file*/
}catch(Exception e){
System.out.println("Failed to read from " + PROP_FILE + " file.");
}
}
}
//use this URL user and pwd in your application
Here's a generic environment class for you. You can get your DB props like Environment.getEnvironment().getProperty("DB_URL"), etc.
public class Environment {
private static final String PROP_FILE = "somefilename";
private static final Environment singleton = new Environment();
public static Environment getEnvironment() {
return singleton;
}
private Properties properties = new Properties();
protected Environment() {
super();
loadProperties();
}
public Properties getProperties() {
return properties;
}
public String getProperty(String propertyName) {
return getProperty(propertyName, System.getProperty(propertyName));
}
public String getProperty(String propertyName, String defaultValue) {
return getProperties().getProperty(propertyName, defaultValue);
}
public void loadProperties() {
URL resourceURL = null;
try {
resourceURL = Thread.currentThread().getContextClassLoader()
.getResource(PROP_FILE);
getProperties().load(resourceURL.openStream());
System.out.println("Loaded properties from "
+ resourceURL.toExternalForm());
} catch (IOException ioe) {
System.err.println("Failed to load properties from "
+ resourceURL.toExternalForm());
}
}
}
I have a static util class that does some string manipulation on a bit sensitive data.
Prior to use of this class I need to initialize certain static variables with values, such as usernames/password, that I prefer to store in a .properties file.
I am not very familiar with how loading of .properties file work in Java, especially outside of *Spring DI *container.
Anyone can give me a hand/insight on how this can be done?
Thank you!
Addition: .properties file precise location is unknown, but it will be on the classpath. Sorta like classpath:/my/folder/name/myproperties.propeties
First, obtain an InputStream from which the properties are to be loaded. This can come from a number of locations, including some of the most likely:
A FileInputStream, created with a file name that is hard-coded or specified via a system property. The name could be relative (to the current working directory of the Java process) or absolute.
A resource file (a file on the classpath), obtained through a call to getResourceAsStream on the Class (relative to the class file) or ClassLoader (relative to the root of the class path). Note that these methods return null if the resource is missing, instead of raising an exception.
A URL, which, like a file name, could be hard-coded or specified via a system property.
Then create a new Properties object, and pass the InputStream to its load() method. Be sure to close the stream, regardless of any exceptions.
In a class initializer, checked exceptions like IOException must be handled. An unchecked exception can be thrown, which will prevent the class from being initialized. That, in turn, will usually prevent your application from running at all. In many applications, it might be desirable to use default properties instead, or fallback to another source of configuration, such as prompting a use in an interactive context.
Altogether, it might look something like this:
private static final String NAME = "my.properties";
private static final Properties config;
static {
Properties fallback = new Properties();
fallback.put("key", "default");
config = new Properties(fallback);
URL res = MyClass.getResource(NAME);
if (res == null) throw new UncheckedIOException(new FileNotFoundException(NAME));
URI uri;
try { uri = res.toURI(); }
catch (URISyntaxException ex) { throw new IllegalArgumentException(ex); }
try (InputStream is = Files.newInputStream(Paths.get(uri))) { config.load(is); }
catch (IOException ex) { throw new UncheckedIOException("Failed to load resource", ex); }
}
Check out java.util.Properties.
You can use a static initializer. So on the top of the class you can do:
static {
Properties props = new Properties();
InputStream steam = ...; // open the file
props.load(stream);
// process properties content
String username = props.getProperty("username");
}
Use either:
CurrentClassName.class.getResourceAsStream
new FileInputStream(File)
to get the input stream depending on if the class is in or out of the classpath. Then use
Properties.load
to load the properties.
It's been a while, but if I remember correctly you just do something like this:
Properties prop = new Properties();
prop.load(new FileInputStream(filename));
//For each property you need.
blah = prop.getProperty(propertyname);
Well with static Properties it would make sense to initialize them as a Singleton which will be loaded once in a class. Here's an example:
class Example
{
public final static String PROPSFILE = "test.properties";
private static Properties props;
protected static Properties getProperties()
{
if(props == null)
{
props = new Properties();
props.load(new FileInputStream(new File(PROPSFILE));
}
return props;
}
public static User getUser()
{
String username = getProperties().getProperty("username");
return new User(username);
}
}
If you use relative Pathnames you should make sure, that your classpath is setup righ.
for me MyClass.class.getClassLoader().getResourceAsStream(..) did the trick:
private static final Properties properties;
static {
Properties fallback = new Properties();
fallback.put(PROP_KEY, FALLBACK_VALUE);
properties = new Properties(fallback);
try {
try (InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("myProperties.properties")) {
properties.load(stream);
}
} catch (IOException ex) {
// handle error
}
}
I agree with #Daff, maybe better to use singleton class...this what i have on my project for similar requirement, maybe it may help:
clients of the class can use it like this:
ConfigsLoader configsLoader = ConfigsLoader.getInstance("etc/configs.xml");
System.out.format("source dir %s %n", configsLoader.getSourceDir());
and then the class:
public class ConfigsLoader {
private String sourceDir;
private String destination;
private String activeMqUrl;
private static Logger log = Logger.getLogger(ConfigsLoader.class.getName());
private static ConfigsLoader instance = null;
private ConfigsLoader(String configFileName) {
log.info("loading configs");
Properties configs = new Properties();
try {
configs.loadFromXML(new FileInputStream(configFileName));
sourceDir = configs.getProperty("source.dir");
destination = configs.getProperty("destination");
activeMqUrl = configs.getProperty("activemqconnectionurl");
configs.setProperty("lastLoaded", new SimpleDateFormat("yyyy-M-d HH:mm").format(new Date()));
configs.storeToXML(new FileOutputStream(configFileName), "saving last modified dates");
} catch (InvalidPropertiesFormatException e) {
log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
} catch (FileNotFoundException e) {
log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
} catch (IOException e) {
log.log(Level.SEVERE,"Error occured loading the properties file" ,e);
}
}
public static ConfigsLoader getInstance(String configFileName) {
if(instance ==null) {
instance = new ConfigsLoader(configFileName);
}
return instance;
}
public String getSourceDir() {
return sourceDir;
}
public void setSourceDir(String sourceDir) {
this.sourceDir = sourceDir;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public String getActiveMqUrl() {
return activeMqUrl;
}
public void setActiveMqUrl(String activeMqUrl) {
this.activeMqUrl = activeMqUrl;
}
}
I did this finally using getResourceAsStream() fuction associated with the class in which the static code block is being written.
//associate Property and ImputStream imports
public class A {
static Properties p;
static {
p = new Properties();
try {
InputStream in = A.class.getResourceAsStream("filename.properties");
p.load(in);
} catch (FileNotFoundException e) {
System.out.println("FileNotFoundException");
e.printStackTrace();
} catch (IOException e) {
System.out.println("IOException");
e.printStackTrace();
}
}
.
.
.
}