dazito
dazito

Reputation: 7980

How to personally format a properties file in java?

I'm using properties class from java to save some configuration for my application. It's the first time I'm using properties so please be gentle with me :)

I can insert and retrieve data from the properties, no problem, but I want to insert the data as something like:

Properties file:

#Header generated by java ~ this is fine, I don't care

#Server 1 configuration
url=192.168.1.1
port=6546
username=max
password=123

#Server 2 configuration
url=192.168.2.1
port=6454
username:dude
password:123

#And so on...

This is my code:

public void setProp(String host, String port, String user, String pass, 
                           String host2, String port2, String user2, String pass2)
{
        try{
            prop.setProperty("host", host);
            prop.setProperty("port", porto);
            prop.setProperty("username", user);
            prop.setProperty("password", pass);

            prop.setProperty("host2", host2);
            prop.setProperty("port2", porto2);
            prop.setProperty("username2", user2);
            prop.setProperty("password2", pass2);

            config.store(new FileOutputStream("configuration.properties"), "Server 1 Configuration");

        }catch (Exception e) {
            JOptionPane.showMessageDialog(null,"Error: "+e.getMessage());
        }
}

EDIT: @Nathan Not close to what I pretend. The properties file generated is:

#Wed Apr 03 14:03:57 BST 2013 
server1.url=192.168.1.1 
server1.port=80 
server2.password=qqq 
server1.user=root 
server2.port=88 
server2.user=dude 
server1.pass=123 
server2.url=192.168.2.1

I would be looking for something like:

#Wed Apr 03 14:03:57 BST 2013 
#Server 1 details
server1.url=192.168.1.1 
server1.port=80 
server1.user=root 
server1.pass=123 

#Server 2 details:
server2.password=qqq 
server2.port=88 
server2.user=dude 
server2.url=192.168.2.1

I dont even care if the order is not right (like password above url and under port, etc) I just need them to be grouped by, as they are in my example now.

Upvotes: 3

Views: 17021

Answers (4)

Pete B.
Pete B.

Reputation: 3276

I think I see your problem...when you have:

#Server 1 configuration
url=192.168.1.1
port=6546

#Server 2 configuration
url=192.168.2.1
port=6454

Only the last value for url, port, etc... will be read in the properties file, as each subsequent one will overwrite the previous. I typically got around this by doing something like:

#Server 1 configuration
server.1.url=192.168.1.1
server.1.port=6546

#Server 2 configuration
server.2.url=192.168.2.1
server.2.port=6454

....

#Server n configuration
server.n.url=192.168.2.1
server.n.port=6454

You can also store a total number of servers, with a property like:

number.of.servers=55

But that is assuming the server numbers are sequential. In the more general case lets assume that they are not so you can have something like:

#server 1
url=xxx
port=123

#server 100
url=xxx
port=123

#server 5
url=xxx
port=123

As @Nathan Hughes concisely pointed out properties are key value pairs, and each duplicate key will blow away the previous key. I have not used YAML, but I would much prefer JSON over XML. However you can still stick to properties.

As previously pointed out you could do something like this:

#server 1
server.1.url=xxx
server.1.port=123

#server 100
server.100.url=xxx
server.100.port=123

#server 5
server.5.url=xxx
server.5.port=123

So now the question becomes, which server numbers are in my properties file. Just iterate over the keys of the properties file, and do some String kung fu.

Properties p = myReadProperties();
Set<String> keys = p.keySet();
Set<Integer> serverNumbers = new Set<Integer>();
Iterator<String> i = keys.iterator();
String str, strArray;
while(i.hasNext()) {
  str = i.next();
  //A regex would be better here, but for brevity.
  if(str.startsWith("server.") && str.endsWith(".url")) {
    strArray = str.split(".");
    serverNumbers.add(new Integer(strArray[1]));
  }

So now you have a set of the server numbers. You can reconstruct your properties keys to get any value.

Upvotes: 4

Nathan Hughes
Nathan Hughes

Reputation: 96385

Properties files are not hierarchical like that. (There are other formats that are, like YAML or XML, but not this one.) Instead every line is a key-value pair, where the key has to be unique across the file. (The Properties class was a quick hack extending from Hashtable.) Change the keys in the properties file:

#Server 1 Configuration
server1.url=192.168.1.1
server1.port=6546
server1.username=max
server1.password=123

#Server 2 configuration
server2.url=192.168.2.1
server2.port=6454
server2.username:dude
server2.password:123

Then change your code to something like:

      prop.setProperty("server1.url", host);

Because Properties extends Hashtable, and hashtables give you their own internal ordering of their key-value pairs, when you generate a properties file from a Properties object the entries are going to be all jumbled up. Since you want the keys to be in an arbitrary order sorting will not be easy either. I'd use the code to generate the initial version of the properties file, then move stuff around to be in the order you want, and use that property file going forward. If you need to generate properties files programmatically then you'll want to write code to write to the file in place of how Properties does it.

Upvotes: 6

IndoKnight
IndoKnight

Reputation: 1864

If you use FileOutputStream, you can create output file and write to it in the format you asked straight away. But, if you use Properties then you will not be able to repeat same keys.

Upvotes: 0

Marcelo Tataje
Marcelo Tataje

Reputation: 3871

#Server 1 configuration
url=192.168.1.1
port=6546
username=max
password=123

#Server 2 configuration
url=192.168.2.1
port=6454
username:dude
password:123

So if I understand, you want to create a configuration file like this. What you could do to format it is to once saved, open the file and insert the lines you want, which will be a very painful job. If you want a very well-structured configuration file, then why you don't try with xml and jaxb?

Something like:

<servers>
<server>
<id>1</id>
<url>192.168.1.1</url>
<port>6546</port>
<username>max</username>
<password>123</password>
</server>

<server>
<id>2</id>
<url>192.168.2.1</url>
<port>6454</port>
<username>dude</username>
<password>123</password>
</server>
</servers>

You can create an schema based on this:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="servers">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="server" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:byte" name="id"/>
              <xs:element type="xs:string" name="url"/>
              <xs:element type="xs:short" name="port"/>
              <xs:element type="xs:string" name="username"/>
              <xs:element type="xs:byte" name="password"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

And then work with JAXB for the purposes you have. I hope it helps you or at least can give you an idea. Best regards.

Upvotes: 1

Related Questions