Deployment in a Development Environment - hmislk/hmis GitHub Wiki

This page walks through installing a working local copy of HMIS โ€” clone, build, database, application server, deploy, first login โ€” end to end. It is written to be followed literally, including by an AI coding agent with shell access: every step has an exact command and a way to check it worked before moving on.

If you only need to point an already-running local Payara at the app (JNDI names already created), skip to Configure persistence.xml.

What you're installing

Component Version used by this project Notes
JDK 11 (Temurin/Adoptium recommended) The build fails/misbehaves on JDK 17+. pom.xml compiles with --release 11.
Build tool Maven 3.6+ Produces a WAR via mvn package.
Application server Payara 5 (5.2022.5 or newer 5.x) GlassFish 5-compatible; not Payara 6/Jakarta EE 9+.
Database MySQL 8.0.x or MariaDB 10.x JDBC driver bundled in the build is com.mysql:mysql-connector-j:8.0.33.
OS Linux (Ubuntu) or Windows Both work for local dev; commands below are given for both where they differ.

The app is a single WAR (Maven artifactId rh, e.g. rh-3.0.0.war) with a fixed context root of /rh (src/main/webapp/WEB-INF/glassfish-web.xml), so once deployed it's reachable at http://localhost:8080/rh/.

It uses two separate JPA persistence units, each backed by its own JNDI datasource, both of which must exist in Payara before the app will deploy successfully:

  • hmisPU โ€” the main application database (JNDI name configured in src/main/resources/META-INF/persistence.xml, currently jdbc/coop in this checkout โ€” see step 6, this is a per-developer local value, never a fixed name)
  • hmisAuditPU โ€” the audit-log database (jdbc/ruhunuAudit in this checkout)

For local dev these can point at two databases on the same MySQL instance (simplest), or even the same database โ€” they don't have to be physically separate.


1. Install prerequisites

Ubuntu:

sudo apt-get update
sudo apt-get install -y git openjdk-11-jdk maven mysql-server
java -version   # must report 11.x
mvn -version    # confirm it picked up JDK 11, not a newer default JDK

Windows: install Git, a JDK 11 build (e.g. Eclipse Adoptium 11), Maven, and MySQL or MariaDB. Make sure JAVA_HOME points at the JDK 11 install and mvn -version reports it.

2. Clone and build

git clone https://github.com/hmislk/hmis.git
cd hmis
git checkout development   # the active integration branch โ€” see CONTRIBUTING.md
mvn clean package -DskipTests

Verify: the build ends with BUILD SUCCESS and prints the WAR path, e.g.:

[INFO] Building war: /path/to/hmis/target/rh-3.0.0.war

If the version number differs, just substitute it in later steps โ€” the important part is the file lives at target/rh-*.war.

3. Install and start Payara

Download and unzip Payara Community 5.2022.5 (or any Payara 5.x) to a folder โ€” call it <PAYARA_HOME> below.

Point Payara at your JDK 11 install:

Linux (<PAYARA_HOME>/glassfish/config/asenv.conf):

AS_JAVA="/usr/lib/jvm/java-11-openjdk-amd64"

Windows (<PAYARA_HOME>\glassfish\config\asenv.bat):

set AS_JAVA=C:\path\to\jdk-11

Make sure nothing else is using port 8080, then start the domain:

<PAYARA_HOME>/bin/asadmin start-domain domain1

Verify: curl -I http://localhost:4848 returns a response (admin console is up), and <PAYARA_HOME>/bin/asadmin list-domains shows domain1 running.

4. Create the database(s)

Create an empty database and a user for it. This example uses one database for both persistence units โ€” see the table in the intro if you'd rather separate them.

CREATE DATABASE hmis CHARACTER SET utf8mb4;
CREATE USER 'hmis'@'localhost' IDENTIFIED BY 'hmis';
GRANT ALL PRIVILEGES ON hmis.* TO 'hmis'@'localhost';
FLUSH PRIVILEGES;

Copy the MySQL JDBC driver into Payara's classpath (must match the version the app was built against โ€” currently 8.0.33):

# Download from Maven Central:
# https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar
cp mysql-connector-j-8.0.33.jar <PAYARA_HOME>/glassfish/lib/
<PAYARA_HOME>/bin/asadmin stop-domain domain1
<PAYARA_HOME>/bin/asadmin start-domain domain1

