As part of my test base class, I have something like this:
seleniumJupiter.getConfig().setDefaultBrowser(BROWSER.getStringValue());
seleniumJupiter.getConfig().setScreenshotAtTheEndOfTests("whenfailure");
SeleniumJupiter.getConfig().takeScreenshotAsBase64AndPng();
and potentially 10-20 more config parameters. Could I somehow overwrite the whole selenium-jupiter.properties file and change some of the properties and other left default?
You can maintain your own copy of selenium-jupiter.properties in your project classpath, changing the values you need, and leaving the default values for the others. Then, you have two options to configure Selenium-Jupiter to use that properties:
Using a JVM property: -Dsel.jup.properties=/my-sel-jup.properties
Using an environmental variable: SEL_JUP_PROPERTIES=/my-sel-jup.properties
Related
The situation is as follows: I'm using some libraries that use a specific class to load and access configuration parameters. The config loader class is implemented in one of the libraries.
What I did is: to extend the config loader class so that it fits my requirements and is able to load different config sources:
public class BetterConfigLoader extends OldConfigLoader {
...
}
Now I want to make the existing libraries use my compatible BetterConfigLoader without applying changes to the libraries or without the need to recompile them.
Is there a way of best practice to accomplish this?
This depends on how your libraries refer to the configuration class. Do they have a hardcoded new OldConfigLoader().configure()?
Or do they use some kind of SPI technique, e.g. checking for existence of a resource named META-INF/services/ConfigLoader, and only if not existing, falling back to the default configuration class?
Instead of checking such a resource, they could as well check a System Property.
In these cases, you can set your special class by creating a matching SPI resource, or by setting the System Property.
In case of hardcoded reference, you are out of luck.
Instead of extending OldConfigLoader you can replace it. Start with the source code of OldConfigLoader, change it to suit your needs and then make sure your version is higher in the classpath then the original. Make sure your implementation has the same classname and is in the same package as the original.
I'm in the middle of a massive refactoring project, the code has a 5000 line main class which was injected into everything, stored everything and had all of the common code.
I'm no expert on analysis and design but I've separated out things to the best of my ability and I'm about 80% through refactoring the classes that depend on the main class to use the new classes I've created.
There are some types of data which are initialised when the application starts and accessed by pretty much everything throughout the life of the application. For instance there is a Config class which holds hundreds of parameters.
The approach I've taken is to create several singletons the two most central are GUIData and ClientData. GUIData contains a reference to the mainframe of the application and clientdata maintains references to the config and other similar classes.
This allows me to call ClientData.getInstance().getConfig().getParam("param") from anywhere in the code but I don't feel like this is the best approach.
I considered individual static classes instead of these data singletons which contain instances of the classes but some of the classes do need constructors.
I've been googling on and off for a week trying to find a better way to do this but somehow I always end up on threads talking about database caching
Immutable (configuration) instances provide "thread-safe application-wide data access".
Typesafe's config (as suggested in a comment by Brian Kent) does exactly that.
Note that this does not involve static classes or singletons. Static classes and singletons may serve your purposes now,
but they could prove bothersome in the future. They can be handy ofcourse, but try limiting their use.
Initialization will have to be done after reading and parsing the configuration data. It is typically done at application startup, before other processing threads are started. The initialization will have to validate the configuration data as much as possible in order to fail fast and terminate the program if the configuration data is no good.
Having a lot of configuration data bundled together can create "hidden lines of communication". E.g. you update one value and the application fails because it required updates to other values as well. It's perfectly fine to put all configuration data in one file and load it from there, but your application (with hundreds of configuration options) should divide the configuration data in sets that are used by different parts of your application. This improves isolation, helps unit-testing and makes it possible to change the application in the future without getting too many nasty surprises.
There are two ways to use a set of configuration data:
from within an object call a singleton Settings.getInstance().getConfigForThisModule().
provide each object that uses configuration data with the configuration data via the constructor or via setConfig(ConfigForThisModule config).
The first approach depends on a convention not to call Settings.getInstance().getConfigForACompletelyUnrelatedModule() which could be a weakness. The second approach is more in line with "dependency injection" and could be more future proof.
You could mix both approaches while you are refactoring, just make sure to be consistent (e.g. only use the singleton approach for configuration data that is used in all parts of the application).
To further improve your design for using the configuration data, keep the following (likely) future functional requirement in mind: when the configuration file is updated, configuration data is reloaded and used in the application. Most logging frameworks manage to support this functional requirement without affecting the performance of multi-threaded applications. Among other things, it requires the following of your application:
if the new configuation data is no good, the program is not terminated but an error is logged instead and the old configuration data remains in use. Your initialization procedure will need to handle both "load at fresh start" and "reload" scenarios. The main thing to take away from this is that your initialization procedure needs to be re-usable and should not affect other (running) parts of your application (isolation, again).
long-lived objects may not keep a local copy of configuration data or a reference to an instance of ConfigForThisModule, instead Settings.getInstance()... (or some other method that can return an updated instance) should be called regurarly.
replacing old configuration with new configuration may not result in errors. Technically, replacing the configuration is as simple as updating an AtomicReference with a new configuration instance returned with Settings.getInstance().... But this is also where the isolation of the configuration data sets are tested: there should be no problem using an old set in one module and a new set in another module at the same.
Configuration data can be seen as a sort of "global state". With that in mind, further design points on what to do and what to avoid (partially blatantly copied to this answer) are discussed in the following two questions:
Why is Global State so Evil?
How are globals any different from a database?
Sorry, the question is a bit vague, are you looking to store the config or the cached objects used by other parts of your program ?
Since you have 100s of params, start with splitting up the config into manageable blocks
1) Split up your configuration parameters into logical blocks that have 1:1 correspondence with a simple properties file -its going to take some time
2) These property files must be externalized so that you can change them at any point in time, make sure that you pass in the base location via a env variable to the program
3) Write a utility class (singleton) that wraps Apache commons configuration to hold your config. (read *.properties from the base location and merge the properties into one configuration object) this must be done before any threads are kicked off.
4) Refer to the configuration param in your code using config.getXXXX() methods
Apache commons config also has ability to reload the config when your properties file changes on the filesystem.
Once this is done, use a DI container like Spring or Guice to cache the configured objects.
If it's just String property values you need, you don't even need a class for that - a global facility exists for you already: System.getProperties()
All you need do is first load the property values on start up:
System.setProperty("myKey", "myValue"); // see below how load properties from a file
Then read it anywhere in your code:
String myValue = System.getProperty("myKey");
or
String myValue = System.getProperty("myKey", "my desired default");
If your container doesn't support property loading out of the box, to load properties from an external file that looks like this:
key1=value
key2=some other value
etc...
you can use this code:
Files.lines(Paths.get("path/to/file"))
.filter(line -> !line.startsWith("#") || !line.contains("=")) // ignore comment/blank
.map(line -> line.split("=", 2)) // split into key/value
.forEach(split -> System.setProperty(split[0], split[1])); // load as property
you can use the Java Properties class util, basically its a HashTable
reference : https://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
you create a file fileName.properties and store your data in key value pairs, for example:
username=your name
port=8080
then you load it into Properties Object and get the data like the following:
Properties prop = new Properties();
load the file...
String userName = prop.getProperty("username")
String port = prop.getProperty("port")// you can parse it to int if needed
what i suggest is to create a property file for each type of configuration like:
clientData.properties
appConfig.properties
you can follow this simple tutorial
http://www.mkyong.com/java/java-properties-file-examples/
I see that the Configuration class in Hadoop is writable http://hadoop.apache.org/docs/current/api/org/apache/hadoop/conf/Configuration.html. However, I do not see any of the methods that it has exposed that can be used to add a writable object (I see a lot of methods to set and get primitive types like int, long). Let us say, I have my own writable object and I want to add it to the configuration for all my mappers and reduces to use, how do I do this?
Thanks,
Venkat
The configuration is really not for passing entire objects. The configuration should be used more for setting simple parameters that are needed for the setup of the Mappers/Reducers. Think of the conf as you set the variables at the beginning of the job. If you make changes during the middle of a run to the configuration, it most likely won't be there at the end as it's not really meant to dynamically pass data.
What you are looking for if you want to pass around entire Objects between nodes is the Distributed Cache. Technically speaking these are files, but you can use standard object serialization to add them. About the Distributed Cache.
*apologies for linking different hadoop versions, their pages are a bit muddled and hard to find what you need sometimes.
You can check HBase sources (starting from HBase 0.94.6) MultiTableInputFormat.setConf() class method and appropriate TableMapReduceUtil code (for example .initTableMapperJob()). They pass Scan objects through configuration. Earlier TableInputFormat.setConf() class uses very similar mechanics.
Usually only minimal attributes are passed through config but this is probably case closer to your one.
Hope it will help.
I have a resource bundle which consist of a few files, lets say:
address_en_us.properties
address_nl_nl.properties
address_fr_ca.properties
How do I obtain and merge two of the properties file with en_us being the 'default' property file?
Some background:
When I use one of the localized property, say, fr_ca, for each keys that are not localized in fr_ca, I want to use the default value specified in en_us
Just rename your "address_en_us.properties" to "address.properties" and this file is always used as 'default' property file.
One way I have seen work is to have the default values set in code, where it is hard-coded in java class. That way any property not set in properties file but used in code will always get the default value.
And from an architecture perspective this is also a really good idea, shipping products with default properties values in code, overridden by the values in properties file. And if you make it so that the product (Android app in my perspective) makes a server call at start-up to check and overwrite the values of properties files then you can add a lot of flexibility to the product.
In my application I use some icons. Where should I store the path of the directory containing those icons ?
The icons are used in different classes so it doesn't really make sense to store them in one of those classes in particular.
I read that global variables are evil, but is it acceptable to use a class (eg Commons) containing only public static final fields to store this king of data ? What solution is used in professional applications ?
Global Constants
As others state, global constants don't have the same negative connotation as global variables. Global variables make a program difficult to debug and maintain because of uncontrolled modifications. Global constants (public static final) don't create the same problem
Nevertheless, object-orientation is about binding code close to its data to enhance understandability and maintainability. You still have to find the right balance between storing global configuration values in a global class vs keeping data close to the code that will use it.
It is probably also worth reminding here that, because the compiler may inline some constants, if you change a constant value, you may have to recompile and redeploy more than just the class that contains the constants.
Externalizing Values
You also asked about what professional apps do. Its not uncommon for those apps to make these types of values, like files paths, externally configurable. It depends on how likely the value is to change (i.e. how likely your app will move or your code will be used in another app) and how convenient or easy it is to recompile and redeploy the code with new values. If you do choose to make some values externally configurable, you still may want to encode default values for those items in the code.
Here are some ways to externalize those values and some links to get you started. This is of course not an exhaustive list:
System properties so you can specify them on the command line
Property files [See StackOverflow Q - How to use java property files?]
Resource Bundles [See StackOverflow Q - How to load a resource bundle from a file resource?]
Global variables are evil (since they make it nearly impossible to figure out who modifies what), but constants aren't evil. public static final String fields are fine, since they can't be modified.
I would recommend to include them (the icons) with your class files in a jar, say a folder called resources and only the icon loader needs to know the resources folders name within your jar.
You are referring to constants, not global variables, so don't worry about them being evil - they are not, because they don't change.
if they are used by one class - place them in that class
if they are used by multiple classes in one package - place them in a special class
if they are used by multiple classes and they logically belong somewhere, place them there.
Have in mind that in case these "constants" are actually configurable, you'd better pass a Configuration object to methods that need it. Well, you may have the static somewhere, but from testability point of view it is a must to inject them / pass them.
Global variables are not the same as global constants. The reason global variables are bad is because they can be changed anywhere in the code and it is very hard to track down errors that result from a global variable not being in the expected state. Global constants will always be in their expected state because they can never be changed inadvertently.
In general I would suggest that this particular case be a packaging problem and to not reference the items as files on the file system, but rather as elements in the classpath, and load them via a classloader. This requires setting their location in the classpath of your application.
Then there should only be one class that knows how to retrieve these icons, and all other code asks that class for the icons it needs.