Contents
Every enterprise has its own software development practices that cover how developers update code, how changes are tracked and tested and how new releases are created. We generally expect that whatever practices have historically worked within an organization will continue to work for the implementation of this application. However, a build methodology was developed that has worked well for managing concurrent changes to the application that is based on the following principles:
· All of the application should work all of the time. Therefore, changing one small part of the application requires that all of the application be retested.
· Bugs are more expensive to fix the longer they stay in a system. This principle has been proven time and time again in software engineering. This truth mostly owes to the fact that it is easiest to find the offending developer immediately after he or she broke the system and also that developer has less recollection of how and where the system was broken as time goes by.
· In a complex system malfunctions can occur "far away" from the points of code modification. It is unreliable to expect selective retesting based on what was likely to malfunction to find the all the places of actual malfunction.
This section will characterize an approach to setting up a Build Server that might be of use to an implementing customer.
Contents
Components Of The Build Server
Setting Up the Version Control System - Perforce
A build server is a server devoted to continuously build and test the application via a long running agent process. From the developer’s point of view the process is completely automated. An open source application named CruiseControl is used for this purpose (http://cruisecontrol.sourceforge.net). By merely checking changes into the source control system, the application developer has told the build server (or just the "build" for short) all it needs to know about the change. No direct contact from developer to build server is required or allowed for that matter. This isn't to say, however, that there is little interaction between the developer and the build server. The build server is prone to get upset about changes that cause application not to work right. That is its job. And, frankly, it is not shy about complaining when it gets upset. Complaining is a nice word but "nagging" is actually more accurate; as a matter of fact our build server has a configuration value set: nag=true.
The following describes the expected way the build server will behave and how/why we should try to make it happy:
· Every 10 minutes or so (this is configurable), the build server looks for committed changes in the appropriate location in the source control system. If none are found, the build waits another 10 minutes and polls again.
· When changes are found it does the following:
· Downloads all changes
· Performs build and test. We use Maven to facilitate this (http://maven.apache.org).
· Removes all artifacts, class files and other remnants from the last build
· Runs the Artifact Generator to create all necessary artifacts
· Compiles all code
· Runs all JUnit tests
· Publishes results to a project build web site.
· If the build was unsuccessful, commonly called "broken", it sends emails to everyone who committed changes since the last successful build.
· Developers receive emails when the build is broken. These are only the developers that committed changes since the last successful build. The build is somewhat targeted in this regard, guessing that those providing new changes are by far the most likely culprits. When developers get these emails they should go to the project build web site (a link is included in the email) and inspect the problem.
· If the developer thinks the problem is his/her fault, it is customary to:
· Send a note to other developers on the list so they do not waste time on the problem
· Fix the problem, test it locally, commit changes to source control and hope the build is appeased.
· If no developer takes responsibility for the problem, some collaboration may be required. It may also require some discussion with the "build master" (see below).
· The build server continues to attempt builds per its normal polling interval. For example, if the build is broken, it will attempt to build every 10 minutes and will fail each time. With each failure it will send "nagging" emails to each developer committing changes since the last successful build -- the "nag list". As you may have guessed, this set of developers may grow as different developers commit changes while the build continues to be broken. This makes the number of "nagged" developers grow through time. Therefore, it behooves the development community to fix the build as soon as possible. More specifically, when a developer suspects in his or her heart that he or she was the one who broke the build, he or she should stop what he or she is doing and fix it. And on the next successful build, the build will stop nagging that developer and all other developers in the nag list.
Someone needs to befriend the build server. While the build server is extremely important, it can be a real pain to deal with sometimes and can require a human go-between with an established relationship to smooth things over. The industry term for this person is "build master". Despite the apparent grandness of title, this is often not a desirable job.
In addition to those who have committed changes since the last successful build, the build master is also sent the same nagging emails. This is so the build master can monitor the health of the build' and head off problems. The build master may, at his or her discretion, contact developers and speculate that said developer was the one who broke the build. Developers should not take exception for two reasons: (1) the build master is just trying to fix the build; (2) the build master has spent so much time with "the build" that making wild and unfounded accusations has become second nature.
Developers also should feel empowered to contact the build master when:
· The build log is either not specific enough about a problem or is just plain confusing.
· Some non-source "resource" needs to be added to either the runtime environment or the testing environment. This would include:
· Jar files
· Configuration files
· Data files (presumably with test data inside)
Oracle Utilities Software Development Kit
There should be a central storage source code and resources that are needed to create the application. A change to source code and/or resources done in the version control system triggers the build process.
Note. The product development team uses PerForce for version control.
CruiseControl is the application that, at certain intervals, checks for changes in the version control system. If a change is detected, it starts the build process. Otherwise, it waits for the next time interval. CruiseControl also provides a reporting application with a web interface that:
· Displays the current status of the build server
· Displays the detailed results of a particular build including the files that changed to trigger the build, the developers that made the changes, and the results for the unit tests that were performed.
· Sends the status of the build via email to the build master and the developers that made changes during that time interval.
· Re-executes the failed build at the specified time intervals and re-sends the email to developers associated with the failed build until a successful build is obtained.
Maven is the application that manages the build process. It is responsible for:
· Verifying the dependencies to build the project are available
· Setting up the build environment
· Compiling and packaging the source
· Running all the unit tests specified
· Generating an error if anything fails
The Java artifact generator is part of the install. The build server will use the artifact generator during the build.
Note. The following section describes the use of PerForce. It must be substituted with the vesion control system being used.
A client spec strictly for the build server use should be created. The Perforce client spec maps the Perforce depot structure to the local workstation directory structure by specifying views in the client spec. The easiest way is to map the entire app server structure to a particular local directory.
For example, to create a client spec that maps a Perforce depot //SPL/CM_PROJ1/… to the C:\SPL\CM_PROJ1 of the local workstation, the following steps should be performed:
· Select ClientSpec à New from the Perforce Windows client menu
· Update the client spec Root to be C:\SPL
· Add the line //SPL/CM_PROJ1/… // myClientSpec /SPL/CM_PROJ1/... to the Views section of the client spec editor
· Add the line //SPL/CM_PROJ1/splapp/applications/root/WEB-INF/lib/… //myClientSpec/SPL/CM_PROJ1/build/repository/cm-dep/jars/… to the Views section of the client spec editor
The last line is necessary for Maven. Maven uses a concept of a repository to store all the Java libraries is will use to satisfy dependencies. Since all the libraries needed are in the app server WEB-INF/lib directory, this should be mapped to the repository Maven will use. It will be assumed that the build server will perform the build process in a build directory. For the purpose of this document, the build directory will be specified under C:\SPL\CCB_PROJ1\build directory.
· Add the following lines to the Views section of the client spec editor
//SPL/CM_PROJ1/runtime/... //SPL/CM_PROJ1/build/runtime/...
//SPL/CM_PROJ1/runtime/CM*.dll //SPL/CM_PROJ1/runtime/CM*.dll
Contents
CruiseControl uses an XML configuration file to customize its behavior. Refer to the CruiseControl website for the detailed description of the configuration file. A sample configuration file for version 2.5 is provided below. Any value starting with “my” should be replaced with the appropriate value for that environment. The important elements are highlighted below:
· threads – specifies the number of concurrent builds that can occur. If more than one project, set this to the number of projects.
· P4Bootstrapper – specifies what needs to be synced before a build is run through the view attribute.
· Modificationset – specifies what changes will trigger a build through the view attribute.
· interval – specifies the time interval between builds in seconds.
· maven – specifies that the build will use Maven. The mavenscript attribute specifies the file to launch. This file should contain any environment specific environment settings, as well a launch maven. The config file below specifies maven_20X.bat will be used.
· log – specifies the logs for the test. Maven automatically puts it in the target/test-reports directory. This will be used to display the test results on the status page.
· email – specifies how email notification will be sent. The map attribute maps the Perforce user name to a valid email address for that user.
CruiseControl comes with a reporting application that displays the status/results of builds. To use the reporting application, the following steps must be performed:
· Install and configure a web server such as Tomcat.
· Add a context path to the server.xml that points to the CruiseControl reporting application. For example:
<Context path="" docBase="c:\myCruiseControlDir\webapps\cruisecontrol" debug="0"/>
· Modify the web.xml file in c:\myCruiseControlDir\webapps\cruisecontrol\WEB-INF to update the param value of the logDir parameter.
<param-name>logDir</param-name>
<param-value> c:/myCruiseControlDir/logs</param-value>
Contents
There are environment variables that need to be set prior to launching Maven. This is accomplished by creating a script that sets the necessary environment variables and then launches Maven. This script is what is specified in the mavenscript attribute of the CruiseControl config.xml file above. The script should contain the following lines:
set PATH=c:\spl\CM_PROJ1\runtime\;%PATH%
set COBSW=(+S5)
call c:\myMavenDir\bin\maven.bat %*
The project file contains information about the project. It is here that dependencies for compilation are specified, how the application is packaged, and how the unit tests will be performed. See below for contents and the Maven home page for a detailed description.
The maven.xml file contains the actions to perform or goals to achieve to build the project. When Maven is launched and a goal is passed in as a parameter, it will look in the maven.xml for that goal and execute any directives in that goal. See below for contents and the Maven home page for a detailed description.
The project.properties allows for specifying properties that can be used in the maven.xml and the project.xml files. This allows for a central place to specify file paths for simpler updates. It also allows for overriding any built-in properties set by Maven.
Below is a working example for setting up a build server.
In the working example, the 2.0.5 release of CC&B is shown which is based on SDK 2.0.10. Some changes are necessary to tailor this example to the actual application and release desired. The following items can be changed to reflect the specific project:
· Product being customized. In this example, it is Oracle Utilities Customer Care and Billing.
· Project name. In this example, it is CCB_205_101.
· Oracle Utilities Software Development Kit version. In this example, it is 2.0.10.0.
· Source Code Control System. In this example, it is PerForce.
It assumes the following directory structure:
where
BuildServer – contains the build server files
spl – contains the appserver installation
SPLSDK – contains the SDK installation
The corresponding Perforce structure is as follows:
It is assumed that the test source files are in C:\spl\CCB_205_101\java\source\cm\test and the test properties file are in C:\spl\CCB_205_101\java\source\cm\test\properties.
Steps to perform:
1) Download CruiseControl 2.5 and extract to C:\BuildServer directory
2) Download Maven 1.0.2 and extract to C:\BuildServer directory
3) Create a directory for the reporting application in the C:\BuildServer\project_web_site
4) Download Tomcat 4 and extract into the C:\BuildServer\project_web_site directory
5) Download Java 2 SDK and extract into the C:\BuildServer\project_web_site directory
6) Copy the reporting app from C:\BuildServer\cruisecontrol-2.5\webapps\cruisecontrol to the C:\BuildServer\project_web_site\project_content
7) In the C:\BuildServer\maven-1.0.2\bin directory, create a batch file that will launch Maven called cmMaven.bat with the following contents:
set PATH=C:\spl\CCB_205_101\runtime;%PATH%
set COBSW=(+S5)
set MAVEN_HOME=C:\BuildServer\maven-1.0.2
set BUILD_DIR=C:\spl\CCB_205_101\build
cd /d %BUILD_DIR%
call %MAVEN_HOME%\bin\maven.bat %*
8) In the C:\BuildServer\ cruisecontrol-2.5 directory, create a batch file that will launch CruiseControl called cmCruiseControl.bat with the following contents:
SET JAVA_HOME=C:\Program Files\Java\jdk1.5.0_10
cd /d C:\BuildServer\cruisecontrol-2.5
call cruisecontrol.bat -projectname cmbuild -configfile config.xml
9) Create a file called C:\BuildServer\ cruisecontrol-2.5\config.xml with the following contents:
<cruisecontrol>
<system>
<configuration>
<threads count="1"/>
</configuration>
</system>
<project name="cmbuild">
<listeners>
<currentbuildstatuslistener file="logs/cmbuild/status.txt"/>
</listeners>
<bootstrappers>
<P4Bootstrapper p4port="SF-PDNT-006:1686" client="CMClientSpec" p4user="fjocson" path="//SDK/..." />
</bootstrappers>
<modificationset requiremodification="true">
<!-- trigger a build for any code change -->
<P4 port="SF-PDNT-006:1686" client="CMClientSpec" user="fjocson" view="//SDK/..." />
</modificationset>
<schedule interval="240">
<!-- Schedule the regular build -->
<maven mavenscript="C:/BuildServer/maven-1.0.2/bin/cmMaven.bat"
projectfile="C:/BuildServer/maven-1.0.2/bin/project.xml"
goal="cmBuild"
multiple="1" />
</schedule>
<log encoding="UTF-8">
<merge dir="c:/spl/CCB_205_101/build/cm/target/test-reports" />
</log>
<publishers>
<email mailhost="sf-smtp1.splwg.com"
returnname="CM Project Build Server"
returnaddress="CMBuildServer@splwg.com"
defaultsuffix="@splwg.com"
buildresultsurl="http://localhost:20230/index.jsp">
<!--always address="buildmasters" /-->
<!--failure address="developers" reportWhenFixed="true" /-->
<failure address="buildmasters" reportWhenFixed="true" />
<map alias="buildmasters" address="fjocson@splwg.com" />
<!-- Map perforce usernames to email names -->
<map alias="fjocson" address="fjocson@splwg.com" />
</email>
</publishers>
</project>
</cruisecontrol>
10) Modify the file C:\BuildServer\project_web_site\tomcatBase\conf\server.xml to add the line:
<Context path="" docBase="C:\BuildServer\project_web_site\project_content" debug="0"/>
11) Modify the file C:\BuildServer\project_web_site\project_content\WEB-INF\web.xml to add the lines:
<param-name>logDir</param-name>
<param-value>logs</param-value>
to
<param-name>logDir</param-name>
<param-value>C:/BuildServer/CruiseControl-2.5/logs</param-value>
12) Create a file called C:\spl\CCB_205_101\build\project.xml with the following contents:
<?xml version="1.0"?>
<project>
<name>CM Dev</name>
<groupId>cm</groupId>
<id>cm</id>
<currentVersion>SNAPSHOT</currentVersion>
<package>com.splwg.cm</package>
<shortDescription>CM Java Development</shortDescription>
<description>CM Java Development</description>
<dependencies>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>spl-ccb</artifactId>
<jar>spl-ccb-2.0.5.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>spl-shared</artifactId>
<jar>spl-shared-2.0.10.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>spl-base</artifactId>
<jar>spl-base-2.0.10.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>spl-charter</artifactId>
<jar>spl-charter-2.0.10.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>commons-lang</artifactId>
<jar>commons-lang-2.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>hibernate</artifactId>
<jar>hibernate-3.0.5.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>log4j</artifactId>
<jar>log4j-1.2.11.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>picocontainer</artifactId>
<jar>picocontainer-1.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>dom4j</artifactId>
<jar>dom4j-1.6.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>commons-collections</artifactId>
<jar>commons-collections-2.1.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>xstream</artifactId>
<jar>xstream-1.1.2.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>cglib</artifactId>
<jar>cglib-2.1.3.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>asm-attrs</artifactId>
<jar>asm-attrs-1.5.3.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>asm</artifactId>
<jar>asm-1.5.3.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>icu4j</artifactId>
<jar>icu4j-3.4.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>commons-logging</artifactId>
<jar>commons-logging-1.0.4.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>c3p0</artifactId>
<jar>c3p0-0.9.0.4.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>ehcache</artifactId>
<jar>ehcache-1.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>commons-beanutils</artifactId>
<jar>commons-beanutils-1.6.1.jar</jar>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>concurrent</artifactId>
<version>1.3.4</version>
</dependency>
<dependency>
<groupId>cm-dep</groupId>
<artifactId>commons-httpclient</artifactId>
<jar>commons-httpclient-2.0.2.jar</jar>
</dependency>
</dependencies>
<build>
<sourceDirectory>
${build.dir}/source/java
</sourceDirectory>
<unitTestSourceDirectory>
${build.dir}/source/test
</unitTestSourceDirectory>
<resources>
<resource>
<directory>${build.dir}/source/java/com/splwg/cm/domain</directory>
<targetPath>com/splwg/cm/domain</targetPath>
<includes>
<include>**/contextManagedObjects.xml</include>
</includes>
</resource>
<resource>
<directory>${spl.build.root.dir}/source/java/com/splwg/cm/domain</directory>
<targetPath>com/splwg/cm/domain</targetPath>
<includes>
<include>**/packageMetaInfo.xml</include>
</includes>
</resource>
<resource>
<directory>${spl.build.root.dir}/source/java/com/splwg/cm/cobol</directory>
<targetPath>com/splwg/cm/cobol</targetPath>
<includes>
<include>**/packageMetaInfo.xml</include>
</includes>
</resource>
<resource>
<directory>${spl.build.root.dir}/source/java/com/splwg</directory>
<targetPath>com/splwg</targetPath>
<includes>
<include>**/*.hbm.xml</include>
</includes>
</resource>
<resource>
<directory>${spl.build.root.dir}/source/java/com/splwg</directory>
<targetPath>com/splwg</targetPath>
<includes>
<include>**/*.info.xml</include>
</includes>
</resource>
<!-- service mapping files -->
<resource>
<directory>${spl.build.root.dir}/source/java/services</directory>
<targetPath>services</targetPath>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/java/cobolServices</directory>
<targetPath>cobolServices</targetPath>
<includes>
<include>*.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/java/com/splwg/cm</directory>
<targetPath>com/splwg/cm</targetPath>
<includes>
<include>dbregex.txt</include>
</includes>
</resource>
</resources>
<unitTest>
<includes>
<include>com/splwg/AllTests.java</include>
</includes>
<resources>
<resource>
<directory>${build.dir}/source/test/com/splwg/cm/domain</directory>
<targetPath>com/splwg/cm/domain</targetPath>
<includes>
<include>**/contextManagedObjects.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/test/com/splwg/cm/domain</directory>
<targetPath>com/splwg/cm/domain</targetPath>
<includes>
<include>**/packageMetaInfo.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/test/com/splwg/cm/cobol</directory>
<targetPath>com/splwg/cm/cobol</targetPath>
<includes>
<include>**/packageMetaInfo.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/test/com/splwg</directory>
<targetPath>com/splwg</targetPath>
<includes>
<include>**/*.hbm.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/test/com/splwg</directory>
<targetPath>com/splwg</targetPath>
<includes>
<include>**/*.info.xml</include>
</includes>
</resource>
<!-- service mapping files -->
<resource>
<directory>${build.dir}/source/test/com/splwg/cm/services</directory>
<targetPath>services</targetPath>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/source/test/cobolServices</directory>
<targetPath>cobolServices</targetPath>
<includes>
<include>*.xml</include>
</includes>
</resource>
<resource>
<directory>${build.dir}/TestProperties</directory>
<includes>
<include>hibernate.properties</include>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</unitTest>
</build>
</project>
13) Create a file called C:\spl\CCB_205_101\build\maven.xml with the following contents:
<project
default="reactor-exec"
xmlns:ant="jelly:ant"
xmlns:j="jelly:core"
xmlns:u="jelly:util"
xmlns:maven="jelly:maven">
<goal name="cmBuild">
<echo message="Copying source files to build location for CM project"/>
<attainGoal name="refresh-build-dir" />
<!-- Generate and compile -->
<attainGoal name="cmGenerate" />
<attainGoal name="jar:jar" />
<copy todir="${build.dir}/repository/cm/jars" >
<fileset dir="${build.dir}/target">
<include name="*.jar"/>
</fileset>
</copy>
<!--Copy files for appserver refresh -->
<attainGoal name="save-files" />
</goal>
<goal name="refresh-build-dir">
<echo message="Refreshing build directory for project CM" />
<echo message="Source root directory is ${java.source.dir}" />
<delete dir="${build.dir}/source" />
<delete dir="${build.dir}/target" />
<!-- Copy over the "java" directories -->
<copy todir="${build.dir}/source/java" >
<fileset dir="${java.source.dir}" />
</copy>
<!-- Copy over the "test" directories -->
<copy todir="${build.dir}/source/test" failonerror="false" >
<fileset dir="${java.source.dir}/test" />
</copy>
<!-- Copy over the properties -->
<copy todir="${build.dir}/properties"
file="${web.root.dir}/WEB-INF/classes/hibernate.properties" overwrite="true" failonerror="false" />
<copy todir="${build.dir}/properties"
file="${web.root.dir}/WEB-INF/classes/log4j.properties" overwrite="true" failonerror="false" />
<copy todir="${build.dir}/properties"
file="${web.root.dir}/WEB-INF/classes/spl.properties" overwrite="true" failonerror="false" />
<!-- Copy over the Test properties -->
<!-- Copy over the Test properties -->
<copy todir="${build.dir}/TestProperties"
file="${java.source.dir}/test/properties/hibernate.properties" overwrite="true" failonerror="false" />
<copy todir="${build.dir}/TestProperties"
file="${java.source.dir}/test/properties/log4j.properties" overwrite="true" failonerror="false" />
<copy todir="${build.dir}/TestProperties"
file="${java.source.dir}/test/properties/spl.properties" overwrite="true" failonerror="false" />
<!-- Refresh the Cobol Runtime files -->
<delete dir="${build.dir}/runtime"/>
<copy todir="${build.dir}/runtime" preservelastmodified="true" >
<fileset dir="${dev.root.dir}/runtime ">
<include name="cm*.dll"/>
<include name="CM*.dll"/>
</fileset>
</copy>
</goal>
<goal name="cmGenerate">
<!-- Generate the classes -->
<property name="generated.artifact.dir"
value="${build.dir}/source/java"/>
<echo message="Generated artifact directory is ${generated.artifact.dir}" />
<java classname="com.splwg.tools.artifactgen.ArtifactGenerator" fork="true" failonerror="true" maxmemory="512m">
<arg line="-appDirs ${generated.artifact.dir} -appJars ${build.dir}/repository/cm-dep/jars/spl-base-2.0.10.jar ${build.dir}/repository/cm-dep/jars/spl-ccb-2.0.5.jar" />
<classpath>
<pathelement path="${build.dir}/properties" />
<fileset dir="${build.dir}/repository/cm-dep/jars">
<include name="*.jar"/>
</fileset>
<fileset dir="${dev.root.dir}/SPLSDKCommon/tools">
<include name="*.jar"/>
</fileset>
</classpath>
<sysproperty key="spl.tools.artifact.manual.sourcedir" value="${generated.artifact.dir}"/>
<sysproperty key="spl.tools.artifact.cobol.sourcedir" value="${dev.root.dir}/cobol/source"/>
<sysproperty key="spl.tools.artifact.generated.sourcedir" value="${generated.artifact.dir}"/>
<sysproperty key="spl.tools.loaded.applications" value="base,ccb,cm"/>
<sysproperty key="log4j.logger.com.splwg" value="info"/>
<sysproperty key="log4j.logger.org.hibernate.cfg" value="warn"/>
<sysproperty key="log4j.logger.org.hibernate.util" value="warn"/>
<sysproperty key="log4j.logger.com.splwg.tools.artifactgen.LookupGenerator" value="warn"/>
<sysproperty key="log4j.logger.com.splwg.tools.artifactgen.sourceparser.JavaSourceProcessor" value="warn"/>
</java>
</goal>
<goal name="save-files">
<echo message="Deleting previous saved files..." />
<!-- Put a marker that files are in the process of being saved -->
<!-- so the appserver refresh won't try to refresh -->
<copy file="${dev.root.dir}/etc/SPLVERSION.txt" tofile="${build.dir}/~saving_files"/>
<delete dir="${build.dir}/saved" />
<echo message="Saving files from successful build..." />
<!-- Copy over the root directory -->
<copy todir="${build.dir}/saved/root/cm">
<fileset dir="${web.root.dir}/cm" />
</copy>
<copy todir="${build.dir}/saved/lib" >
<fileset dir="${build.dir}/repository/cm/jars" />
</copy>
<!-- Copy over the dlls -->
<copy todir="${build.dir}/saved/runtime" >
<fileset dir="${build.dir}/runtime">
<include name="CM*.dll" />
<include name="cm*.dll" />
</fileset>
</copy>
<delete file="${build.dir}/~saving_files"/>
</goal>
</project>
14) Create a properties file in the build directory called C:\spl\CCB_205_101\build\project.properties with the following contents:
# The top level directories
dev.root.dir=c:/spl/CCB_205_101
build.dir=${dev.root.dir}/build
java.source.dir=${dev.root.dir}/java/source/cm
web.root.dir=${dev.root.dir}/splapp/applications/root
## Properties used during the build process
maven.pmd.cpd.enable=true
## JUnit testing properties
log4j.logger.com.splwg=info
log4j.logger.org.hibernate.cfg=warn
log4j.logger.org.hibernate.util=warn
log4j.logger.com.splwg.base.context.ApplicationContextImpl=warn
log4j.logger.com.splwg.base.context.PicoComponentContainer=warn
maven.junit.sysproperties=spl.tools.loaded.applications log4j.logger.com.splwg log4j.logger.org.hibernate.cfg log4j.logger.org.hibernate.util log4j.logger.com.splwg.base.context.ApplicationContextImpl log4j.logger.com.splwg.base.context.PicoComponentContainer
maven.junit.jvmargs=-Xms128m -Xmx512m -XX:MaxPermSize=512m
# Define the set of applications to be loaded
spl.tools.loaded.applications=base,ccb
## These "built-in" maven properties need to be here because the property inheritance of this type is broken in maven 1.0.1
## Should be fixed in 1.0.2 (hopefully).
##maven.repo.remote.enabled = false
maven.site.deploy.method = fs
maven.repo.local = ${build.dir}/repository
maven.junit.fork = true
maven.jar.override = on
15) Create script to start Tomcat for the build status website by creating a file called C:\BuildServer\project_web_site\starttcat.bat with the following contents:
REM This script calls the tomcat startup script in tomcathome\bin.
set SITE_BASE=C:\BuildServer\project_web_site
set JAVA_HOME=%SITE_BASE%\j2sdk1.4.2_11
set JAVA_OPTS=-Xms384m -Xmx384m
set CATALINA_BASE=%SITE_BASE%\tomcatBase
set CATALINA_HOME=%SITE_BASE%\tomcatHome\jakarta-tomcat-4.1.29
pushd %CATALINA_HOME%\bin
call startup.bat
popd
:endofbat
16) Create script to stop Tomcat for the build status website by creating a file called C:\BuildServer\project_web_site\stoptcat.bat with the following contents:
@REM This script calls the tomcat shutdown script in tomcathome\bin.
set SITE_BASE=C:\BuildServer\project_web_site
set JAVA_HOME=%SITE_BASE%\j2sdk1.4.2_11
set JAVA_OPTS=-Xms384m -Xmx384m
set CATALINA_BASE=%SITE_BASE%\tomcatBase
set CATALINA_HOME=%SITE_BASE%\tomcatHome\jakarta-tomcat-4.1.29
if not exist %SITE_BASE%\tomcatHome\jakarta-tomcat-4.1.29\bin echo Unable to find directory %SITE_BASE%\tomcatHome\jakarta-tomcat-4.1.29\bin.&&pause&&goto endofbat
pushd %SITE_BASE%\tomcatHome\jakarta-tomcat-4.1.29\bin
call shutdown.bat
popd
:endofbat
17) Create a Perforce client spec named CMClientSpec for this example. The Root should be c:\spl and has the following view defined:
//SDK/2.0.10/AppSvrs/CCB_205_101/... //CMClientSpec/CCB_205_101/...
18) Start the build status website by executing the file C:\BuildServer\project_web_site\starttcat.bat
19) Start CruiseControl by executing the file C:\BuildServer\ cruisecontrol-2.5\cmCruiseControl.bat. Once it completes, the console should state that is waiting for the next time to build:
20) Once the build finishes in the CruiseControl console, view the build status by opening a web browser to http://localhost:20230. The following status page should be displayed:
21) If successful, the resulting cm jar file can be found at c:\spl\CCB_205_101\build\target\cm-SNAPSHOT.jar.
Contents
Application Server Refresh Scripts
Application Server Refresh Procedure
The following scripts must be created for Application Server Refresh, substitute Name/Version(xxx) according to the requirement. The scripts copies the build files from the build server to the shared app server.
Contents
· Create a file called setupEnv2xx.cmd in //C1CM/2.x.0/V2xx_CCB_CM_WIN_TC_ORA/SPLSDKCommon with the following contents:
set JAVA_HOME=C:\jdk\jdk1.5.0_10
set ORACLE_HOME=C:\oracle\oracle10203
set CATALINA_HOME=C:\tomcat\apache-tomcat-5.5.20
set COBDIR=C:\Program Files\Micro Focus\Net Express 5.0\Base
set C3P0_JAR_DIR=C:\c3p0\c3p00904\lib
set HIBERNATE_JAR_DIR=C:\hibernate\hib313
· Create a file called setAppserverEnv.bat in //C1CM/2.x.x/V2xx_CCB_CM_WIN_TC_ORA/bin with the following contents:
SET MOD=V2xx_CM_DEMO_DEV_WIN_TC_ORA
SET BUILDSERVER_MAP=U:\%MOD%
SET DEVDIR=C:\splcm\%MOD%
SET BINDIR=%DEVDIR%\bin
SET SPLAPPDIR=%DEVDIR%\splapp\applications
SET ANT_HOME=C:\splcm\V2xx_CM_DEMO_DEV_WIN_TC_ORA\product\apache-ant-1.6.3
SET TOMCAT_VER=5.5.20
SET TOMCAT_PORT=7300
SET DEBUG_PORT=7301
SET ENV_TITLE= Sanity Check for %MOD% %DB_TYPE% %TOMCAT_PORT%
SET PATH=%DEVDIR%\runtime;%PATH%
set ONLINEBILLINI=%DEVDIR%\ect\billdirfile.ini
set ONLINEDOCINI=%DEVDIR%\etc\doc1dirfile.ini
· Create a file called AppServerRefresh.bat in //C1CM/2.x.x/V2xx_CCB_CM_WIN_TC_ORA/bin with the following contents:
@echo off
rem Setup the Environment Variable for AppServer
rem call setAppserverEnv.bat
rem Setup the Environment Variables for V2xx_CM_DEMO_DEV_WIN_TC_ORA
rem cd /d %DEVDIR%\SPLSDKCommon
rem call setupEnv2xx.cmd
rem Execute splenviron
rem cd /d %BINDIR%
rem cmd /k "call splenviron.cmd -e V2xx_CM_DEMO_DEV_WIN_TC_ORA"
if not exist %BUILDSERVER_MAP% goto map_error
if not exist %SPLAPPDIR% goto app_error
cd /d %SPLAPPDIR%
call %ANT_HOME%\bin\ant.bat -l %SPLAPPDIR%\log.txt
goto end
:map_error
echo Error: Could not find build server path %BUILDSERVER_MAP%
goto end
:app_error
echo Error: App server path %SPLAPPDIR% not found
goto end
:end
· Create a file called build.xml in //C1CM/2.x.x/V2xx_CCB_CM_WIN_TC_ORA/ splapp/applications with the following contents:
<?xml version="1.0" encoding="UTF-8" ?>
<project name="AppserverRefresh" default="refreshAppserver" basedir=".">
<property name="spl.tcat.port" value="7300"/>
<property name="spl.tcat.version" value="tomcatBase-5.5.20"/>
<property name="spl.build.saved.dir" location="U:/V2xx_CM_DEMO_DEV_WIN_TC_ORA/build/saved"/>
<property name="spl.base.dir" location="C:/splcm/V2xx_CM_DEMO_DEV_WIN_TC_ORA"/>
<property name="spl.bin.dir" location="${spl.base.dir}/bin"/>
<property name="spl.splapp.dir" location="${spl.base.dir}/splapp"/>
<property name="spl.splapp.applications.dir" location="${spl.splapp.dir}/applications/"/>
<property name="spl.root.dir" location="${spl.splapp.applications.dir}/root"/>
<property name="spl.runtime.dir" location="${spl.base.dir}/runtime"/>
<property name="spl.standalone.lib.dir" location="${spl.splapp.dir}/standalone/lib"/>
<property name="spl.root.web-inf.lib.dir" location="${spl.root.dir}/WEB-INF/lib"/>
<property name="spl.xai.web-inf.lib.dir" location="${spl.splapp.applications.dir}/XAIApp/WEB-INF/lib"/>
<target name="deployXAI" depends="deploy" >
<echo message="Copying CM appserver jar file to ${spl.xai.web-inf.lib.dir}..."/>
<copy todir="${spl.xai.web-inf.lib.dir}">
<fileset dir="${spl.build.saved.dir}\lib">
<include name="cm*.jar" />
</fileset>
</copy>
</target>
<target name="starttomcat" depends="deployXAI">
<echo message="Starting Tomcat..."/>
<property name="host" value="localhost"/>
<property name="port" value="${spl.tcat.port}"/>
<property name="server.url" value="http://${host}:${port}"/>
<exec dir="${spl.bin.dir}" executable="cmd.exe" spawn="true">
<arg line="/c spl.cmd start" />
</exec>
<waitfor maxwait="180" maxwaitunit="second" timeoutproperty="server.is.unavailable">
<http url="${server.url}"/>
</waitfor>
<fail if="server.is.unavailable" message="Ant was unable to start the server..."/>
<echo message="Finished App Server Refresh..."/>
</target>
<target name="deploy" depends="CheckSavedDir">
<tstamp>
<format property="TODAY" pattern="MM/dd/yy HH:mm"/>
</tstamp>
<echo message="Starting refresh on ${TODAY}"/>
<fail unless="saved.dir.exist" message="No saved directory exist. Not refreshing..."/>
<fail if="saving.files.in.progress" message="Build server save files in progress. Not refreshing..."/>
<echo message="Shutting down MPL..."/>
<exec dir="${spl.splapp.dir}/mpl" executable="cmd.exe" spawn="true">
<arg line="/c stopMPL.cmd" />
</exec>
<echo message="Waiting 30 seconds while MPL shutsdown..."/>
<sleep seconds="30"/>
<echo message="Shutting down Tomcat..."/>
<exec dir="${spl.bin.dir}" executable="cmd.exe" spawn="true">
<arg line="/c spl.cmd stop" />
</exec>
<echo message="Waiting 120 seconds while Tomcat shutsdown..."/>
<sleep seconds="120"/>
<echo message="Refreshing appserver ..."/>
<echo message="Deleting CM appserver root directory ${spl.root.dir}\cm"/>
<delete dir="${spl.root.dir}\cm"/>
<echo message="Deleting CM appserver root directory ${spl.root.dir}\c1\cm"/>
<delete dir="${spl.root.dir}\c1\cm"/>
<echo message="Deleting CM appserver dlls in ${spl.runtime.dir}"/>
<delete>
<fileset dir="${spl.runtime.dir}">
<include name="cm*.dll"/>
<include name="CM*.dll"/>
</fileset>
</delete>
<echo message="Deleting CM appserver jars in ${spl.standalone.lib.dir}"/>
<delete>
<fileset dir="${spl.standalone.lib.dir}">
<include name="cm*.jar"/>
</fileset>
</delete>
<echo message="Deleting CM appserver jars in ${spl.root.web-inf.lib.dir}"/>
<delete>
<fileset dir="${spl.root.web-inf.lib.dir}">
<include name="cm*.jar"/>
</fileset>
</delete>
<echo message="Deleting CM appserver jars in ${spl.xai.web-inf.lib.dir}"/>
<delete>
<fileset dir="${spl.xai.web-inf.lib.dir}">
<include name="cm*.jar"/>
</fileset>
</delete>
<echo message="Create the build saved directory if it doesn't exist ${spl.build.saved.dir}\root\cm..."/>
<mkdir dir="${spl.build.saved.dir}\root\cm"/>
<echo message="Copying CM appserver files to ${spl.root.dir}..."/>
<copy todir="${spl.root.dir}\cm">
<fileset dir="${spl.build.saved.dir}\root\cm" />
</copy>
<echo message="Copying CM appserver dlls to ${spl.runtime.dir}"/>
<copy todir="${spl.runtime.dir}">
<fileset dir="${spl.build.saved.dir}\runtime">
<include name="CM*.dll" />
<include name="cm*.dll" />
</fileset>
</copy>
<echo message="Copying CM appserver jar file to ${spl.standalone.lib.dir}..."/>
<copy todir="${spl.standalone.lib.dir}">
<fileset dir="${spl.build.saved.dir}\lib">
<include name="cm*.jar" />
</fileset>
</copy>
<echo message="Copying CM appserver jar file to ${spl.root.web-inf.lib.dir}..."/>
<copy todir="${spl.root.web-inf.lib.dir}">
<fileset dir="${spl.build.saved.dir}\lib">
<include name="cm*.jar" />
</fileset>
</copy>
</target>
<target name="refreshAppserver" depends="starttomcat"/>
<target name="CheckSavedDir">
<echo message="Checking if saved directory exist..."/>
<condition property="saved.dir.exist">
<available file="${spl.build.saved.dir}" type="dir"/>
</condition>
<echo message="Checking if build server is in the process of saving files..."/>
<condition property="saving.files.in.progress">
<available file="${spl.build.root.dir}\~saving_files" type="file"/>
</condition>
</target>
</project>
· Share the Appserver installation root directory in the Build Server and give full access.
· From the Application Server, Map the root directory of the Build Server’s appserver installation.
· In a Command prompt, execute setupEnv2xx.cmd in C:\splcm\V2xx_CM_DEMO_DEV_WIN_TC_ORA\SPLSDKCommon.
· Execute setAppServerRefresh.bat in C:\splcm\V2xx_CM_DEMO_DEV_WIN_TC_ORA\bin
· In the command prompt, execute splenviron –e V2xx_CM_DEMO_DEV_WIN_TC_ORA.
· Execute AppServerRefresh.bat in C:\splcm\V2xx_CM_DEMO_DEV_WIN_TC_ORA\bin.
Windows Scheduler can be used to schedule daily app server refresh.