5. Create the JDBC connection pools and JNDI resources

Create one pool/resource pair per persistence unit. The JNDI resource names must exactly match whatever is in <jta-data-source> in persistence.xml (step 6) โ€” pick names now and use the same ones there.

ASADMIN=<PAYARA_HOME>/bin/asadmin

# Main application datasource
$ASADMIN create-jdbc-connection-pool \
  --datasourceclassname com.mysql.cj.jdbc.MysqlDataSource \
  --restype javax.sql.DataSource \
  --property "user=hmis:password=hmis:databaseName=hmis:serverName=localhost:port=3306:useSSL=false:allowPublicKeyRetrieval=true:rewriteBatchedStatements=true" \
  hmisPool

$ASADMIN create-jdbc-resource --connectionpoolid hmisPool jdbc/coop

# Audit datasource (can point at the same database)
$ASADMIN create-jdbc-connection-pool \
  --datasourceclassname com.mysql.cj.jdbc.MysqlDataSource \
  --restype javax.sql.DataSource \
  --property "user=hmis:password=hmis:databaseName=hmis:serverName=localhost:port=3306:useSSL=false:allowPublicKeyRetrieval=true" \
  hmisAuditPool

$ASADMIN create-jdbc-resource --connectionpoolid hmisAuditPool jdbc/ruhunuAudit

rewriteBatchedStatements=true on the main pool matters: persistence.xml turns on EclipseLink JDBC batch-writing, and MySQL Connector/J silently ignores batching without this property.

Verify each pool can actually reach the database:

$ASADMIN ping-connection-pool hmisPool
$ASADMIN ping-connection-pool hmisAuditPool

Both must print Command ping-connection-pool executed successfully. If a ping fails, re-check the driver jar (step 4) and the pool's user/password/databaseName properties before continuing โ€” nothing downstream will work until this passes.

6. Point persistence.xml at your local datasources

Open src/main/resources/META-INF/persistence.xml and check the two <jta-data-source> values:

grep -A1 jta-data-source src/main/resources/META-INF/persistence.xml
  • If they already match the JNDI names you created in step 5 (e.g. jdbc/coop, jdbc/ruhunuAudit), you're done.
  • If they show placeholders (${JDBC_DATASOURCE}, ${JDBC_AUDIT_DATASOURCE}) โ€” the form this file must be in before every git push โ€” edit them locally to your JNDI names from step 5.

๐Ÿšจ Never commit this local edit. These names are per-developer/per-environment; committing hardcoded names breaks CI/CD deployments for everyone else. Keep the change unstaged, and restore the placeholders (or git checkout the file) before pushing. See developer_docs/deployment/persistence-verification.md in the main repo for the full rule.

7. Create the schema

A freshly created empty database has no tables yet, and the app does not create them automatically on startup โ€” schema generation has to be turned on explicitly, once.

Add these two properties inside both <persistence-unit> blocks in persistence.xml (inside their <properties> section):

<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>

Deploy the WAR once (step 9 below covers the full deploy command). EclipseLink will create all ~190 tables directly in the database on that first deployment. Watch the server log for errors:

tail -f <PAYARA_HOME>/glassfish/domains/domain1/logs/server.log

Verify: SHOW TABLES; in the hmis database now lists a large number of tables (e.g. WEBUSER, INSTITUTION, DEPARTMENT, BILL, ...).

Once the schema exists, remove the two properties again (or comment them out) and redeploy. Leaving create-or-extend-tables on permanently is a supported local-dev pattern for picking up new columns as entities change, but keep it deliberate โ€” it's one of the settings step 6's warning applies to (never push it enabled).

8. Get a usable admin login

The application has no self-service "create first institution/user" wizard โ€” an empty, freshly-created schema has no INSTITUTION, DEPARTMENT, or WEBUSER rows, and there is no in-app bootstrap flow that creates them. You need at least one row in each of those tables (plus role/privilege rows) before you can log in at all.

