Reading Java property groups from a file - java

Is it possible to read different property groups from a Java file, without manual processing?
By "manual" I mean reading the file line by line, detecting where the start of a property group is and then extracting the corresponding key-value pairs. In practice, this means reinventing (most of) the wheel that the Properties.load() method constitutes.
Essentially, what I am looking for is an easy way of reading, from a single file, multiple groups of properties, with each group being identifiable, so that it can be loaded in its own Java Properties object.

I you want to use java.util.Properties you can use prefixes. In .properties file:
group1.key1=valgroup1key1
group2.key1=valgroup2key1
group2.key2=valgroup2key2
and read them like this:
class PrefixedProperty extends Properties {
public String getProperty(String group, String key) {
return getProperty(group + '.' + key);
}
}
and using:
/* loading, initialization like for java.util.Properties */
String val = prefixedProperty.getProperty("group1", "key1");
You can also use ini4j with windows ini files.
Another, better way is using own, custom structured file (for example XML).

Related

How to read a Iterable nested object - Java

Hi all I have the following yaml file example 'test.yml'
server:
port: 1000
someDate: /abcd
anotherConfig:
host: http://localhost:1000
fileList:
files:
- name: filea
filePath: \filea
- name: fileb
filePath: \fileb
---
anotherdoc:
data: 300
nestedData:
animal:
- name: dog
I read this file like so:
Yaml yaml = new Yaml();
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("test.yml");
Iterable<Object> rules = yaml.loadAll(inputStream);
for (Object rule : rules) {
Map<String, Object> map = (Map<String, Object>) rule;
System.out.println("blah");
}
I am wondering how it is possible to get data from the rules object, e.g. if I wanted directly to search fileList/files or nestedData/animal so that I can use the path to get a List directly.
(Note yaml structure varies so cannot seem to use the entities method)
fileList/files is not a path in YAML terms because the YAML spec does not define any kind of path. You can:
use composeAll to get an iterator on Nodes. Nodes represent the YAML's structure and you can navigate through them similar to an XML DOM. You can then write a function that can walk a path.
plug in a modified parser that throws away everything not on your desired path, so that only your path is constructed. This example shows the basics for a slightly different use-case.
Write a custom constructor that throws away everything around the desired path. I am not entirely sure whether this is possible because the constructor API is a bit strange.
I suggest using method 1. It is flexible enough to deal with any kind of YAML structure, while being far less complex than the other methods. When you arrive at your desired Node, you can even use the Constructor class to construct a List or whatever you need from it.

What is the best way to store a common part of Strings in Java?

I have some very similar string like this:
String first = "differentConfig1,config1,config2,config3,config4,config5,config6,config7,config8,config9";
String second = "differentConfig2,config1,config2,config3,config4,config5,config6,config7,config8,config9";
String third = "differentConfig3,config1,config2,config3,config4,config5,config6,config7,config8,config9";
where config1 ... config9 are the same in each string, but differentConfig1, differentConfig2 and differentConfig3 are different
what is the best way to avoid duplicating config1-9 in each string?
(Note that config1-9 are around 1 line long values)
What I have now is:
private String commonConfiguration() {
return "config1,config2,config3,config4,config5,config6,config7,config8,config9"
}
and then the strings are constructed like this:
String first = "differentConfig1," + commonConfiguration();
I was thinking about using variables instead of a function, but I am afraid that a very long variable at the beginning of the function would make it less readable.
Configuration strings are better when stored in files. This is how most systems work too. Ex: Most systems like Kafka or Cassandra have configurations of loging, log file location, addresses etc in such configuration files.
So with this approach you can change these configuration strings as per a different environment as needed without impacting code.
With the use of a properties file, your input would just be a collection of key-value pairs.
firstConfig="differentConfig1,config1,config2,config3,config4,config5,config6,config7,config8,config9"
secondConfig="differentConfig2,config1,config2,config3,config4,config5,config6,config7,config8,config9"
thirdConfig="differentConfig3,config1,config2,config3,config4,config5,config6,config7,config8,config9"
I dont really suggest breaking it further, but if you are sure that they will always have the same commonPrefix, one option is to do something like this:
In your properties file,
firstConfig="differentConfig1"
secondConfig="differentConfig2"
thirdConfig="differentConfig3"
commonPrefix="config1,config2,config3....config9"
And in your code, you read these configuration string and append them. Something like this:
String c1 = Registry.getString("firstConfig")+Registry.getString("commonPrefix")
String c2 = Registry.getString("secondConfig")+Registry.getString("commonPrefix")
String c3 = Registry.getString("thirdConfig")+Registry.getString("commonPrefix")
Note: Properties file just a file that is present in your java project that holds the information of the configurations as a key-value pair.

