📜 ⬆️ ⬇️

Building Java applications using Apache Ant, quick start

What is this article about


One of the distinguishing features of the Java platform is its independence from the tools used. You can develop an arbitrarily large Java application with Notepad (vi) and the command line. It is clear that no one does and everyone uses some kind of IDE. As a consequence of tool independence, the IDE for Java is plentiful. All this is good but there is one feature. If your colleague made an application and used IDE_A to build the project, then in IDE_B which you should have, you cannot build the application.
In general, this is no longer a problem. It is considered good practice to use an assembly system independent of the IDE. For Java, the two are Apache-Ant and Maven (also Apache in general). But there is one pitfall. If in Delphi or Visual Studio, to create and build an application you need to click on the new button to go through the steps of the wizard and click the build button, then writing an ant script to build, for example a web application, especially for a novice developer, is not a trivial task.
The article covers building and deploying Java web applications step by step.

In general, the problem can be solved with the help of ant or with the help of maven, ant will be considered here. For beginners, it is easier and clearer.


')

Why do you need an assembly script




We collect and deploy war



There are many ways to build war and there are many ways to arrange application files. The article gives one way - maybe not the best but quite good.

Project structure

Project files are placed like this.
 +---ant | | step1.ant.xml | | step2.ant.xml | | step3.ant.xml | | step4.ant.xml | | step5.ant.xml | | step6.ant.xml | | | \---env | default.properties | semenych.properties | +---lib | \---google-gson-1.4 | gson-1.4-javadoc.jar | gson-1.4-sources.jar | gson-1.4.jar | +---src | \---java | \---com | \---dataart | \---ant | \---demo | Test.java | \---web \---WEB-INF | web.xml | \---lib 

In a real project, instead of stepN.xml will be build.xml. There will be more libraries and each should be placed in a separate directory. The names of the packages give out that I work at DataArt.

Step 1: Compile

To begin, just compile all the code by connecting the GSON library. The compiled code goes to the .build directory. The name can be anything, but it is usually convenient if the directory name starts with a dot.
 <project name="step1" default="compile"> 
<target name="compile"> <mkdir dir="../.build/classes"/> <javac srcdir="../src/java" destdir="../.build/classes"> <classpath location="../lib/google-gson-1.4/gson-1.4.jar"/> </javac> </target> </project>


Step 2: improve the script

The script of step 1 is rather not flexible and a number of paths are registered there once. Let's improve it

 <project name="step2" default="compile"> <property name="dir.build" value="../.build"/> <property name="dir.classes" value="${dir.build}/classes"/> <property name="dir.src.java" value="../src/java"/> <target name="clean"> <delete dir="${dir.build}"/> </target> <target name="mkdirs"> <mkdir dir="${dir.classes}"/> </target> <target name="compile" depends="mkdirs"> <javac srcdir="${dir.src.java}" destdir="${dir.classes}"> <classpath location="../lib/google-gson-1.4/gson-1.4.jar"/> </javac> </target> </project> 


Step 3: Library Paths

Paths to libraries are written hard in the middle of the code. This is not good, we are changing.

 <project name="step3" default="compile"> <property name="dir.build" value="../.build"/> <property name="dir.classes" value="${dir.build}/classes"/> <property name="dir.src.java" value="../src/java"/> <property name="dir.lib" value="../lib"/> <path id="libs.gson"> <fileset dir="${dir.lib}/google-gson-1.4"> <include name="*.jar"/> </fileset> </path> <path id="libs.main.module"> <path refid="libs.gson"/> </path> <target name="clean"> <delete dir="${dir.build}"/> </target> <target name="mkdirs"> <mkdir dir="${dir.classes}"/> </target> <target name="compile" depends="mkdirs"> <javac srcdir="${dir.src.java}" destdir="${dir.classes}"> <classpath> <path refid="libs.main.module"/> </classpath> </javac> </target> </project> 


Step 4: Configuration Management