Two practical ways to get there:

  • Restore a reference database dump (recommended). Ask a team member for a sanitized snapshot of an existing HMIS database โ€” it already has the schema, base reference data (categories, fee types, etc.), and at least one super-admin WEBUSER. Restore it instead of creating an empty schema in step 7. src/main/webapp/resources/sql/new_installation.sql can then be run against the restored database to wipe customer-specific transactional data (bills, patients, staff, stock, etc.) while keeping the schema, reference data, and the admin account โ€” useful for turning a copy of a live database into a clean local sandbox. Read the script before running it: it is destructive by design and keeps only specific hardcoded WEBUSER/DEPARTMENT/INSTITUTION IDs.
  • Seed manually. If no dump is available, insert a minimal INSTITUTION, DEPARTMENT, and WEBUSER (with the appropriate password hash and privilege rows) directly via SQL. There's no documented canonical seed script for this in the repo today โ€” treat it as exploratory, and cross-check the WebUser, Institution, and Department entity classes under src/main/java/com/divudi/core/entity/ for required fields before inserting.

9. Deploy the WAR

<PAYARA_HOME>/bin/asadmin deploy target/rh-3.0.0.war

(substitute the actual filename from step 2 if the version differs)

Verify:

<PAYARA_HOME>/bin/asadmin list-applications
# should list: rh <ejb, web>

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/rh/
# 302 (redirect to login) means the app deployed and started correctly

Open http://localhost:8080/rh/ in a browser and log in with the admin account from step 8.

Redeploying after code changes

mvn clean package -DskipTests
<PAYARA_HOME>/bin/asadmin redeploy target/rh-3.0.0.war

Troubleshooting

ping-connection-pool fails / app won't deploy, mentions ClassNotFoundException: com.mysql.cj.jdbc.MysqlDataSource The driver jar isn't on Payara's classpath. Re-check step 4 โ€” the jar must be in <PAYARA_HOME>/glassfish/lib/ and the domain restarted afterward.

Deploy fails referencing jdbc/coop (or whatever name you used) not found The JNDI resource name in persistence.xml doesn't match what you created in step 5. Re-run grep -A1 jta-data-source src/main/resources/META-INF/persistence.xml and asadmin list-jdbc-resources and make them match exactly.

curl http://localhost:8080/rh/ returns 404 after a successful-looking deploy Usually means Payara did deploy but the app failed to fully initialize โ€” check <PAYARA_HOME>/glassfish/domains/domain1/logs/server.log for the actual exception, most often a missing table (schema not created โ€” step 7) or a datasource that pings but points at the wrong database.

Build succeeds with JDK 17+ installed but the app misbehaves at runtime, or Maven picks the wrong JDK This project targets JDK 11. Confirm JAVA_HOME and mvn -version both point at a JDK 11 install, not whatever newer JDK might also be on the machine.

Table names came from a dump made on Linux and queries fail on a case-sensitive/insensitive mismatch MySQL table-name case sensitivity differs between Linux (case-sensitive by default) and Windows/macOS (usually not). See "Cross-deployment case sensitivity" in developer_docs/database/migration-development-guide.md in the main repo if you hit this after restoring a dump from a different OS.

Never run Payara/asadmin as root on a Linux dev box that's also used for anything shared โ€” it leaves root-owned files behind that block subsequent deploys. Not usually relevant on a personal dev machine, but avoid sudo asadmin ... out of habit.

Quick reference

git clone https://github.com/hmislk/hmis.git && cd hmis && git checkout development
mvn clean package -DskipTests

<PAYARA_HOME>/bin/asadmin start-domain domain1

mysql -u root -e "CREATE DATABASE hmis CHARACTER SET utf8mb4; \
  CREATE USER 'hmis'@'localhost' IDENTIFIED BY 'hmis'; \
  GRANT ALL PRIVILEGES ON hmis.* TO 'hmis'@'localhost'; FLUSH PRIVILEGES;"

cp mysql-connector-j-8.0.33.jar <PAYARA_HOME>/glassfish/lib/
<PAYARA_HOME>/bin/asadmin stop-domain domain1 && <PAYARA_HOME>/bin/asadmin start-domain domain1

# create hmisPool/jdbc-coop and hmisAuditPool/jdbc-ruhunuAudit โ€” see step 5
# edit persistence.xml jta-data-source values to match โ€” see step 6 (never commit)
# add ddl-generation properties, deploy once to create schema, then remove them โ€” see step 7
# get an admin login (dump restore or manual seed) โ€” see step 8

<PAYARA_HOME>/bin/asadmin deploy target/rh-3.0.0.war
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/rh/   # expect 302
โš ๏ธ **GitHub.com Fallback** โš ๏ธ