JWare/AntXtras Properties Editor for Ant (PEd4Ant) is a collection of components for creating and manipulating standard Java properties files from within Ant script. If you need to do lots of custom properties manipulation, while preserving the original source as much as possible, you will find PEd4Ant very useful.
To use PEd4Ant you just load its antlib into your Ant runtime. PEd4Ant depends on the standard Ant and AntXtras libraries only. The recommended namespace URI and prefix for PEd4Ant is “jwaresoftware.ped4ant” and “ped:” respectively. Read the “Loading PEd4Ant antlib” instructions for additional information.
The recommended namespace prefix for PEd4Ant is “ped:”; this prefix is assumed in our table below. If you’re a developer looking to extend or use PEd4Ant in your own Ant components, you will find additional implementation details in the PEd4Ant Javadoc API reference.
| Task/Type | General Description |
|---|---|
| ped:makeproperties | Lets you create a new Properties object in memory. |
| ped:loadproperties | Lets you load a pre-existing Properties source into memory. |
| ped:mergeloadproperties | Lets you load-and-merge multiple pre-existing Properties sources into memory . |
| ped:editproperties | Lets you performs a multitude of operations on loaded Properties. |
| ped:readproperties | Lets you copy in-memory Properties to Ant fixture or other Properties. |
| ped:saveproperties | Lets you save in-memory Properties to a file. |
| ped:diffproperties | Lets you capture differences between two Properties as objects (not text). |
| ped:testproperties | Lets you apply a test condition to a Properties’ contents or keys. |
All PEd4Ant manipulation operations require that you either create a new memory-based Properties object or load one from an external source. The following examples show you how to manipulate a Properties object created from scratch or loaded from an external definition file (standard or XML). Once you’re done with your edits you can: save the in-memory object back to a file, create some other Ant data structure like a property set or other resource collection, or apply the properties into the current Ant fixture so you can use them like regular Ant properties via ‘${…}’ semantics.
Not all of the features described below were available in the initial beta release of PEd4Ant with AntXtras v2; however, all of these components and operations exist in the latest PEd4Ant 1.0.0 release that works with AntXtras v3. Any example that describes future functionality is marked with an “in progress” icon (
) at its start. You can read the Release Notes for the list of features implemented in the latest distribution and then the Future Plans for the general PEd4Ant release schedule.
You can install the PEd4Ant extension directly into your <ANT_HOME>/lib directory or more typically into its own location. This example assumes the latter case: it loads the PEd4Ant antlib into the Ant runtime from a location defined by the ‘PED4ANT_HOME’ property and then links its components to the “ped:” namespace prefix.
1: <project name="example" xmlns:ped="jwaresoftware.ped4ant"…> 2: <property name="PED4ANT_HOME" value="..."/> 3: … 4: <taskdef uri="jwaresoftware.ped4ant" 5: resource="org/jwaresoftware/ped4ant/antlib.xml"> 6: <classpath> 7: <fileset dir="${PED4ANT_HOME}" 8: includes="lib/*.jar"/> 9: </classpath> 10: </taskdef> 11: …
• Example: creates a new empty Properties object “myconf” in memory, overwriting unconditionally any object currently stored with that id. After creation, the new object is ready to accept key-value data from other PEd4Ant commands.
1: <ped:makeproperties under="myconf"/>
• Example: creates a new empty Properties object “myconf” that is automatically linked to a file ‘autogen.properties’ for saving. Note that the file not created until the first actual call to save the “myconf” object:
1: <ped:makeproperties under="myconf" 2: filelink="${my.d}/autogen.properties"/>
• Example: creates a new Properties object “myconf” that is automatically pre-filled with some inlined property values including comments. You can also seed a new Properties object from a standard Ant <propertyset>, or a <string> resources collection, or an AntXtras <properties> object.
1: <ped:makeproperties under="myconf"> 2: <string value="#TOP-OF-FILE (created:${$iso:})"/> 3: <string value="my-key=my-value"/> 4: <string value="#END-OF-FILE"/> 5: </ped:makeproperties>
• Example: creates a new Properties object “runconf” that is pre-filled with a subset of properties in the current Ant fixture (properties starting with “test.”). The new Properties is also automatically linked to an output file for auto-save operations after more editing.
1: <propertyset id="testproperties"> 2: <property prefix="test."/> 3: </propertyset> 4: … 5: <ped:makeproperties under="runconf" from="testproperties" 6: filelink="${run.d}/run.properties"/>
• Example: loads a new Properties object “myconf” from an existing external source, in this case a local file ‘template.properties’. Note that the file is not backed up, so any subsequent saves will overwrite the original file.
1: <ped:loadproperties under="myconf" 2: file="${my.d}/template.properties"/>
• Example: loads a new Properties object “myconf” from an existing external source that is using the standard XML format for Java Properties. If you want to load an XML formatted source that does not use the standard “.xml” extension set the ‘format=xml’ parameter explicitly.
1: <ped:loadproperties under="myconf" 2: file="${my.d}/template.xml"/>
• Example: loads a new Properties object “myconf” from information stored at remote location ‘${my.url}’ and saves a local baseline file version ‘original.properties’ with which we can create a patch file after editing the in-memory copy.
1: <ped:loadproperties under="myconf" 2: url="${my.url}/template.properties" 3: backup="${tmp.d}/original.properties"/>
• Example: loads a new readonly Properties object “myconf” from information stored at location ‘${my.properties}’. No edits of any kind will be allowed to the memory based “myconf” data.
1: <ped:loadproperties under="myconf" 2: file="${my.properties}" readonly="yes"/>
• Example: loads a new Properties object “myconf” from a information stored at remote location ‘${my.url}’ then replaces all ‘${…}’ value references with their current runtime values (including properties defined within the loaded Properties source itself). The ‘baseline=off’ parameter tells PEd4Ant not to consider the initial in-memory copy as a baseline, aka pristine, copy of the original source.
1: <ped:loadproperties under="myconf" 2: url="${my.url}/template.properties" baseline="off" 3: expandpropertyrefs="yes"/>
• Example: loads a new Properties object “myconf” from a local file but does some pre-processing of the file's contents before storing it to memory. In particular, we remove all blank and comment lines and load only items whose keys begin with “deploy.”. Note that the PEd4Ant’s load tasks support all standard Ant filter readers and token filters when loading a Properties object.
1: <ped:loadproperties under="myconf" 2: file="${my.d}/build.properties" baseline="off"> 3: <filterchain> 4: <striplinecomments> 5: <comment value="#"/> 6: <comment value="!"/> 7: </striplinecomments> 8: <tokenfilter> 9: <ignoreblank/> 10: </tokenfilter> 11: <linecontainsregexp> 12: <regexp pattern="^deploy\."/> 13: </linecontainsregexp> 14: </filterchain> 15: </ped:loadproperties>
• Example: creates a new Properties object “myconf” by loading a combination of three other local files into memory. Note that the loading of the files is part of the filtering process; additional filters are not applied to each loaded file (see next example).
1: <ped:loadproperties under="myconf" 2: file="${my.d}/empty.properties" baseline="off"> 3: <filterchain> 4: <concatfilter append="${conf.d}/defaults.properties"/> 5: <concatfilter append="${conf.d}/${deploy.env}.properties"/> 6: <concatfilter append="${conf.d}/fixed.properties"/> 7: </filterchain> 8: </ped:loadproperties>
• Example:
two ways to create and merge load a series of files into a single in-memory Properties object “myconf”. Note that the order in which source files are loaded, depends on how you define your inclusion criteria. For an ordered sequence of local files you can use a <filelist>; otherwise, you can use any filesystem based Ant resource set like a <fileset>, <zipresource>, or <tarresource>. You can even include remote sources by using the standard Ant <url> resource. Also, if you do a merged load of multiple sources, any filtering is applied to each source’s contents before it is merged; this differs from how filters are applied if the merging is done via filters too (previous examples).
1: <ped:mergeloadproperties under="myconf"> <ped:mergeloadproperties under="myconf"> 2: <filelist dir="${conf.d}"> <file file="${conf.d}/defaults.properties"/> 3: <file name="defaults.properties"/> <javaresource name="conf/${env}.properties"/> 4: <file name="${deploy.env}.properties"/> <url url="${my.url}/company.properties"/> 5: <file name="fixed.properties"/> </ped:mergeloadproperties> 6: </filelist> 7: </ped:mergeloadproperties>
• Example: appends a set of new properties into an existing Properties object “myconf” using the <insert> action. You can insert comments, blank lines, empty values (value is the empty string), regular single key-value pairs, or property sets (sorted-by-key or unsorted).
1: <ped:editproperties under="myconf"> 2: <insert value="#A comment goes here..."/> 3: <insert key="a-key" value="its-value"/> 4: <insert properties="refid-properties" ordering="key"/> 5: <insert properties="refid-other-properties"/> 6: <insert key="key.with.empty.value"/> 7: </ped:editproperties>
• Example: appends a blank line to an existing Properties object “myconf”.
1: <ped:editproperties under="myconf"> 2: <insert/> 3: </ped:editproperties>
• Example: inserts a line into an existing Properties object “myconf” before a specific comment line by using the ‘before’ parameter. The new comment, that contains a dynamically generated time stamp, will be inserted just before the comment line that equals “#EOF”.
1: <ped:editproperties under="myconf"> 2: <insert value="#Deployed on: ${DATETIME}" before="#EOF"/> 3: </ped:editproperties>
• Example: inserts a line with a value that can itself contain quotes or restricted XML or special Ant characters. The line’s contents will be encoded according to the standard Java Properties specification (ISO 8859 and unicode escaping).
1: <ped:editproperties under="myconf"> 2: <insert key="arguments"> 3: <value><![CDATA[this includes <xml> and other ${special} values]]></value> 4: </insert> 5: <insert key="synopsis"> 6: <value>${$loadfile:synopsis.txt}</value> 7: </insert> 8: </ped:editproperties>
• Example: removes a set of properties from an existing Properties object “myconf”. You can remove a single property by key or by value, or you can remove a set of properties based on some key or value selecting regular expression. You can even remove specific comments if needed. If you do not specify the ‘selector’ parameter, PEd4Ant assumes the operation applies to the properties’ keys.
1: <ped:editproperties under="myconf"> 2: <remove like="^disabled\..*"/> 3: <remove equals="@@FIXME@@" selector="values"/> 4: <remove key="java.naming.factory.initial"/> 5: <remove like="^#INSTR:.*$" selector="comments"/> 6: </ped:editproperties>
• Example: removes all blank lines from an existing Properties object “myconf”. You cannot use the generic value match for blank lines (e.g. like=“^$”) as that would also match empty-valued properties.
1: <ped:editproperties under="myconf"> 2: <remove blanks="yes"/> 3: </ped:editproperties>
• Example: removes all lines from an existing Properties object “myconf”. Note that this can be different from removing all keys from a properties definition as it also removes all comment lines and blanks lines.
1: <ped:editproperties under="myconf"> 2: <clear/> 3: </ped:editproperties>
The update operations are the main workhorses for the PEd4Ant package. You can change existing property keys, values, and comments in a variety of ways.
• Example: updates the value of the ‘version’ property in an existing Properties object “myconf”. The property's value is replaced unconditionally with the new value and if the key does not exist, update does nothing; it will not insert a new key.
1: <ped:editproperties under="my.conf"> 2: <update key="version" value="${build.version}"/> 3: </ped:editproperties>
• Example: updates the value of the ‘notice’ item with text that contains quotes or restricted XML or special Ant characters. The line’s contents will be encoded according to the standard Java Properties specification (ISO 8859 and unicode escaping).
1: <ped:editproperties under="my.conf"> 2: <update key="notice"> 3: <value><![CDATA[Illegal characters include "<>${}![]&#.""]]></value> 4: </update> 5: </ped:editproperties>
• Example: updates all properties that have a value that equals “FIXXME” to instead have the value “UNRESOLVED!”.
1: <ped:editproperties under="my.conf"> 2: <update equals="FIXXME" selector="values" value="UNRESOLVED!"/> 3: </ped:editproperties>
• Example: updates the property with the key ‘version’ to use a totally different key; the property’s value is left as-is.
1: <ped:editproperties under="my.conf"> 2: <update like="^version$" selector="key" replace="${environ}.version"/> 3: </ped:editproperties>
• Example: updates all properties whose values are in a custom property selector format (like “@a:propertyname”) with the current value of that property in the Ant runtime. If the property does not exist in the current Ant fixture, the script replaces the property selector with the value “UNRESOLVED!”.
1: <ped:editproperties under="my.conf"> 2: <update like="^\@a\:(.*)" selector="values" 3: replace="%{$property:\1?UNRESOLVED!}"/> 4: </ped:editproperties>
• Example: flips two sets of specific properties (disable one set by prefixing key with “disabled.” and enable other set by dropping environment specific prefix) using the shortcut rename update. Because renaming keys is such a common use for the general update operation, PEd4ant supplies a predefined variant <rename> for this common use.
1: <ped:editproperties under="my.conf"> 2: <rename like="^throttle\.(.*)" to="disabled.throttle.\1"/> 3: <rename like="^${env}\.throttle\.(.*)" to="throttle.\1"/> 4: </ped:editproperties>
• Example: uncomments a set of specific properties masked as a comments. All of the comments that begin with the expanded value of the ‘if.${env}.’ string will be uncommented and become active properties without the ‘if.${env}.’ part.
1: <ped:editproperties under="myconf"> 2: <enable like="^if\.${env}\.(.*)" replace="\1"/> 3: </ped:editproperties>
• Example: comments out any property whose key begins with ‘java.naming’. The <toggle> operation can flip a value on or off; but in this instance, because we select only keys (i.e. non-comments), the toggle acts as a comment or disable request.
1: <ped:editproperties under="myconf"> 2: <toggle like="^java\.naming\." selector="key"/> 3: </ped:editproperties>
• Example: saves a file-sourced Properties object “myconf” if there have been any changes to the original loaded information (from within Ant). The file is actually rewritten only if there was an actual change to the properties.
1: <ped:saveproperties under="myconf"/>
• Example: saves a file-sourced Properties object “myconf” unconditionally. The file is always re-written even if there have been no changes since the properties where loaded or if the file has changed on the file system.
1: <ped:saveproperties under="myconf" when="always"/>
• Example: saves a memory-sourced Properties object “myconf” to a local file “run.properties”. Because in-memory properties are not automatically linked to a source file, you must supply the target output file for each save (a file is not linked by the save operation).
1: <ped:makeproperties under="myconf"/> 2: [edit edit…] 3: <ped:saveproperties under="myconf" tofile="${out.d}/run.properties"/> 4: [edit edit…] 5: <ped:saveproperties under="myconf" tofile="${out.d}/run.properties"/>
• Example: saves an existing Properties object “myconf” to a new (different) file with a custom header and timestamp. This save operation does not change the file to which the loaded properties is linked (its source file).
1: <ped:loadproperties under="myconf" 2: file="${ini.d}/test.properties,in"/> 3: [edit edit…] 4: <ped:saveproperties under="myconf" 5: header="Generated by build process. Do NOT edit." 6: datetime="$isodatetime:" 7: tofile="${out.d}/test.properties"/>
• Example: immediately saves results of a set of edit operations to an existing file-sourced Properties object “myconf” back to the original file.
1: <ped:editproperties under="myconf" save="yes"> 2: [edit actions here…] 3: </ped:editproperties>
• Example: saves a copy of the Properties object under “myconf” to a different file that uses the JRE5 XML properties format. Note that any comments and blank lines are omitted in the output to the new file because these are not supported in the standard JRE functions.
1: <ped:loadproperties under="myconf" 2: file="${ini.d}/test.properties,in"/> 3: [edit edit…] 4: <ped:saveproperties under="myconf" 5: tofile="${out.d}/test.conf" 6: format="xml"/>
• Example: sets a property “something.changed” if the two named in-memory Properties objects contain different property sets. Note that the comparison does not consider non-property items like blanks, comments, and declaration order!
1: <ped:diffproperties source="production" target="newrelease" 2: format="none" diffproperty="something.changed"/>
• Example: displays the differences between two in-memory Properties objects as simple (aka brief) edit instructions. Only property names along with shorthand operation indicators are shown on Ant console.
1: <ped:diffproperties source="production" target="newrelease" 2: format="brief"/>
Output sent to Ant console might look like:
+ p: env.strict.list ~ p: env.name ~ p: env.version + p: reports.layouts.default - p: layouts.default
Which means to get from “production” to “newrelease” the following changes were done:
• Example: captures the differences between two in-memory Properties objects as a set of JSON formatted edit instructions including old, new, and updated values as well as property names.
1: <ped:diffproperties source="production" target="newrelease" 2: format="json" tofile="${logs.d}/changed-properties.json"/>
Output sent to “changed-properties.json” file might look like (just a snippet):
[
{"op": "+",
"type": "p",
"name": "env.strict.list",
"+": "CAT,PUB,BAK"
},
{"op": "~",
"type": "p",
"name": "env.name",
"-": "PROD",
"+": "PUB"
},
{"op": "-",
"type": "p",
"name": "layouts.default",
"-": "excel-strict"
}
]
• Example: copies all properties in the Properties object “myconf” that begin with ‘project.’ to the current Ant fixture as regular properties. Before copying, the item’s key is stripped of the prefix so something like “project.label” becomes just “label”.
1: <ped:readproperties under="myconf"> 2: <select like="^project\..*" to="ant.project"> 3: <keymapper type="glob" from="project.*" to="*"/> 4: </select> 5: </ped:readproperties>
• Example: copies all properties that begin with ‘throttle.conf.’ to an existing properties set and all properties that begin with ‘test.conf.’ to another properties set. The properties are copied as-is without modification. If any throttle properties were copied the property ‘throttle.edited’ is created and set to “true”.
1: <ped:readproperties under="myconf"> 2: <select like="^throttle\.conf\..*" 3: to="throttle.properties" 4: hitproperty="throttle.edited"/> 5: <select like="^test\.conf\..*" 6: to="test.properties" 7: hitproperty="testdata.edited"/> 8: </ped:readproperties>
• Example: reviews a set of configuration Property files defined by the “conf.files” fileset to see if there are any unresolved property values (identified by ‘${’ anywhere in value) or missing property values (identified by marker values like ‘FIXXME’ or ‘TODO’). The result of the checks are reported in another file “broken.properties” also constructed using PEd4Ant components.
1: <ped:makeproperties under="badd.conf" haltifexists="yes" 2: filelink="${logs.d}/broken.properties"/> 3: 4: <doforeach i="conf.loc" files="conf.files" tryeach="yes"> 5: <isolate> 6: <ped:loadproperties under="next.conf" file="${conf.loc}"/> 7: <ped:editproperties under="badd.conf"> 8: <insert value="FILE: ${conf.loc}"/> 9: </ped:editproperties> 10: <ped:readproperties under="next.conf" hitproperty="badd.found"> 11: <select like="(FIXXME|TODO)" selector="value" to="badd.conf"> 12: <keymapper type="glob" from="*" to="badd_*"/> 13: </select> 14: <select like="\$\{" selector="value" to="badd.conf"> 15: <keymapper type="glob" from="*" to="badd_*"/> 16: </select> 17: </ped:readproperties> 18: <unassign reference="next.conf"/> 19: <show if="badd.found" level="warning" 20: message="!! Missing properties found in ${conf.loc}"/> 21: </isolate> 22: </doforeach> 23: 24: <ped:saveproperties under="badd.conf" 25: header="BROKEN CONFIGURATION REPORT" 26: datetime="$isodatetime:"/> 27: 28: <unassign reference="badd.conf"/>