/** * Copyright (c) 2007-2011, JAGaToo Project Group all rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.jagatoo.util.ini; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jagatoo.util.errorhandling.ParsingException; import org.jagatoo.util.io.FileUtils; /** * Read-only interface to an ini file. * * @author Marvin Froehlich (aka Qudus) */ public class IniFile { private final Map<String, Map<String, String>> settings = new HashMap<String, Map<String, String>>(); private final List<String> groupsOrder = new ArrayList<String>(); private final Map<String, List<String>> settingsOrder = new HashMap<String, List<String>>(); public static final boolean DEFAULT_CASE_SENSITIVITY = true; private final File file; private final boolean caseSensitivity; private long lastModified = -1L; private void addGroup( String group ) { if ( caseSensitivity ) { settings.put( group, new HashMap<String, String>() ); groupsOrder.add( group ); settingsOrder.put( group, new ArrayList<String>() ); } else { String groupLC = ( group == null ) ? null : group.toLowerCase(); settings.put( groupLC, new HashMap<String, String>() ); groupsOrder.add( group ); settingsOrder.put( groupLC, new ArrayList<String>() ); } } private void parse() throws IOException, ParsingException { new AbstractIniParser() { @Override protected boolean onGroupParsed( int lineNr, String group ) throws ParsingException { addGroup( group ); return ( true ); } @Override protected boolean onSettingParsed( int lineNr, String group, String key, String value, String comment ) throws ParsingException { if ( ( group == null ) && !settingsOrder.containsKey( null ) ) { addGroup( group ); } if ( caseSensitivity ) { settings.get( group ).put( key, value ); settingsOrder.get( group ).add( key ); } else { String groupLC = ( group == null ) ? null : group.toLowerCase(); settings.get( groupLC ).put( key.toLowerCase(), value ); settingsOrder.get( groupLC ).add( key ); } return ( true ); } }.parse( file ); } /** * Checks, if the ini file has bee modified since the last refresh and updates in case. * * @return whether a refresh as necessary. * * @throws IOException * @throws ParsingException */ public boolean refresh() throws IOException, ParsingException { if ( !file.exists() ) throw new FileNotFoundException( file.getAbsolutePath() ); if ( lastModified != file.lastModified() ) { lastModified = file.lastModified(); settings.clear(); groupsOrder.clear(); settingsOrder.clear(); parse(); return ( true ); } return ( false ); } /** * Gets the settings's value for the given group and key. * * @param group * @param key * * @return the settings's value for the given group and key or <code>null</code>, if not found. */ public final boolean settingExists( String group, String key ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); Map<String, String> map = settings.get( group_ ); if ( map == null ) return ( false ); return ( map.containsKey( caseSensitivity ? key : key.toLowerCase() ) ); } /** * Gets the settings's value for the given group and key. * * @param group * @param key * @param defaultValue the value to be returned, if the settings does not exist * * @return the settings's value for the given group and key or 'defaultValue', if not found. */ public final String getSetting( String group, String key, String defaultValue ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); Map<String, String> map = settings.get( group_ ); if ( map == null ) return ( defaultValue ); String value = map.get( caseSensitivity ? key : key.toLowerCase() ); if ( value == null ) return ( defaultValue ); return ( value ); } /** * Gets the settings's value for the given group and key. * * @param group * @param key * * @return the settings's value for the given group and key or <code>null</code>, if not found. */ public final String getSetting( String group, String key ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); Map<String, String> map = settings.get( group_ ); if ( map == null ) return ( null ); return ( map.get( caseSensitivity ? key : key.toLowerCase() ) ); } /** * Gets the number of groups. * * @return the number of groups. */ public final int getNumGroups() { return ( groupsOrder.size() ); } /** * Gets the index'th group name. * * @param index * * @return the index'th group name. */ public final String getGroup( int index ) { return ( groupsOrder.get( index ) ); } /** * Gets an unmodifiable list of the group names. * * @return an unmodifiable list of the group names. */ public final List<String> getGroups() { return ( Collections.unmodifiableList( groupsOrder ) ); } /** * Gets the number of settings in the given group. * If the given group does not exist, -1 is returned. * * @param group * * @return the number of settings in the given group or -1. */ public final int getNumSettings( String group ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); List<String> list = settingsOrder.get( group_ ); if ( list == null ) return ( -1 ); return ( list.size() ); } /** * Gets the index'th setting key in the passed group. * * @param group * @param index * * @return the index'th setting key in the passed group. */ public final String getKey( String group, int index ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); List<String> list = settingsOrder.get( group_ ); if ( list == null ) return ( null ); return ( list.get( index ) ); } /** * Gets an unmodifiable list of the key names. * * @param group * * @return an unmodifiable list of the key names. */ public final List<String> getKeys( String group ) { String group_ = ( group == null ) ? null : ( caseSensitivity ? group : group.toLowerCase() ); List<String> list = settingsOrder.get( group_ ); if ( list == null ) return ( null ); return ( Collections.unmodifiableList( list ) ); } /** * Creates a new ini file interface. The constructor doesn't call the {@link #refresh()} method. * * @param file * @param caseSensitivity */ public IniFile( File file, boolean caseSensitivity ) { if ( file == null ) throw new IllegalArgumentException( "file must not be null." ); this.file = file; this.caseSensitivity = caseSensitivity; } /** * Creates a new ini file interface. The constructor doesn't call the {@link #refresh()} method. * * @param filename * @param caseSensitivity */ public IniFile( String filename, boolean caseSensitivity ) { this( FileUtils.getCanonicalFile( new File( filename ) ), caseSensitivity ); } /** * Creates a new ini file interface. The constructor doesn't call the {@link #refresh()} method. * * @param file */ public IniFile( File file ) { this( file, DEFAULT_CASE_SENSITIVITY ); } /** * Creates a new ini file interface. The constructor doesn't call the {@link #refresh()} method. * * @param filename */ public IniFile( String filename ) { this( filename, DEFAULT_CASE_SENSITIVITY ); } }