Overview

   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.

Main Features

  1. 100% Ant, 100% Java Properties– information manipulated as objects not text.
  2. Preserves structure including whitespace and comments so that `diff` shows only edits.
  3. Has a full suite of property operations: insert, delete, test, replace, [un]comment, copy, diff.
  4. Can read local or remote properties sources using any URL format your Ant runtime supports.
  5. Supports editing in place with auto-backup on load and auto-save per edit.
  6. Supports ‘bulk’ or set versions of operations using standard Ant filter chains and mappers.
  7. Support properties in both standard format as well as the newer XML format (JRE 1.5+).
  8. Supports Ant filter chains on properties load to transform incoming keys and values with ease.
  9. Works the same on both transient in-memory content or externally sourced content.
  10. Lets you create custom Ant <propertyset> data from processed property file contents.

Component Summary

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 memoryIn progress.
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.

Quick Start Examples

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 (In progress) 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.

Installing PEd4Ant Antlib

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:

Creating New Properties

• 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"/>

Loading Existing 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: In progress 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>

Editing Properties (inserts)

• 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>

Editing Properties (deletes)

• 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>

Editing Properties (updates)

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>

Editing Properties (toggles)

• 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>

Saving Edited Properties

• 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"/>

Finding Changed Properties

• 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:

  • Added new property ‘env.strict.list’
  • Changed old property ‘env.name’
  • Changed old property ‘env.version’
  • Added new property ‘reports.layouts.default’
  • Removed old property ‘layouts.default’


• 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"
 }
]

Copying Loaded Properties

• 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"/>

Testing Loaded Properties

This example checks whether a set of properties, masked as comments, exist in a loaded Properties object “myconf”.

1: <ped:testproperties under="myconf"
2:      like="^${env}\.throttle\..*" selector="comments"
3:      trueproperty="throttle.enabled"/>

Navigation
Personal Tools