how to pass parameter to static initialize block - java

What I want to do is load key/value pairs from a file (excel file using Apache poi) into a static map that will be used as a lookup table. Once loaded the table will not change.
public final class LookupTable
{
private final static Map<String, String> map;
static {
map = new HashMap<String, String>();
// should do initialization here
// InputStream is = new FileInputStream(new File("pathToFile"));
// not sure how to pass pathToFile without hardcoding it?
}
private LookupTable() {
}
public static void loadTable(InputStream is) {
// read table from file
// load it into map
map.put("regex", "value");
}
public static String getValue(String key) {
return map.get(key);
}
}
Ideally I want to load the map within the static initialization block, but how would I pass the stream in without hard coding it? The problem I see using the loadTable static method is it might not be called before calling the other static methods.
// LookupTable.loadTable(stream);
LookupTable.getValue("regex"); // null since map was never populated.
Is there a better approach to this?

Anything you use will have to be accessible at startup. As far as I know, your options are:
Hard-code the path. This is bad for obvious reasons.
A static variable or static method. This presents a bit of a chicken-and-egg problem; ultimately it gets hard-coded, but at least you can do a search with a static method.
Use a variable, either Java or Environment. So, you'd use something System.getProperty("filename", "/default/filename"). Better because it's at least customizable using the environment or -D parameters at JVM startup.
Use the ClassLoader getResource* methods. This is probably The Right Answer. Specifically, you'll probably want to use the getResourceAsStream() method on the current thread's context ClassLoader Thread.currentThread().getContextClassLoader(). (So, Thread.currentThread().getContextClassLoader().getResourceAsStream("filename") in total.) The ClassLoader will then find your resource for you (as long as you put it somewhere sane in your CLASSPATH).

Yes, there is a better approach, use the Factory design pattern to initialise the object before you have to use it:
http://www.oodesign.com/factory-pattern.html

You cannot pass information into static initialization blocks - they are supposed to work in isolation. Since the stream that you are planning to pass needs to be known before the program begins execution, presumably your LookupTable should be able to find it too. For example, this could be some sort of configuration utility that provides the stream for you. Then you can write your initializer like this:
static {
InputStream exelStream = MyConfigUtil.getExcelStreamForLookup();
loadTable(exelStream);
}
Presumably, there is a class in the system that could get your Excel stream from a source that is known to it. The source does not need to be hard-coded: it could read the location from a configuration file, or receive the data from a predefined network location on your server. In all cases the process of getting the Excel stream has to "bottom out" somewhere, in the sense that something in your system needs to be able to find it without additional parameters.

This is not directly answering your question, but I don't see why map has to be static. You could change map to non-static and change the constructor to public LookupTable(File file) {...fill map...}. You could then even have many instances of that class if you have different excel files; it might not be the case now, but it would "future-proof" your code.

This is probably a case for using lazy loading of the map.
But you will need to set the inputFileName before calling getValue() the first time. This would be done in your initialization code for the applications. (Or you could have a static method to set it.)
This points out the advantage of lazy loading. You don't have to have the file name available until you call getValue() the first time. With a static initializer, you have to get the file name stored somewhere outside the class so it can be used to load the data when the class loads (but after the static fields have been initialized.
public static String inputFileName = null;
public static String getValue(String key) {
if (map == null) {
map = = new HashMap<String, String>();
// open the file using 'inputFileName'
loadTable(InputStream is);
}
return map.get(key);
}
If your code is multithreaded, let me know and I'll comment on the synchronization issues.
Alternate
You could also use Spring to inject the map and build it in some other class -- MapBuilder for example.

Try using System.getProperty() and pass parameter with -D in command line.
static String prop;
static {
prop = System.getProperty("java.home");
}
public static void main(String... args) {
System.out.println(prop);
}

I would suggest a singleton enum approach if it suits your case.
public enum LookupTable {
INSTANCE(FileManager.getFileName());
LookupTable(String fileName){
props = new HashMap<String,String>();
//Read from excel and fill the hashmap
}
private final Map<String, String> props;
public String getMapValue(String key){
return props.get(key);
}
}
Which can be called by
LookupTable.INSTANCE.getMapValue("mykey");
This will call these methods in order
Get filename from a filemanager class, which is parametrized on your needs
Call the constructor (it is private) and load properties from the excel file
getMapValue for the key and return
A subsequent call LookupTable.INSTANCE.getMapValue("mysecondkey") will only call getMapValue as the INSTANCE is initialized beforehand.

Related

How to change values of "private static final String filePath" for unittesting

