Ant Macros

Macros are a very slick way to consolidate, simplify, and configure your ANT scripts. For example, if your running a bunch of targets that executes sql queries. Your code could look something like this.

Without Macros (build.xml)

<project default="test">
	<extension-point name="DB.Install.1.0.0.Baseline" />

	<target name="DB.Install.1.0.0.Baseline.Clean" extensionOf="DB.Install.1.0.0.Baseline">
		<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installer}" userid="postgres" password="" autocommit="true"><![CDATA[
			DROP DATABASE IF EXISTS ${DB.Database};
			DROP ROLE IF EXISTS ${DB.Username};
		]]></sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Users" extensionOf="DB.Install.1.0.0.Baseline">
		<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installer}" userid="postgres" password="" autocommit="true"><![CDATA[
			CREATE ROLE ${DB.Username} WITH PASSWORD '${DB.Password}' LOGIN;
		]]></sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Database" extensionOf="DB.Install.1.0.0.Baseline">
		<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installer}" userid="postgres" password="" autocommit="true"><![CDATA[
			CREATE DATABASE ${DB.Database} WITH OWNER ${DB.Username};
		]]></sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Schemas" extensionOf="DB.Install.1.0.0.Baseline">
		<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installee}" userid="postgres" password="" autocommit="true"><![CDATA[
			CREATE SCHEMA ${DB.Schema};
			ALTER SCHEMA ${DB.Schema} OWNER TO ${DB.Username};
			COMMENT ON SCHEMA ${DB.Schema} IS 'My Cool Database Schema';
		]]></sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Tables" extensionOf="DB.Install.1.0.0.Baseline">
		<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installee}" userid="postgres" password="">
			<transaction src="tables.sql"/>
		</sql>
	</target>
<project>

Lots of redundant configurables being used

  • This means if you ever decide to change how you run queries you’ll need to modify each one of these calls to reflect the change
  • This also adds lots of bulk/waste code

Here is a example of how macros can help clean up your code.

With Macros (macros.xml)

<project>
	<!-- ============= -->
	<!-- = My Macros = -->
	<!-- ============= -->
	<macrodef name="run-sql-file">
		<attribute name="file"/>
		<attribute name="delimiter" default=";"/>
		<sequential>
			<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installee}" userid="postgres" password="" delimiter="@{delimiter}">
				<transaction><![CDATA[SET search_path = ${DB.Schema};]]></transaction>
				<transaction src="@{file}"/>
			</sql>
		</sequential>
	</macrodef>

	<macrodef name="run-sql">
		<text name="query"/>
   		<attribute name="transaction" default="false"/>
		<sequential>
			<if>
				<equals arg1="@{transaction}" arg2="true" />
				<then>
					<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installee}" userid="postgres" password="">
						<transaction><![CDATA[SET search_path = ${DB.Schema};]]></transaction>
						<transaction>@{query}</transaction>
					</sql>
				</then>
				<else>
					<sql driver="${JDBC.Driver}" url="${JDBC.URL.Installee}" userid="postgres" password="" autocommit="true">
						<transaction>@{query}</transaction>
					</sql>
				</else>
			</if>
		</sequential>
	</macrodef>
</project>

With Macros (build.xml)

<project default="test">
	<!-- ====================== -->
	<!-- = Include The Macros = -->
	<!-- ====================== -->
	<include file="macros.xml"/>

	<extension-point name="DB.Install.1.0.0.Baseline" />

	<target name="DB.Install.1.0.0.Baseline.Clean" extensionOf="DB.Install.1.0.0.Baseline">
		<run-sql><![CDATA[
			DROP DATABASE IF EXISTS ${DB.Database};
			DROP ROLE IF EXISTS ${DB.Username};
		]]></run-sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Users" extensionOf="DB.Install.1.0.0.Baseline">
		<run-sql><![CDATA[
			CREATE ROLE ${DB.Username} WITH PASSWORD '${DB.Password}' LOGIN;
		]]></run-sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Database" extensionOf="DB.Install.1.0.0.Baseline">
		<run-sql><![CDATA[
			CREATE DATABASE ${DB.Database} WITH OWNER ${DB.Username};
		]]></run-sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Schemas" extensionOf="DB.Install.1.0.0.Baseline">
		<run-sql transaction="false"><![CDATA[
			CREATE SCHEMA ${DB.Schema};
			ALTER SCHEMA ${DB.Schema} OWNER TO ${DB.Username};
			COMMENT ON SCHEMA ${DB.Schema} IS 'Cool Database Database Scheme';
		]]></run-sql>
	</target>

	<target name="DB.Install.1.0.0.Baseline.Tables" extensionOf="DB.Install.1.0.0.Baseline">
		<run-sql-file file="tables.sql" />
	</target>
<project>

Now if we ever want to change how we run our queries, we just modify our macros and all our code is updated. Also in large scale projects, this simplifies the code and shrinks it pretty dramatically.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s