Apache Camel: How to look inside body to determine file format

We receive .csv files (both via ftp and email) each of which can be one of a few different formats (that can be determined by looking at the top line of the file). I am fairly new to Apache Camel but want to implement a content based router and unmarshal each to the relevant class.
My current solution is to break down the files to a lists of strings, manually use the first line to determine the type of file, and then use the rest of the strings to create relevant entity instances.
Are there a cleaner and better way?
You could use a POJO to implement the type check in whatever way works best for your files.
public String checkFileType(#Body File file) {
return determineFileType(file);
}
private String determineFileType(File file) {...}
Like this you can keep your route clean by separating the filetype check and any other part of processing. Because the filetype check is just metadata enrichment.
For example you could just set the return value as a message header by calling the bean)
.setHeader("fileType", method(fileTypeChecker))
Then you can route the files according to type easily by using the message header.
.choice()
.when(header("fileType").isEqualTo("foo"))
...

How to recognize if given file or String is in Java Properties file format?

How to recognize if given content (file, String or InputStream) is in Java Properties file format?
The content is stored in database and should be parsed into Properties if it is a properties file. However, with a simple test I've noticed, that java.util.Properties parsed without error an xml file </log4j). It could 'parse' also a normal text file.
So, if the java.util.Properties can parse practically everything what is text, how can I recognize if I have properties file or not? Need I check if this is in any other recognized format, can I use some heuristics or there is an existing library with such functionality?
I would do it this way
private boolean isProperties(Scanner sc) {
Pattern p = Pattern.compile("\\w.*[=:] *.+");
int nProps = 0;
while (sc.hasNextLine()) {
String line = sc.nextLine();
if (!line.startsWith("#")) {
if (!p.matcher(line).matches()) {
sc.close();
return false;
}
nProps++;
}
}
sc.close();
return nProps > 0;
}
public boolean isProperties(String s) {
return isProperties(new Scanner(s));
}
public boolean isProperties(File f) throws FileNotFoundException {
return isProperties(new Scanner(f));
}
... more overloaded isProperties for different sources
This is just a prototype, regex may need improvement, see Properties.load API. I would ignore xml version, but if need be it's even simpler since there is DTD in API
I would read the stream (file or string) e.g. into BufferedReader. Then, I would check for
properties on form of xml file:
Taken from javadoc:
The XML document must have the following DOCTYPE declaration:
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
So you can check for DOCTYPE (using reader and going through first lines or - by parsing with xml parser, e.g. jdom). If DOCTYPE is there, use:
Properties.loadFromXML()
Otherwise you can look for line matching the pattern \s*\w+\s*=.*
so you will know that some assignment is made there, so it can be properties file,
that you load with:
Properties.load()
You can send the propertyNames() method to the resulting properties object and if you get back one or more names (you get back an Enumeration - use the hasMoreElements() method as your test) then you can assume it's a valid properties file.

storing and retrieving a list of systems, ips, and usernames

I have a properties file which currently contains system names and ip addresses. What would be the best way for me to store usernames with it as well. Can you use more then one element or key in a properties file? Thanks for any help and suggestions.
Create a class that has the fields you require along with the relevant getters and setters. Then you can set the fields to hold whatever you need and add these objects to your map as the value, e.g.:
public class SystemInfo {
private String systemName;
private String ipAddress;
private String username;
public SystemInfo() {
// do whatever
}
public void setSystemName(String name) {
this.systemName = name;
}
// etc.
}
Then you can create an instance of this, set the information required and store it in your map using whichever field you want as the key (or use some other data structure to store them), e.g.
SystemInfo system1 = new SystemInfo();
system1.setSystemName("The Name");
// etc.
Map<String, SystemInfo> systemMap = new HashMap<String, SystemInfo>();
systemMap.put(system1.getSystemName(), system1);
Are the usernames associated with particular systems?
If so you could just create two properties for each system. One could have a key "(system)_address" and the other "(system)_username"
This is assuming there's only one username per system
1.
system1.ip=10.100.151.1
system1.username=John
2.
Use database instead of properties file.
A Java .properties file is just a text file with key/value pairs in the form "key=value" or "key:value" and represented in Java as a Properties object which is a subclass of Hashtable. While you can store/load the file to XML, it is often much easier to use the default "key=value" form. The keys should be unique, and the values should not contain the delimiter ('=' or ':') unless escaped with a '\'. That said you can add whatever information to the file you want. For more detailed information, check out the API doc: http://java.sun.com/javase/6/docs/api/java/util/Properties.html#load%28java.io.Reader%29. You can use as many keys as desired, as long as they are unique. Depending on the problem you are trying to solve, there may be a better approach.

Categories

Resources