I have my class as
public class MappingLoader
{
private static final String filepath = "/tmp/mapping.properties" // unix path of production system
private static Map<String,String> mapping = new HashMap<String,String>()
static
{
loadMappingFile()
}
#VisibleForTesting
static void loadMappingFile()
{
//reading properties files here
final Properties prop = new Properties();
try (final InputStream input = Files.newInputStream(Paths.get(filepath)))
{
prop.load(input);
}
catch (final Exception e)
{
...
...
throw new RuntimeException(e);
}
//now load "mapping" from properties file
....
....
}
}
For testing, I need to change the value of string variable "filepath" such that it should take development system path(say c:\project\target\mapping.properties)
I have tried powermocks in junits, but it always throws exception and terminates.
annotations at class level:
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor("some.package.ClassWithStaticInit")
and in test case:
Whitebox.setInternalState(Mappingloader.class, "filepath", testfilepath);
Mappingloader.loadMappingFile();
I also tried to change this via reflection as given in(Change private static final field using Java reflection) but it always throws the FileNotFoundException for "filepath" and does not takes the changed path "testFilePath"
Is there any way i can change this variable such that it does not throw FileNotFoundException without any modification in source code?
If I remove "throw new RuntimeException(e);" in source code, powermocks works for me. but i want to achieve this without modifying source code, either via powermock, reflection api.
Well, you can try your luck with Powermock; and that should work (maybe if you spend some more hours reading its documentation and making experiments); but honestly: your problem is not testing. Your problem is that you created untestable code. And now you are trying to use the big powermock hammer to "fix" what is your broken design.
You see, when using static methods and constants; people think they "save" on performance (which is true; but to a very small degree; which probably doesn't matter for 99.999% of all applications); but they keep forgetting that using static leads to direct coupling of different functionalities. static is an abnormality in good OO design; and should be used with great care.
So, in your case, you could replace the whole thing with something along these lines:
interface MappingLoader {
Map<String, String> loadMappingsFrom(String fileName);
}
class MappingLoaderImpl implements MappingLoader {
...
and you see, all of a sudden you are only dealing with "real" interfaces and classes; and non-static methods; and surprise: now you can fully unit-test the whole thing; and most likely, you don't even need a mocking framework. You just create a temp file with mappings somewhere; and then you make sure that your impl class gives you the mappings from that file.
Zero mocking; zero testing of internal implementation details; just a few asserts.
And another advantage on top: all your client code that should only be using the MappingLoader interface can also be tested. Because ordinary frameworks like EasyMock or Mockito will allow you to mock out instances of that interface ... because: no static calls any more!
That is how you change the value of private final static fields - by not using them!
(and if I made you curious: watch this to learn how to write testable code from the beginning)
While I completely agree with #GhostCat's response, I understand you are looking for a solution not involving to change the source code. Have you thought of changing the contents of /tmp/mapping.properties before the test runs (and restore them later)?
static final String fields or any final static primitives fields cannot be modified in runtime. If speed honestly you can modify these fields, but your change will not affect code which uses these fields, because during compile time reference is replaced by value.
My suggestion: use static mock to Files.newInputStream()call and then return ByteArrayInputStream with expected data. In this case you will avoid fragile disk IO operation which could affect your test stability.

design an error reporting utility

I had difficulties finding a relevant title since it is not a simple issue. I will try to explain. I have a class responsible of error reporting whose methods basically wrap multiple ways of reporting an error.
For example, I have a method failTest:
public static void failTest(Logger log, Exception e, String message, boolean reportToES, String esTestPath, String esTestSet, String esTestInstance)
{
log.error(e, message);
someExternalErrorReportingService(reportToES, esTestPath,esTestSet,esTestInstance);
Assert.fail(e,message);
}
And I call this error reporting method in many, many places and it doesn't seem a good practice (too many parameters, hard to follow their order etc.) to just call it with the es* parameters each and every time because they don't change very often so they could be set up once and then reused.
And I came up with this version
public static void failTest(Logger log, Exception e, String message)
{//same body
}
And then added method to set up es* parameters
setES(boolean reportToES, String esTestPath, String esTestSet, String esTestInstance)
{
this.reportToES = reportToES;
this.esTestPath = esTestPath;
this.esTestSet = esTestSet;
this.esTestInstance=esTestInstance;
}
and of course added these instance variables above.
And only now I can enunciate the issue:
now if I want to use this error reporting class I need to first instantiate it and set the es* fields. The issue is that I often need to use the error reporting in a utility class that could be static but now, with my change above, I have to instantiate it and set up the error reporting class in order to have the es* fields set before I call failTest().
To conclude, I don't like this solution either because I can't use static utility classes anymore and moreover some utility classes are already used in a static way so cannot be refactored to non-static and will end up being used sometimes static, sometimes instantiated.
So the question is, do you see a better solution in order to simplify the calling of failTest() in utility classes?
To give you an example, we have a client that
sets up the error reporting class and sets up its es* fields
This client calls utility method Utility.doSomething
public static doSomething(reportToES, esTestPath, esTestSet, esTestInstance)
{
try{
methodThatThrowsFatalException()
}
catch(Exception e){
failTest(log, e, "Some smart message",reportToES, esTestPath, esTestSet, esTestInstance);
}
}
Now, in order to reduce the number of parameters we can just add setErrorReportingInstance to the Utility class,
then in client instantiate the Utility, then utilityInstance. setErrorReportingInstance(configuredErrorReportingInstance). And doSomething becomes:
public static doSomethingRefactored()
{
try{
methodThatThrowsFatalException()
}
catch(Exception e){
errorReportingInstance.failTest(log, e, "Some smart message");
}
}
What is not ok, from my point of view, is that:
1. I have complicated the usage of Utility. Now I have to make sure it is instantiated before I use it. It's inconvenient when having a lot of Utility like classes.
2. I cannot make static methods in Utility if I have to do error reporting in their implementation.
3. The methods that are already used as static will remain with the es* parameters in their signature (due to backward compatibility). So I will have in the same class methods like doSomething and also methods like doSomethingRefactored.
4. I have created a dependency between utility classes and error reporting so I have an issue when I need to test the utility methods
The question is, how can I keep the simple design of utility classes as simple collection of static utility methods but in the same time use the error reporting class but without passing too many parameters since it is bad practice?
More details:
Actually the client is many TestNG test cases:
So first I had :
class TestClass1
{
static final boolean REPORT_TO_ES="true",
static final String ES_TEST_PATH="somePath", //and so on for the others
#Test
{
Utility1.doSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility2.doSomethingElse(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility3.doSomethingMoreUseful(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility4.doSomethingSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
}
And then I would try to get rid of calling the doSomethings with the ES* values
by setting them once on the ErrorReporter instance (so I would also make ErrorReporter non-static).
class TestClass1
{
private ErrorReporter errorReporter = new ErrorReporter();
errorReporter.setReportToEs(true);
errorReporter.setEsTestPath("somePath");//and so on
Utility1 utility1Instance = new Utility1();
utility1Instance.setErrorReporter(errorReporter);
Utility2 utility1Instance = new Utility2();
utility2Instance.setErrorReporter(errorReporter);
#Test
{
utility1Instance.doSomething();
utility2Instance.doSomethingElse();
...
The title to your question should be "Static Mess".
Take a look at how real loggers work and you may get some ideas. Log4J and Slf4j are well respected ones. You need to control all of your static variables. You could create a Logger class that encapsulates the ES data and does the real work of logging:
// Does the real work of logging.
class Logger {
public Logger(all of your es data)
public fail(String msg) // Logs msg
}
Then you need a static collection of these Loggers referenced by name (I assume you have more than one set of es data). This gives you a central place to go get the loggers. Works if you're in a static method or somewhere else. The static collection goes inside the LogFactory object
class LogFactory {
private static Map<String, Logger> loggers ...
public static Logger get(String name) ...
}
Here is your static method using the new logger:
public static doSomething() {
try {
methodThatThrowsFatalException()
}
catch(Exception e){
LogFactory.get("Util").failTest(e, "Some smart message");
}
}
I would add a clear or reset method to LogFactory so that you have a chance of writing JUnit tests for your code. For the same reason I would write a NullLogger (in which case you might want to pull out an interface that the NullLogger and the EsLogger can both implement.
You need to decide how to add Loggers to LogFactory. I suggest doing it in your main class. Resist the temptation to do it in a static initializer.
LogFactory could also be written so it holds a collection and not a static collection. You then just keep a static reference (a Singleton) to it. Just keep in mind that you'll want a way to clear the Singleton to make unit testing possible.
Good luck.

Efficient way of reading Config file

We're developing a Java application that reads a Config file at runtime. My question is that which of the following scenario is efficient for reading a Config file.
Scenario #1: Retrieves a value from config by opening the file, get the value, then close the file.
So this means that file will be open and close every time retrieving a value.
Scenario #2: Open the file during initialization, then expose the object statically across the runtime.
File will be open once, then retrieving a value using the Config object.
Honestly, we currently using the scenario #2. A reason why we choose it because Config file will be open once. Opening file needs syncrhonization, which may lead to untimely retrieval of value. Also, scenario #1 may cause runtime error if the Config file is moved from it's absolute path (anything is possible). But scenario #1 is efficient when it comes in modifying the Config values during runtime.
So which is efficient?
Is your application a mulit-threaded application? if yes, you need to make sure that you have scenario #1 with necessary synchronisation and semaphores. The reason is that your config file is a general item in your application which will be used by all the threads. You don't want the config file reading operation to be interleaved. Even with single threaded operation, it is good to do #1 because you will have less chances of having IO Error. The RTE that you mentioned in your question can happen with anything if you decide to move the file (? Why would you if you need it at a certain place?).
If I should have to access the file more than once, probably I would create a class with a field for each configuration, I would read the file once (only to initialize the class fields) and then I would close the file. In this way you read the file once, during the init, and then you could simply access the configuration by reading the field values stored in the class.
public class Configuration
{
private static String confOne;
private static int confTwo;
private static boolean confThree;
public static init(File configFile) {
/* read the file and init fields */
}
public static String getConfigOne() {
return configOne;
}
public static int getConfigTwo() {
return configOne;
}
public static boolean getConfigThree() {
return configOne;
}
}
A little advice: tries to never hold open a file (or resources) unless absolutely necessary.
I think neither of the scenarios is the best one:
As you you have already stated in sencario #1 you may have a lot of unnecessary IO-Workload and in #2 you cannot change config parameters dynamically at runtime.
I suggest to use a mixture of both. You can load your configuration statically once and then check periodically, if changes have happend. If so, reload your config.
You can see how it may be done by inspecting Java's ResourceBundle-Class. In fact, if the config can be placed as properties-file in your classpath, you can (ab?)use this implementation for your purpose:
private static Control MY_CONTROL = new Control()
{
#Override
public long getTimeToLive(String baseName, Locale locale)
{
return MY_TTL; //make shure, that changes are checked periodically
}
};
public static String getParamter(String name)
{
ResourceBundle config = ResourceBundle.getBundle("config", MY_CONTROL);
return config.getString(name);
}

Bukkit config.yml connection

Alright, I'm trying to program a bukkit plugin and I need to have values from the config file, I've looked up the tutorial at
http://wiki.bukkit.org/Configuration_API_Reference#The_Configuration_Object but this gave me no assistance.
So my code for connect.java is this:
package com.live.AlioGenerica.netherflight;
import java.util.Set;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
public class users {
this.getConfig().options().copyDefaults(true);
public static Boolean getValue(Player p) {
this.getConfig().getBoolean(p);
return true;
}
public static Object setValue(Player p, Boolean v) {
conval.myConfig().set("users." + p + ".boolean", v);
return true;
}
}
config.yml is this:
users:
username: false
userother:true
and etcetera.
How in the world do I connect, I couldn't find anything. I know this is a mess, because I have no idea how to do it.
I myself create Bukkit plugins on my own. The YamlConfiguration is quite easy to use. You can use the method
public void set(String option, Object value)
to set a certain configuration option (option) to a specified value (value) and
public Object get(String option)
and others to get a previously set value. To find all the methods you can use, look them up in Bukkit's JavaDoc for YamlConfiguration.
If you want to save your YamlConfiguration, use
public void save(File f) throws IOException
Besides that, you should work on your coding. Here's a improved version of your code as it is now.
package com.live.AlioGenerica.netherflight;
import java.io.IOException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
public class Users {
private static YamlConfiguration config = null;
// some code
// this method has to be static if you want to use it
// in another static method
public static YamlConfiguration getConfig() {
// load the configuration if it hasn't been loaded yet
if(config == null) {
config = YamlConfiguration.loadConfiguration("path/to/config.yml");
}
// some code
return config;
}
// this will return the boolean you want to get
public static Boolean getValue(Player p) {
return getConfig().getBoolean("users."+p.getName());
}
// use this code to set the value
public static void setValue(Player p, Boolean value) {
getConfig().set("users."+p.getName(), value);
}
// save the configuration
public static void save() {
try{
config.save(new File("path/to/config.yml"));
}catch(IOException e){
e.printStackTrace();
}
}
}
If there are any questions left, just let me know.
#EDIT: Just realized you wanted to save a boolean for a player so that it looks like this in the configuration.
users:
player: true
anotherplayer: false
andsoon: false
Ok, so to deal with the config, the first thing you want to do is actually have a config and put it in the correct place. It looks like you have a config, so you just have to make sure it's located in the resource section of your plugin. After you do that, then you can start dealing with it in your code.
First you want to actually get the config. You do that with this code.
FileConfiguration config = plugin.getConfig();
Simple enough. Now what you want to do is make it so that the plugin will retrieve the values in the config.
config.options().copyDefaults(true);
Finally, you just check to see if the config has been saved in you plugin's data folder.
if (!(new File(plugin.getDataFolder() + config.getName()).exists())) {
plugin.saveDefaultConfig();
}
After you do all those things, you can retrieve the actual values of the config with:
plugin.getConfig().getBoolean("username");
Using this.getConfig() can only be done from the main class that extends JavaPlugin.
You can use the getConfig() and methods built in with that if you do something like this:
public class Example {
MyPlugin plugin;
public String getSomethingFromConfig() {
return plugin.getConfig().getString("path");
}
}
Thats the Easiest way, In My Opinion.
Having a configuration file to get reference variables is very easy to do once you know how to do it. Starting this off you need actually have a config.yml in your src folder of your project. If you are not in Eclipse, I would suggest switching to it to do this easier. Just make a file called config.yml. You can put your variables inside of here that I see you have already did.
After this you need to create the config file when the server starts.
You would need to call a method on your onEnabled method from your main class. You can pull the getConfig() method from other classes also, that I will show you how below.
Since everytime the console enables it will do this method you will need a try/catch operation:
try
{
}
catch (Exception e)
{
e.printStackTrace();
}
The catch is if something goes wrong it will print a stackTrace to console. Inside of the try you will create the config.yml. To do this you will need to make a file variable inside of the try:
File config = new File(getDataFolder(), "config.yml");
Before you can make the config there has to be a data folder for the config to be stored in. To make this data Folder you will need to first see if it is there:
if(!getDataFolder().exists())
{
getDataFolder().mkdirs();
}
After making the data folder you will need to check if the config.yml is already there, and if not create it.
if(!config.exists())
{
getLogger().info("Config.yml not found, Creating");
saveDefaultConfig();
}
Having the saveDefaultConfig(); method will make sure to save your #notes inside of your config file to tell the user what each variable does. This is the best way to save your config file upon creating it. If the config already exists you can put an else and say that it is already there, but this is not necessary.
Make sure all of that is inside of a method that is called in the onEnable() method from your main class. Now that your config is created you can easily get variables from the main class by using the method getConfig()
You can also do this from other classes that I will tell you how to do soon. You can grab any variable from the config by doing getConfig().get ... and past here you can get many things such as strings, integers, booleans, etc... It will then give you a string to find the variable from. This will be the variable name inside of your config.
To use the getConfig() method from other classes you will need to use a constructor. You will need to call an instance from the main class to do this.
In your other class make a constructor like this:
[MainClassName] plugin;
public [OtherClassName]([MainClassName] instance)
{
plugin = instance;
}
The plugin variable will be your instance from the main class. You can use plugin.getConfig() to get the config now.
However, when you register events/commands you will need to match this constructor. Just put this to match the constructor when registering events/commands.
I also notice that you have variables inside of variables. To get the variables inside of the variables you need to get a Configuration Section:
for(String key : instance#getConfig().getConfigurationSection([config path]).getKeys(false))
The String key will be the variable inside of the variable. Since this is iterating, it will get all the variables inside of the variable with the one string key. To get the value of the key variable you would just make a boolean/int/string or whatever is inside and get it by doing:
[String/boolean/int/etc...] value = instance#getConfig().get[Int/String/Boolean/etc...]([first config path]+"."+key)
This is all you need to know about configuration files.

Is there any way I can store a string in the context.xml during run time?

At many places in my web application I need a certain String which is :
request.getServletContext().getRealPath("/");
// I can only get this once the web-app starts
Sometimes a simple java class needs to know this string. I don't want to pass each and every time this string to the class's function. One way could be to stash this string in a file at the very beginning of the web application. Every time I would need this, simply read the file.But this doesn't seem a pretty good option. Is there any other way out ?
May be I can store in the context.xml of the application. If it is possible how do I do that ?
If there is a better way please suggest.
I am using tomcat as the server.
Invoke run the following code when your application starts (e.g. with a ServletContextListener):
public void contextInitialized(ServletContextEvent sce) {
ServletContextRootRealPath.set(sce.getServletContext().getRealPath("/"));
}
Then later whenever you need it you simply call
ServletContextRootRealPath.get()
Since it's all static the variable is accessible JVM-wide to every code that runs in this JVM.
Utility class
public final class ServletContextRootRealPath {
private static String path;
private ServletContextRootRealPath() {
// don't instantiate utility classes
}
public static void set(String rootRealPath) {
path = rootRealPath;
}
public static String get() {
return path;
}
}
You can store the value in static variable of any class (Basically a helper class which is used for serving common utility functions). Later you can refer to this variable without creating instance of the class, as it is static and can be accessed without its instance.

Categories

Resources