org.apache.juneau.ini.package.html Maven / Gradle / Ivy
INI file support
Table of Contents
-
-
-
-
-
-
-
1 - Overview
The {@link org.apache.juneau.ini.ConfigFileBuilder} and {@link org.apache.juneau.ini.ConfigFile} classes
implement an API for working with INI-style configuration files such as the following:
#--------------------------
# Default section
#--------------------------
key1 = 1
key2 = true
key3 = 1,2,3
key4 = http://foo
#--------------------------
# A comment about Section 1
#--------------------------
[Section1]
key1 = 2
key2 = false
key3 = 4,5,6
key4 = http://bar
The {@link org.apache.juneau.ini.ConfigFileBuilder} class is used to instantiate instances of
{@link org.apache.juneau.ini.ConfigFile} which can then be used to retrieve config file values through either
"key" or "Section/key" identifiers.
int key1;
boolean key2;
int [] key3;
URL key4;
// Get our config file using the default config manager
ConfigFile f = new ConfigFileBuilder().build("C:/temp/MyConfig.cfg" );
// Read values from default section
key1 = f.getInt("key1" );
key2 = f.getBoolean("key2" );
key3 = f.getObject(int [].class , "key3" );
key4 = f.getObject(URL.class , "key4" );
// Read values from Section #1
key1 = f.getInt("Section1/key1" );
key2 = f.getBoolean("Section1/key2" );
key3 = f.getObject(int [].class , "Section1/key3" );
key4 = f.getObject(URL.class , "Section1/key4" );
The interface also allows config files to be constructed programmatically...
// Construct the sample INI file programmatically
ConfigFile f = new ConfigFileBuilder().build("C:/temp/MyConfig.cfg" , true )
.addLines(null , // The default 'null' section
"# Default section" , // A regular comment
"key1 = 1" , // A numeric entry
"key2 = true" , // A boolean entry
"key3 = 1,2,3" , // An array entry
"key4 = http://foo" , // A POJO entry
"" ) // A blank line
.addHeaderComments("Section1" , // The 'Section1' section
"A comment about Section 1" ) // A header comment
.addLines("Section1" , // The 'Section1' section
"key1 = 2" , // A numeric entry
"key2 = false" , // A boolean entry
"key3 = 4,5,6" , // An array entry
"key4 = http://bar" ) // A POJO entry
.save(); // Save to MyConfig.cfg
The following is equivalent, except uses {@link org.apache.juneau.ini.ConfigFile#put(String,Object)} to set values.
Note how we're setting values as POJOs which will be automatically converted to strings when persisted to disk.
// Construct the sample INI file programmatically
ConfigFile f = new ConfigFileBuilder().build("C:/temp/MyConfig.cfg" , true )
.addLines(null ,
"# Default section" )
.addHeaderComments("Section1" ,
"A comment about Section 1" );
cf.put("key1" , 1);
cf.put("key2" , true );
cf.put("key3" , new int []{1,2,3});
cf.put("key4" , new URL("http://foo" ));
cf.put("Section1/key1" , 2);
cf.put("Section1/key2" , false );
cf.put("Section1/key3" , new int []{4,5,6});
cf.put("Section1/key4" , new URL("http://bar" ));
cf.save();
Refer to {@link org.apache.juneau.ini.ConfigFile#put(String,Object,boolean)} for a description of
formats for various data types.
Various convenience getter methods are provided for retrieving different data types:
// Strings with default values
// key1 = foobar
String key1 = cf.getString("key1" );
// Numbers
// key2 = 123
float key2 = cf.getObject(float .class , "key2" );
// Booleans
// key3 = true
boolean key3 = cf.getBoolean("key3" );
// Objects convertable to and from strings using the JSON serializer and parser
// key4 = http://foo
URL key4 = cf.getObject(URL.class , "key4" );
// Arrays of strings
// key5 = foo, bar
String[] key5 = cf.getStringArray("key5" );
// Arrays of objects
// key6 = http://foo,http://bar
URL[] key6 = cf.getObject(URL[].class , "key6" );
// Arrays of primitives
// key7 = 1,2,3
int [] key7 = cf.getObject(int [].class , "key7" );
// Enums
// key8 = MINUTES
TimeUnit key8 = cf.getObject(TimeUnit.class , "key8" );
// Beans
// key9 = {name:'John Smith', addresses:[{street:'101 Main St', city:'Anywhere', state:'TX'}]}
Person key9 = cf.getObject(Person.class , "key9" );
// Generic Maps
// key10 = {foo:'bar', baz:123}
Map key10 = cf.getObject(ObjectMap.class , "key10" );
2 - Variables
Config files can contain variables that get resolved dynamically using the
{@link org.apache.juneau.svl.VarResolver} API.
Resolving config files can be retrieved through the following methods:
-
{@link org.apache.juneau.ini.ConfigFile#getResolving()} - Returns a config file that resolves a default
set of variables.
-
{@link org.apache.juneau.ini.ConfigFile#getResolving(VarResolver)} - Returns a config file that resolves
a custom set of variables.
The default {@link org.apache.juneau.ini.ConfigFile#getResolving()} method returns a config file that resolves
the following variables:
-
$S{key}
, $S{key,default}
- System properties.
-
$E{key}
, $E{key,default}
- Environment variables.
-
$C{key}
, $C{key,default}
- Values in this configuration file.
Examples:
#--------------------------
# Examples
#--------------------------
[MyProperties]
javaHome = $S{java.home}
path = $E{PATH}
customMessage = Java home is $C{MyProperties/javaHome} and the environment path is $C{MyProperties/path}.
Support for variables is extensible. You can add support for your own variables by implementing custom
{@link org.apache.juneau.svl.VarResolver VarResolvers}.
For example, the microservice Resource
class provides access to config files that
can contain any of the following variables:
$C
- Config variables.
$S
- System properties.
$E
- Environment variables.
$I
- Servlet init parameters.
$ARG
- JVM command-line arguments.
$MF
- Main jar manifest file entries.
$L
- Localized strings.
$A
- HTTP request attributes.
$P
- HTTP request URL parameters.
$R
- HTTP request variables.
$UE
- URL-encoding function.
3 - Encoded Entries
If a config file contains sensitive information such as passwords, those values can be
marked for encoding by appending '*' to the end of the key name.
If a marked and unencoded value is detected in the file during load, it will be encoded and saved immediately.
For example, the following password is marked for encoding....
[MyHost]
url = http://localhost:9080/foo
user = me
password* = mypassword
After initial loading, the file contents will contain an encoded value...
[MyHost]
url = http://localhost:9080/foo
user = me
password* = {AwwJVhwUQFZEMg==}
The default encoder is {@link org.apache.juneau.ini.XorEncoder} which is a simple XOR+Base64 encoder.
If desired, custom encoder can be used by implementing the {@link org.apache.juneau.ini.Encoder}
interface and creating your own ConfigFileBuilder
using the
{@link org.apache.juneau.ini.ConfigFileBuilder#encoder(Encoder)} method.
4 - Listeners
The following method is provided for listening to changes made on config files:
{@link org.apache.juneau.ini.ConfigFile#addListener(ConfigFileListener)}.
Subclasses are provided for listening for different kinds of events:
-
{@link org.apache.juneau.ini.ConfigFileListener} - Config file is saved, loaded, or modified.
-
{@link org.apache.juneau.ini.SectionListener} - One or more entries in a section are modified.
-
{@link org.apache.juneau.ini.EntryListener} - An individual entry is modified.
Example:
// Get our config file using the default config manager
ConfigFile f = new ConfigFileBuilder().build("C:/temp/MyConfig.cfg" );
// Add a listener for an entry
f.addListener(
new EntryListener("Section1/key1" ) {
@Override
public void onChange(ConfigFile cf) {
System.err .println("Entry changed! New value is " + cf.getString("Section1/key1" ));
}
}
);
5 - Command Line API
The {@link org.apache.juneau.ini.ConfigFileBuilder} class contains a
{@link org.apache.juneau.ini.ConfigFileBuilder#main(String[])} method that can be used to work with config
files through a command-line prompt.
This is invoked as a normal Java command:
java -jar juneau.jar org.apache.juneau.ini.ConfigFileBuilder [args]
Arguments can be any of the following...
-
No arguments
Prints usage message.
-
createBatchEnvFile -configfile <configFile> -envfile <batchFile> [-verbose]
Creates a batch file that will set each config file entry as an environment variable.
Characters in the keys that are not valid as environment variable names (e.g. '/' and '.' )
will be converted to underscores.
-
createShellEnvFile -configFile <configFile> -envFile <configFile> [-verbose]
Creates a shell script that will set each config file entry as an environment variable.
Characters in the keys that are not valid as environment variable names (e.g. '/' and '.' )
will be converted to underscores.
-
setVals -configFile <configFile> -vals [var1=val1 [var2=val2...]] [-verbose]
Sets values in config files.
For example, the following command will create the file 'MyConfig.bat'
from the contents of the
file 'MyConfig.cfg'
.
java org.apache.juneau.ini.ConfigFileBuilder createBatchEnvFile -configfile C:\foo\MyConfig.cfg -batchfile C:\foo\MyConfig.bat
6 - Serializing Config Files
Instances of {@link org.apache.juneau.ini.ConfigFile} are POJOs that can be serialized to and parsed from
all supported Juneau languages.
The org.apache.juneau.microservice.resources.ConfigResource
is a predefined REST interface that
allows access to the config file used by a microservice.
The juneau-examples-rest
project is a microservice that includes this resource
at http://localhost:10000/sample/config
.
The sample microservice uses the following config file juneau-examples.cfg
:
#================================================================================
# Basic configuration file for SaaS microservices
# Subprojects can use this as a starting point.
#================================================================================
#================================================================================
# REST settings
#================================================================================
[REST]
# The HTTP port number to use.
# Default is Rest-Port setting in manifest file, or 8000.
port = 10000
# A JSON map of servlet paths to servlet classes.
# Example:
# resourceMap = {'/*':'com.foo.MyServlet'}
# Either resourceMap or resources must be specified.
resourceMap =
# A comma-delimited list of names of classes that extend from Servlet.
# Resource paths are pulled from @RestResource.path() annotation, or
# "/*" if annotation not specified.
# Example:
# resources = com.foo.MyServlet
# Default is Rest-Resources in manifest file.
# Either resourceMap or resources must be specified.
resources =
# The context root of the Jetty server.
# Default is Rest-ContextPath in manifest file, or "/".
contextPath =
# Authentication: NONE, BASIC.
authType = NONE
# The BASIC auth username.
# Default is Rest-LoginUser in manifest file.
loginUser =
# The BASIC auth password.
# Default is Rest-LoginPassword in manifest file.
loginPassword =
# The BASIC auth realm.
# Default is Rest-AuthRealm in manifest file.
authRealm =
# Stylesheet to use for HTML views.
# The default options are:
# - styles/juneau.css
# - styles/devops.css
# Other stylesheets can be referenced relative to the servlet package or working
# directory.
stylesheet = styles/devops.css
# What to do when the config file is saved.
# Possible values:
# NOTHING - Don't do anything.
# RESTART_SERVER - Restart the Jetty server.
# RESTART_SERVICE - Shutdown and exit with code '3'.
saveConfigAction = RESTART_SERVER
# Enable SSL support.
useSsl = false
#================================================================================
# Bean properties on the org.eclipse.jetty.util.ssl.SslSocketFactory class
#--------------------------------------------------------------------------------
# Ignored if REST/useSsl is false.
#================================================================================
[REST-SslContextFactory]
keyStorePath = client_keystore.jks
keyStorePassword* = {HRAaRQoT}
excludeCipherSuites = TLS_DHE.*, TLS_EDH.*
excludeProtocols = SSLv3
allowRenegotiate = false
#================================================================================
# Logger settings
# See FileHandler Java class for details.
#================================================================================
[Logging]
# The directory where to create the log file.
# Default is "."
logDir = logs
# The name of the log file to create for the main logger.
# The logDir and logFile make up the pattern that's passed to the FileHandler
# constructor.
# If value is not specified, then logging to a file will not be set up.
logFile = microservice.%g.log
# Whether to append to the existing log file or create a new one.
# Default is false.
append =
# The SimpleDateFormat format to use for dates.
# Default is "yyyy.MM.dd hh:mm:ss".
dateFormat =
# The log message format.
# The value can contain any of the following variables:
# {date} - The date, formatted per dateFormat.
# {class} - The class name.
# {method} - The method name.
# {logger} - The logger name.
# {level} - The log level name.
# {msg} - The log message.
# {threadid} - The thread ID.
# {exception} - The localized exception message.
# Default is "[{date} {level}] {msg}%n".
format =
# The maximum log file size.
# Suffixes available for numbers.
# See ConfigFile.getInt(String,int) for details.
# Default is 1M.
limit = 10M
# Max number of log files.
# Default is 1.
count = 5
# Default log levels.
# Keys are logger names.
# Values are serialized Level POJOs.
levels = { org.apache.juneau:'INFO' }
# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
# Useful for preventing log files from filling up with duplicate stack traces.
# Default is false.
useStackTraceHashes = true
# The default level for the console logger.
# Default is WARNING.
consoleLevel =
#================================================================================
# System properties
#--------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
#================================================================================
[SystemProperties]
# Configure Jetty for StdErrLog Logging
org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
# Jetty logging level
org.eclipse.jetty.LEVEL = WARN
The config file looks deceivingly simple.
However, it should be noticed that the config file is a VERY powerful feature with many capabilities including:
When you point your browser to this resource, you'll notice that the contents of the config file are being
serialized to HTML as a POJO:
Likewise, the config file can also be serialized as any of the supported languages such as JSON:
The code for implementing this page could not be any simpler, since it simply returns the config file returned
by the RestServlet.getConfig()
method.
/**
* [GET /] - Show contents of config file.
*
* @return The config file.
* @throws Exception
*/
@RestMethod (name=GET, path="/" , description="Show contents of config file." )
public ConfigFile getConfigContents() throws Exception {
return getConfig();
}
The edit page takes you to an editor that allows you to modify the contents of the config file:
This latter page uses the {@link org.apache.juneau.ini.ConfigFile#toString()} method to retrieve the
contents of the config file in INI format.
Since config files are serializable, that mean they can also be retrieved through the RestClient
API.
// Create a new REST client with JSON support
RestClient c = new RestClientBuilder().build();
// Retrieve config file through REST interface
ConfigFile cf = c.doGet("http://localhost:10000/sample/config" ).getResponse(ConfigFileImpl.class );
7 - Merging Config Files
In the previous example, an edit page was shown that allows you to edit config files through
a REST interface.
Note that if only a single entry is modified in the config file, we only want to trigger
listeners for that change, not trigger all listeners.
This is where the {@link org.apache.juneau.ini.ConfigFile#merge(ConfigFile)} method comes into play.
This method will copy the contents of one config file over to another config file, but only
trigger listeners when the values are different.
The edit page is implemented with this method which is a simple PUT with the contents of the new INI file as
the body of the HTTP request:
/**
* [PUT /] - Sets contents of config file.
*
* @param contents The new contents of the config file.
* @return The new config file contents.
* @throws Exception
*/
@RestMethod (name=PUT , path="/" ,
description="Sets contents of config file." ,
parameters={
@Parameter (in="body" , description="New contents in INI file format." )
}
)
public ConfigFile setConfigContents(@Body Reader contents) throws Exception {
// Create a new in-memory config file based on the contents of the HTTP request.
ConfigFile cf2 = new ConfigFileBuilder.build().load(contents);
// Merge the in-memory config file into the existing config file and save it.
// Then return the modified config file to be parsed as a POJO.
return getConfig().merge(cf2).save();
}