Cmobilecom AF 5.19 Developer Guide

4 Project Build

A Cmobilecom AF project consists of a number of module projects using gradle multi-project build. Directory structure:

appRootDir/
	build.properties

	conf/
		META-INF/persistence.xml
		system-config.xml

	web/
		build.gradle
		setting.gradle
		app/
			build.gradle
	
	module1/
	module2/

	install
		bundle/
		seed/
			seed.xml
			sites/

	resources
		bundle/

	test/
		src/
		test-automation/webdriver/

	proguard.conf
	LICENSE.txt
	NOTICE.txt
	RELEASE_NOTES.txt
It has root project (web), conf, install and test. A module is a subproject that can be a separate project (e.g., svn project or git repository) that has its own versioning.

Build Properties

The build.properties specifies software group/name/version and module versions for build-time module version verification. For example,
	software.group=com.cmobilecom
	software.name=cmobilecom-af-examples
	software.displayName=Cmobilecom AF Examples
	software.version=1.2

	# module versions
	module-hr.version=1.2
The property naming convention for module versions is
	module-<module_name_lowercase>.version

Root Project

The root project is web that has build.gradle and settings.gradle.

settings.gradle defines subprojects. For example,

	rootProject.name = 'myapp-web'

	include 'app'

	include 'module-module1'
	project(':module-module1').projectDir = new File('../module1')

	include 'module-module2'
	project(':module-module2').projectDir = new File('../module2')

	include 'test'
	project(':test').projectDir = new File('../test')
The root project build.gradle needs to verify that environment variable CMOBILECOM_AF_DIR is defined, unzip the cmobilecom-af zip if needed, and apply the root.gradle from cmobilecom-af that will configure subprojects, create tasks for installation and test automation, etc.
	// define properties before applying root.gradle, see web/build.gradle of Cmobilecom AF examples.
	apply from : "$cmobilecomAFBuildCommonDir/root.gradle"

App Project

The web app project has build.gradle only, which applies the app.gradle from cmobilecom-af that will assemble war and obfuscate war for release build.

build.gradle

	apply from : "${rootProject.cmobilecomAFBuildCommonDir}/app.gradle"

Module Project

see Module Development for directory structure and build.gradle.

Conf

Configuration files:

Install

Installation related files including seed.sql, sites and resource bundles.

Seed XML

seed/seed.xml is a configuration file for installer, which specifies: For example,
<seed>
	<!-- seed sql files for system instance -->
	<!-- seed sql path: [module]/db/[dbmsType]/seed.sql -->
	<seedSql>system/db/@DBMS_TYPE@/seed-user.sql</seedSql>
	<seedSql>system/db/@DBMS_TYPE@/seed.sql</seedSql>
	<seedSql>system/db/@DBMS_TYPE@/seed-sys.sql</seedSql>
	<seedSql>website/db/@DBMS_TYPE@/seed.sql</seedSql>

	<!-- configuration files -->
	<copy dir="conf" todir="#{cmobilecom.home}" target="conf"/>
	<!-- copy main site -->
	<copy dir="sites/hr/main" todir="#{cmobilecom.home}/dau/hr/www" target="main"/>
</seed>
@DBMS_TYPE@ will be replaced by the target database name(e.g., mysql, oracle) during installation. Database seed will be skipped during installation if answer property "install.init.db" is false. If database is not initialized during installation, it will be initialized from module seed sql file list when application starts.

Install Resource Bundles

Resource bundles are used for installer to display software information in user's locale.

For example, install/bundle/messages.properties:

	cmobilecom-af-examples=Cmobilecom AF Examples
	cmobilecom-af-examples.description=This installer will guide you to install \
		Cmobilecom AF Examples {0}{1} on this computer.
cmobilecom-af-examples is the software name specified in build.properties. {0} and {1} will be resolved to software version and target platform respectively.

Application Resources

Application resources include app resource bundles and images.

	appRootDir/resources/
			bundle/messages.properties
				   messages_*.properties
			images/