Configuration management is a mega technology that Walden Mathews, a seasoned American programmer, told me about. The point is this: when building, you write a timeout or path to some external directory or URL of a service to the properties file. On your local machine, it is one, on the battle server (or on a colleague’s other machine). The question is how to use the correct property values ​​and not kill each other.
 <project name="step4" default="compile"> <property name="dir.build" value="../.build"/> <property name="dir.classes" value="${dir.build}/classes"/> <property name="dir.src.java" value="../src/java"/> <property name="dir.lib" value="../lib"/> <property name="dir.env" value="./env"/> <property name="assembled.properties" value="${dir.build}/assembled.properties"/> <path id="libs.gson"> <fileset dir="${dir.lib}/google-gson-1.4"> <include name="*.jar"/> </fileset> </path> <path id="libs.main.module"> <path refid="libs.gson"/> </path> <target name="clean"> <delete dir="${dir.build}"/> </target> <target name="mkdirs"> <mkdir dir="${dir.build}"/> <mkdir dir="${dir.classes}"/> </target> <target name="init" depends="mkdirs"> <property name="env" value="${user.name}"/> <echo level="info" message="env=${env}"/> <available file="${dir.env}/${env}.properties" property="env.props.available"/> <fail unless="env.props.available" message="No such file: ${dir.env}/${env}.properties"/> <property file="${dir.env}/${env}.properties"/> <property file="${dir.env}/default.properties"/> <echoproperties destfile="${assembled.properties}"/> <filter filtersfile="${assembled.properties}"/> </target> <target name="compile" depends="init"> <javac srcdir="${dir.src.java}" destdir="${dir.classes}"> <classpath> <path refid="libs.main.module"/> </classpath> </javac> </target> </project> 


Here in target init the file with the same name as your user is read. If this is not the assembly is no further. And only then the default properties from default are read. Since the property values ​​cannot be redefined in ant, then all properties must be in default, and only those values ​​in your file differ.

default.properties

 welcome.file=default.html tomcat.service.name=tomcat6 tomcat.home=C:/bin/tomcat6 


semenych.properties

 welcome.file=index.html 


If you want to build a project with a property file whose name is different from the user’s name, write this
ant -Denv=mihalych compile

Note that the command says simply mihalych and not mihalych.properties

Step 5: Let's already build the jar and war file

Yes, really give.
 <project name="step5" default="compile"> <property name="dir.build" value="../.build"/> <property name="dir.classes" value="${dir.build}/classes"/> <property name="dir.src.java" value="../src/java"/> <property name="dir.lib" value="../lib"/> <property name="dir.env" value="./env"/> <property name="dir.war.content" value="${dir.build}/war.content"/> <property name="assembled.properties" value="${dir.build}/assembled.properties"/> <property name="file.jar" value="${dir.build}/main.module.jar"/> <property name="name.application" value="demo"/> <property name="file.war" value="${dir.build}/${name.application}.war"/> <path id="libs.gson"> <fileset dir="${dir.lib}/google-gson-1.4"> <include name="*.jar"/> </fileset> </path> <path id="libs.main.module"> <path refid="libs.gson"/> </path> <target name="clean"> <delete dir="${dir.build}"/> </target> <target name="mkdirs"> <mkdir dir="${dir.build}"/> <mkdir dir="${dir.classes}"/> <mkdir dir="${dir.war.content}"/> </target> <target name="init" depends="mkdirs"> <property name="env" value="${user.name}"/> <echo level="info" message="env=${env}"/> <available file="${dir.env}/${env}.properties" property="env.props.available"/> <fail unless="env.props.available" message="No such file: ${dir.env}/${env}.properties"/> <property file="${dir.env}/${env}.properties"/> <property file="${dir.env}/default.properties"/> <echoproperties destfile="${assembled.properties}"/> <filter filtersfile="${assembled.properties}"/> </target> <target name="compile" depends="init"> <javac srcdir="${dir.src.java}" destdir="${dir.classes}"> <classpath> <path refid="libs.main.module"/> </classpath> </javac> </target> <target name="build.jar" depends="compile"> <jar destfile="${file.jar}" basedir="${dir.classes}" compress="false" index="true"> </jar> </target> <target name="build.war.content" depends="build.jar"> <copy todir="${dir.war.content}" preservelastmodified="true" overwrite="true"> <fileset dir="../web"/> </copy> <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true"> <path refid="libs.main.module"/> </copy> <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true" file="${file.jar}"> </copy> <replace dir="${dir.war.content}/WEB-INF/" propertyfile="${assembled.properties}"> <include name="*.xml"/> <replacefilter token="@welcome.file@" property="welcome.file"/> </replace> </target> <target name="build.war" depends="build.war.content"> <delete file="${file.war}"/> <war compress="true" encoding="utf-8" warfile="${file.war}" webxml="${dir.war.content}/WEB-INF/web.xml"> <fileset dir="${dir.war.content}" excludes="WEB-INF/web.xml"/> </war> </target> </project> 


One comment:

 <replace dir="${dir.war.content}/WEB-INF/" propertyfile="${assembled.properties}"> <include name="*.xml"/> <replacefilter token="@welcome.file@" property="welcome.file"/> </replace> 


