package rabbitescape.engine.config; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.SortedSet; import rabbitescape.engine.err.RabbitEscapeException; import rabbitescape.engine.util.FileSystem; /** * Don't use this directly - wrap it in a Config object. * * Stores and retrieves config values to/from a file. */ public class ConfigFile implements IConfigStorage { public static class UnableToLoad extends RabbitEscapeException { private static final long serialVersionUID = 1L; public final String filePath; public UnableToLoad( String filePath, Exception cause ) { super( cause ); this.filePath = filePath; } } public static class UnableToSave extends RabbitEscapeException { private static final long serialVersionUID = 1L; public final String filePath; public UnableToSave( String filePath, Exception cause ) { super( cause ); this.filePath = filePath; } } private final Map<String, String> values; private final FileSystem fs; private final String filePath; public ConfigFile( FileSystem fs, String filePath ) { this.fs = fs; this.filePath = filePath; this.values = new HashMap<>(); load(); } private void load() { if ( fs == null || filePath == null || !fs.exists( filePath ) ) { return; } Properties props = new Properties(); try { props.load( new ByteArrayInputStream( fs.read( filePath ).getBytes() ) ); } catch ( Exception e ) { throw new UnableToLoad( filePath, e ); } for ( String name : props.stringPropertyNames() ) { set( name, props.getProperty( name ) ); } } @Override public void set( String key, String value ) { values.put( key, value ); } @Override public String get( String key ) { return values.get( key ); } @Override public void save( Config config ) { try { fs.mkdirs( fs.parent( filePath ) ); fs.write( filePath, saveToString( config ) ); } catch ( IOException e ) { throw new UnableToSave( filePath, e ); } } private String saveToString( Config config ) { StringBuilder ret = new StringBuilder(); // Tree set for sorting SortedSet<String> keys = config.keys(); boolean first = true; for ( String key : keys ) { if ( first ) { first = false; } else { ret.append( "\n" ); } ret.append( "# " ); ret.append( config.schema.getDescription( key ) ); ret.append( "\n" ); if ( ! values.containsKey( key ) ) { ret.append( '#' ); } ret.append( propertyLine( config, key ) ); ret.append( "\n" ); } return ret.toString(); } private String propertyLine( Config config, String key ) { Properties props = new Properties(); props.setProperty( key, config.get( key ) ); StringWriter writer = new StringWriter(); try { props.store( writer, null ); } catch ( IOException e ) { // Should never happen throw new RuntimeException( e ); } return writer.toString().split( "\n" )[1]; } }