Application resource bundles (resources/bundle/*) are used for resolving instance-type display names and expression #{bundle.Key} in system-config.xml. For example,

conf/system-config.xml:

	<system-config>
		<description><![CDATA[
			#{bundle.About_CmobilecomAF_Examples}
			<p>
			<a href="http://Cmobilecom-AF-Examples.com" target="_blank">http://Cmobilecom-AF-Examples.com</a>
		]]>
		</description>

		...
	</system-config>
The description is shown as application overview in help page. #{bundle.About_CmobilecomAF_Examples} will be resolved by application resource bundles. For example,

appRootDir/resources/bundle/messages.properties:

	CmobilecomAF_Examples=Cmobilecom AF Examples
	About_CmobilecomAF_Examples=Cmobilecom AF examples demonstrate how to develop a \
		Cmobilecom AF application.

Test

Test is a subproject for testing applications.
	test/
		src/test/
			java/
			resources/

		test-automation/
			webdriver/
				chromedriver.exe
				edgedriver.exe
			fileupload/
			<installation-dir>/
The subdirectory "test-automation" contains web drivers, files to upload, and installation directories for test automation. Download web drivers (correct versions) for the web browsers used for testing. Put files for upload under fileupload directory if they are needed for test automation. When running installer for test automation, the app will be installed under a subdirectory(e.g., win64_mysql) of the test-automation directory.

If running tests using docker Selenium Grid, the webdriver directory is not needed.

See Testing on how to write code for test automation.

Build And Run With Docker

Generate Dockerfile, docker-compose.yml, .env and .dockerignore files, or copy those from cmobilecom-af-examples and change environment variables in .env files.

Generate Docker Files

Docker-compose profiles:
	Profile                         Web App          Test Client
	-----------------------------------------------------------------
	debug                           debug            N/A
	production                      production       N/A
	debug_test (dt)                 debug            non-debug
	production_test (pt)            production       non-debug
	debug_test_debug (dtd)          debug            debug
	production_test_debug (ptd)     production       debug
Change current working directory to the root project web/docker directory to run docker commands.
	cd appRootDir/web/docker

Build And Run On Host

Build and run on host without using docker containers.

Preparations

Run gradle tasks from root project directory (web/).
	cd web
	gradle wrapper

Build War

Build war that will be put under app/build/libs. If options -Pdebug is not specified, the war will be obfuscated.
	gradlew :app:assemble [options]

	options:
		-Pdebug: debug build (for building war only)
		-Psnapshot: snapshot build
		-Psnapshot.date: snapshot timestamp(YYYYMMDD), default current date
Snapshot build will append timestamp to the versions of all modules and app.

Build and Deploy War

Build and deploy war to local test-automation Tomcat instance (${cmobilecom.home}/tomcat-<version>/webapp).
	gradlew deployWarToLocal [options]

Start and Stop Server

Start/Stop Tomcat instance for test automation.
	gradlew startServer
	gradlew stopServer

Enable Server Debug

Enable server debugging (JVM debug and set log level=DEBUG)
	gradlew enableServerDebug
It will enable server(tomcat) JVM debug(listen on port 8787), and change the log level to DEBUG in ${cmobilecom.home}/conf/logback.xml. Server restart is required.
	gradlew stopServer
	gradlew startServer

Log files are under ${cmobilecom.home}/log/ and ${cmobilecom.home}/tomcat-<version>/logs/.

Update System Config

Copy modified conf/system-config.xml to ${cmobilecom.home} without re-install:
	gradlew copySystemConfigToLocal
Restart server to load the new configuration.

Delete Local Install

Delete the local installation for test automation.
	gradlew cleanInstall
	gradlew clean cleanInstall   // clean both build and install

Copy Sites

Copy sites under install/seed/sites to the local test automation.
	gradlew copySitesToLocal

Generate Database Schemas

Module seed.sql files are used to create database schema objects for production. For development, schema objects can be generated with JPA standard properties in META-INF/persistence.xml. Refer to Cmobilecom JPA documentation for detail. They can also be generated from command line using Cmobilecom JPA directly.

mysql db:

	gradlew generateSchema -Ppu=hr -PjdbcUrl=jdbc:mysql://localhost:3306/test_db_hr
		-PjdbcUser=test_user -PjdbcPassword=welcome
		-Psystem.schema=test_db -Puser.schema=test_db
oracle db:
	gradlew generateSchema -Ppu=hr -PjdbcUrl=jdbc:oracle:thin:@//localhost:1521/XEPDB1
		-PjdbcUser=test_db_hr -PjdbcPassword=welcome
		-Psystem.schema=test_db -Puser.schema=test_db
properties:
	pu: persistence unit name
	jdbcUrl: JDBC connection URL
	jdbcUser: JDBC connection user
	jdbcPassword: JDBC connection password
	system.schema: system instance schema name for resolving expression
		#{system.schema} in orm.xml. default: empty string.
	user.schema: user table schema name for resolving expression
		#{user.schema} in orm.xml. default: empty string.
Both drop and create actions will be taken to generate schema objects in database and files. For database, all schema objects will be dropped before creating new schema objects. Create new empty database schemas for schema object generation. Database privileges required include: create tables, drop tables.

Generated schema drop and create sql files are put under

	rootProjectDir/build/schema-gen/<persistence-unit-name>/

Silent Install

Preparations: The answer properties above can be overridden by command-line properties as followings.

Run silent install:

	gradlew install [options]

	-Pcmobilecom.home=<name>: installation directory, overriding default and environment
	    variable CMOBILECOM_HOME. default is ../test/test-automation/install/<os_dbms>.

	-Pos=[win32|win64|linux]: operating system. empty for platform-independent
	    without application server bundled. Override environment CMOBILECOM_AF_OS.

	-Pdbms=[mysql|oracle]: database type. Override environment CMOBILECOM_AF_DBMS.

	-Pdbms.host=<host_name>: dbms host name or ip address. default: localhost.

	-Pdbms.port=<port_number>: dbms port number overriding default port number.

	-Pdb.schemaName=<name>: specify database schema name overriding default generated
		name. If the database schema already exists, it will be used without change.

	-Pdb.rootPassword=<password>: db root password, overriding that in answer properties.
	    Must match database root password.

	-Pdb.username=<username>: db username, overriding that in answer properties.
	    Do not override username if it is the same as schema name (e.g., oracle database).

	-Pdb.password=<password>: db password for the user, overriding that in answer properties.
	    The password for an existing user will be correct.

	-Pdb.userHost=<host_name>: db client host or ip address. default: localhost. For example,
		user <db.username>@<db.userHost> will be created for mysql database.

	-Pas.port.http=<port_number>: application server HTTP port overriding that in answer properties.

	-Pas.port.https=<port_number>: application server HTTPS port overriding that in answer properties.

	-Pinstall.init.db=[true|false] whether to init database during installation. If false,
	    database will be initialized when application is started. Default is true.

	-Ptest.automation[=true|false]: whether to enable/disable test automation. Default is false.

	-Ptest.noInternet[=true|false]: whether to turn off all features that require internet
	    connection (e.g., captcha) for test automation. Default is false.
For example: install, start server and run test automation:
	gradlew install startServer -Ptest.automation=true
	gradlew :test:test

Run Tests

Preparations:
Run Test Automation:
	gradlew :test:test [--tests filter]
Open test report html on host web browser for local test, remote test or test with docker-compose:
	gradlew :test:openReport
Re-run Tests
Re-run a previous test from an exec point:
	gradlew :test:test -Prerun -PuserNo=<userNumber> -PgotoExec=<execPoint>

	userNo: the user number for the previous test.
	gotoExec: run from an exec point, e.g. Main.HR.create_expenseClaims.
ExecPoint format: instanceIdentifier.moduleName.execPointName.
Run Remote Tests
Run a remote test using test code on host with remote driver connected to a remote test server (e.g. Selenium grid running in docker container):
	docker-compose --profile dt up

	gradlew clean cleanInstall install -Ptest.automation=true
	gradlew :test:test -Premote=true [-PremoteURL=<testServerURL>]
If remoteURL is not specified, default to:
	http://localhost:4444
The browser and web driver on the remote test server (docker image) will be used.

Live remote test sessions: http://localhost:4444

Test reports are on host as if running a local test.

Release Build

Build installer zip files under build/distributions:
	gradlew assemble [options]        // build all installer zips
	gradlew installerZip_[targetOs]   // build installer zip for one target OS
	gradlew installerZip              // build installer zip (platform-independent) without tomcat

	targetOs: win32, win64 or linux.
	options:
		-Psnapshot: snapshot build
		-Psnapshot.date: snapshot timestamp(YYYYMMDD), default current date
To build installer zip for a targetOS, cmobilecom-af-<version>-<targetOS>.zip needs to be downloaded and put under cmobilecomAFDistsDir (the parent directory of CMOBILECOM_AF_DIR). For example,
	cmobilecomAFDistsDir/
		cmobilecom-af-<version>.zip
		cmobilecom-af-<version>-linux.zip
		cmobilecom-af-<version>-win32.zip
		cmobilecom-af-<version>-win64.zip
		cmobilecom-af-<version>/ (CMOBILECOM_AF_DIR)

Generate Docker Files

In the root project build.gradle, define docker map property. For example,
ext {
	// docker map for task createDockerFiles
	docker = [
			dockerignoreDir : '..',  // relative to rootProject.projectDir
			ignoreNginxConf : false,

			env : [
					// docker-compose.yml dir: ./docker
					BUILD_CONTEXT : '../..', // relative to docker-compose.yml
					DOCKER_FILE_DIR : 'web/docker', // relative to build context
					IMAGE_NAME : 'foo/bar',
					DB_ROOT_PASSWORD : 'welcome1',
					DB_PASSWORD : 'welcome2',
			],

			PREPARE_BUILD : '''
WORKDIR $CMOBILECOM_APP_DIR/$SOFTWARE_NAME
COPY . .
WORKDIR web
'''
	]
}
Generate Dockerfile, docker-compose.yml, .env, .dockerignore and nginx.conf files:
	gradlew createDockerFiles
Dockerfile and docker-compose.yml are generated into subdirectory "docker" from templates under $CMOBILECOM_AF_DIR/build-common/docker, and all the name/value pairs in the docker.env will be added to the .env files overriding default values.

Dockerfile multi-stage build:

	                      build-prepare
	                      -------------
	                           |
	                      build-release
	                    -----------------
	                    /       |       \
	       web-production  build-debug  test-client-non-debug
	       --------------  -----------  ---------------------
	                        /      \
	                 web-debug     test-client-debug
	                 ---------     -----------------
Replacement blocks in Dockerfile: Notes: See section Build And Run With Docker.
InstallationEntity AnnotationFrames / No Frames