This section makes a replacement inside web.xml, while web.xml looks like this:

 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>@welcome.file@</welcome-file> </welcome-file-list> </web-app> 


Step 6: war is ready, final touch, warm up

The script will do the so-called “cold” deployment ie deploying an application with server shutdown. In some cases, the “cold” deployment allows you to avoid a number of problems associated with the release of resources and cleaning the cache.

 <project name="step6" default="compile"> <property name="dir.build" value="../.build"/> <property name="dir.classes" value="${dir.build}/classes"/> <property name="dir.src.java" value="../src/java"/> <property name="dir.lib" value="../lib"/> <property name="dir.env" value="./env"/> <property name="dir.war.content" value="${dir.build}/war.content"/> <property name="assembled.properties" value="${dir.build}/assembled.properties"/> <property name="file.jar" value="${dir.build}/main.module.jar"/> <property name="name.application" value="demo"/> <property name="file.war" value="${dir.build}/${name.application}.war"/> <path id="libs.gson"> <fileset dir="${dir.lib}/google-gson-1.4"> <include name="*.jar"/> </fileset> </path> <path id="libs.main.module"> <path refid="libs.gson"/> </path> <target name="clean"> <delete dir="${dir.build}"/> </target> <target name="mkdirs"> <mkdir dir="${dir.build}"/> <mkdir dir="${dir.classes}"/> <mkdir dir="${dir.war.content}"/> </target> <target name="init" depends="mkdirs"> <property name="env" value="${user.name}"/> <echo level="info" message="env=${env}"/> <available file="${dir.env}/${env}.properties" property="env.props.available"/> <fail unless="env.props.available" message="No such file: ${dir.env}/${env}.properties"/> <property file="${dir.env}/${env}.properties"/> <property file="${dir.env}/default.properties"/> <echoproperties destfile="${assembled.properties}"/> <filter filtersfile="${assembled.properties}"/> </target> <target name="compile" depends="init"> <javac srcdir="${dir.src.java}" destdir="${dir.classes}"> <classpath> <path refid="libs.main.module"/> </classpath> </javac> </target> <target name="build.jar" depends="compile"> <jar destfile="${file.jar}" basedir="${dir.classes}" compress="false" index="true"> </jar> </target> <target name="build.war.content" depends="build.jar"> <copy todir="${dir.war.content}" preservelastmodified="true" overwrite="true"> <fileset dir="../web"/> </copy> <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true"> <path refid="libs.main.module"/> </copy> <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true" file="${file.jar}"> </copy> <replace dir="${dir.war.content}/WEB-INF/" propertyfile="${assembled.properties}"> <include name="*.xml"/> <replacefilter token="@welcome.file@" property="welcome.file"/> </replace> </target> <target name="build.war" depends="build.war.content"> <delete file="${file.war}"/> <war compress="true" encoding="utf-8" warfile="${file.war}" webxml="${dir.war.content}/WEB-INF/web.xml"> <fileset dir="${dir.war.content}" excludes="WEB-INF/web.xml"/> </war> </target> <target name="deploy" depends="build.war,do.undeploy.war,do.deploy.war"> </target> <target name="do.undeploy.war" depends="init"> <service.stop.win32 service.name="${tomcat.service.name}"/> <delete file="${tomcat.home}/webapps/${name.application}.war" failonerror="false"/> <delete dir="${tomcat.home}/webapps/${name.application}" failonerror="false"/> </target> <target name="do.deploy.war" depends="init"> <copy todir="${tomcat.home}/webapps" failonerror="yes"> <fileset file="${file.war}"/> </copy> <service.start.win32 service.name="${tomcat.service.name}"/> </target> <!-- macro --> <macrodef name="service.stop.win32"> <attribute name="service.name"/> <sequential> <echo>Stoping service: @{service.name}</echo> <exec executable="net" outputproperty="whatsRunning"> <arg value="stop"/> <arg value="@{service.name}"/> </exec> </sequential> </macrodef> <macrodef name="service.start.win32"> <attribute name="service.name"/> <sequential> <echo>Starting service: @{service.name}</echo> <exec executable="net" failonerror="yes"> <arg value="start"/> <arg value="@{service.name}"/> </exec> </sequential> </macrodef> </project> 


Conclusion


That's all. This is an almost finished example taken from a real project. Use on health, do not forget to write comments.

Links


Source: https://habr.com/ru/post/99394/


All Articles