IniProperties.java

/***************************************************************************
   Copyright 2008 Emily Estes

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***************************************************************************/
package net.metanotion.util;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/** This class loads "sectioned" INI files with an API similar to the {@link java.util.Properties}.
The files loaded by this file have sections denoted with square brackets and key/value assignments made by "=". The top
level of the file is loaded into the section named ""(i.e. empty string). Comments start with a "#" and continue to the
end of the line. This class is not thread safe. Here's an example:<br />
<code>key1 = value<br />
anotherKey=1235<br />
[section heading]<br/>
thisKey=1<br/>
foo="bar"<br/>
# this is a comment</br/>
[anotherSection]<br />
baz="a string with quotes around it for the value"<br/></code>
*/
public final class IniProperties {
	private final Map<String,Map<String,String>> map = new HashMap<>();

	/** Look up a property from the default section("").
		@param key The property to look up.
		@return The value of the property.
	*/
	public String getProperty(final String key) { return getProperty(key, ""); }

	/** Look up a property from a section.
		@param key The property to look up.
		@param section The name of the section to get the property from.
		@return The value of the property.
	*/
	public String getProperty(final String key, final String section) {
		final Map<String,String> sec = map.get(section);
		if(sec == null) { return null; }
		return sec.get(key);
	}


	/** Get a list of the sections.
		@return The list of the sections in this instance.
	*/
	public Iterator<String> sections() { return map.keySet().iterator(); }

	/** Get a list of the keys in a section.
		@param section The name of the section to list the keys.
		@return The list of the sections in this instance.
	*/
	public Iterator<String> keys(final String section) { return map.get(section).keySet().iterator(); }

	/** Read an INI file into this instance.
		@param in The INI file to read.
		@throws IOException if there is a problem reading the file.
		@return The instance of INI Properties,
	*/
	public IniProperties load(final Reader in) throws IOException {
		final BufferedReader lines = new BufferedReader(in);
		String line;
		Map<String,String> sec = map.get("");
		if(sec == null) {
			sec = new HashMap<>();
			map.put("", sec);
		}
		while((line = lines.readLine()) != null) {
			line = line.trim();
			if((line.length() > 2) && (line.startsWith("[")) && (line.endsWith("]"))) {
				final String section = line.substring(1, line.length() - 1);
				sec = new HashMap<>();
				map.put(section, sec);
			} else {
				final String[] justKV = line.split("#", 2)[0].trim().split("=", 2);
				final String key = (justKV.length > 0) ? justKV[0].trim() : null;
				final String val = (justKV.length > 1) ? justKV[1].trim() : null;
				sec.put(key, val);
			}
		}
		return this;
	}
}