J2ME Polish
J2ME Polish 2.4 Documentation
Enough Software

Creating and Using Custom Preprocessing Directives

You can easily use your own preprocessing directives by extending the de.enough.polish.preprocess.CustomPreprocessor class and by integrating your preprocessor with the <preprocessor> element in the "build.xml" file.

Preparations

Create a new project in your IDE and set the classpath so that it includes the "enough-j2mepolish-build.jar", which can be found in the "import" folder of the installation directory. Also include the "ant.jar" file from your Ant-installation into the classpath.

Creating the Preprocessor Class

Create a new class which extends de.enough.polish.preprocess.CustomPreprocessor.

Using the registerDirective()-Method

The easiest way to use custom directive is by registering them with the "registerDirective"-method:

	/**
	 * Adds a directive which is searched for in the preprocessed source codes.
	 * Whenever the directive is found, the appropriate method 
	 * process[directive-name] is called.
	 * When for example the preprocessing directive "//#hello" should be processed,
	 * the subclass needs to implement the method 
	 * processHello( String line, StringList lines, String className ).
	 * <pre>
	 * registerDirective("hello");
	 * // is the same like
	 * registerDirective("//#hello");
	 * </pre> 
	 *  
	 * @param directive the preprocessing directive which should be found.
	 *        The directive needs to contain at least 2 characters (apart from
	 * 		the beginning "//#"). 
	 *		The "//#" beginning is added when not specified.
	 * @throws BuildException when the corresponding method could not be found.
	 */
	protected void registerDirective( String directive ) throws BuildException

When for example the directive "date" is registered, the public method processDate( String line, de.enough.polish.util.StringList lines, String className ) needs to be implemented.

You can make use of following protected variables:

  • de.enough.polish.preprocess.Preprocessor preprocessor: the main preprocessor
  • de.enough.polish.preprocess.BooleanEvaluator booleanEvaluator : an evaluator for complex terms which can be used in the #if-directive.

If you need further configuration settings, you can add them with the <parameter> construct, which is discussed below.

In the processing method the line in which the preprocessing directive was found is usually changed. When the line is changed, please make sure that the preprocessing-directive is removed from the changed line, so that the following preprocessing can continue without errors.

When there is an exception, abort the build by throwing a org.apache.tools.ant.BuildException explaining the details why the preprocessing was aborted.

This example should illustrate the usage of the registerDirective()-method:

package com.company.preprocess;

import org.apache.tools.ant.BuildException;
import de.enough.polish.preprocess.CustomPreprocessor;
import de.enough.polish.util.StringList;
import java.util.Date;

public class MyPreprocessor extends CustomPreprocessor {

 public MyPreprocessor() {
	super();
	registerDirective("date");
 }

 public void processDate( String line, StringList lines, String className ) {
 	int directiveStart = line.indexOf( "//#date");
	String argument = line.substring( directiveStart + "//#date".length() ).trim();
	int replacePos = argument.indexOf("${date}");
	if (replacePos == -1) {
	  throw new BuildException(className + " at line " 
		+ (lines.getCurrentIndex() + 1) 
		+ ": Unable to process #date-directive: found no ${date} sequence in line [" 
		+ line + "." );
	}
	String result = argument.substring(0, replacePos )
		+ ( new Date().toString() ) 
		+ argument.substring( replacePos + "${date}".length() );
	lines.setCurrent(result);
 }	
}

Using the processClass()-Method

For more complex situations, you can override the processClass()-method which allows you to process the whole java-file in one go:

	/**
	 * Processes the given class.
	 * 
	 * @param lines the source code of the class
	 * @param className the name of the class
	 */
	public void processClass( StringList lines, String className ) {
		while (lines.next()) {
			String line = lines.getCurrent();
			// now process the line...
		}
	}

Integrating the Preprocessor into the build.xml

You can integrate your preprocessor with the usual <preprocessor> element in the build.xml file (compare the <preprocessor> documentation).

<preprocessor 
	class="com.company.preprocess.MyPreprocessor"
	classPath="../preprocessor-project/bin/classes"
	>
	<parameter name="scriptFile" value="../scripts/preprocess.script" />
</preprocessor>

The "class"-attribute needs to be set to the new class. The classPath-attribute can be used for pointing out the location of the preprocessor. This is only needed when the preprocessor is not on the Ant-classpath.

Configuring the Preprocessor with Parameters

The preprocessor can be configured using <parameter> subelements in the build.xml. For each <parameter> a corresponding "set[parameter-name]"-method needs to be implemented, which either needs to have one File parameter, one boolean or one String parameter:

	<parameter name="scriptFile" value="../scripts/obfuscate.script" />

For the using the above parameter, the preprocessor needs to implement either the public method setScriptFile( File file ) or the public method setScriptFile( String value ). When a method with a File-parameter is used, relative file paths are resolved relative to the location of the build.xml file (or to be more precise relative to the project.getBaseDir() location). The file given as a parameter in the set-method uses an absolute path in that case.

JavaDoc Resources

Please refer to these JavaDoc resources for detailed information:

back to top