diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..f91f64602e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/.gitignore b/.gitignore index 9dcfd64acf..8f092cbda2 100644 --- a/.gitignore +++ b/.gitignore @@ -734,3 +734,9 @@ donkey/donkey-test # /webadmin/src/com/mirth/connect/webadmin/utils/ + +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/.sdkmanrc b/.sdkmanrc index 4f6817d132..86c7b483c7 100644 --- a/.sdkmanrc +++ b/.sdkmanrc @@ -2,3 +2,4 @@ # Add key=value pairs of SDKs to use below java=8.0.442.fx-zulu ant=1.10.14 +gradle=8.14 \ No newline at end of file diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000000..afc3ae4376 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,238 @@ +# Mirth Connect Gradle Orchestrator Build Configuration + +## Overview + +This document describes the comprehensive orchestrator build configuration that replicates the functionality of the original `server/mirth-build.xml` file using Gradle. The orchestrator manages the entire build process with proper dependencies and file copying between modules. + +## Orchestrator Tasks Implemented + +### Core Build Tasks + +1. **`build-donkey`** - Build donkey and copy JARs to server/lib/donkey + - Builds the donkey module + - Copies donkey-model.jar and donkey-server.jar to server/lib/donkey + - Copies donkey lib dependencies with specific exclusions + +2. **`build-webadmin`** - Build webadmin and copy WAR to server setup + - Builds the webadmin module + - Copies webadmin.war to both server/build/webapps and server/setup/webapps + +3. **`build-server-extensions`** - Build server extensions and copy shared JARs to client/lib + - Depends on build-donkey + - Builds server extensions via copyExtensionsToSetup task + - Copies shared extension JARs (*-shared.jar) to client/lib + +4. **`build-client`** - Build client and copy JARs/extensions to server setup + - Depends on build-server-extensions + - Copies required JARs to client/lib before building + - Builds the client module + - Copies client artifacts to server setup directories + +5. **`build-manager`** - Build manager and copy to server setup + - Depends on build-client + - Copies required JARs to manager/lib before building + - Builds the manager module + - Copies manager artifacts to server setup + +6. **`build-cli`** - Build CLI and copy to server setup + - Depends on build-client + - Copies required JARs to command/lib before building + - Builds the command module + - Copies CLI artifacts and configuration to server setup + +### Main Orchestration Tasks + +1. **`orchestratorBuild`** - Main build target that orchestrates everything + - Depends on build-manager, build-cli, build-webadmin, and server:createSetup + - Copies extensions and client-lib to server build directory + - Runs tests via finalizedBy + +2. **`build`** - Enhanced default build task + - Overrides the default Gradle build task to use orchestratorBuild + - Maintains compatibility with standard Gradle workflows + +3. **`dist`** - Distribution creation target + - Creates distribution by copying server setup to server/dist + - Displays application version information + +### Utility Tasks + +1. **`test-run`** - Run tests across all modules + - Runs tests for donkey and server modules + - Provides status reporting for test execution + +2. **`remove-classes`** - Clean compiled classes across all modules + - Executes clean task for all subprojects + - Provides comprehensive cleanup + +3. **`append-license`** - License header management + - Processes Java files in all modules + - Adds license headers to files that don't have them + - Respects module-specific exclusions + +4. **`build-custom`** - Build custom extensions + - Placeholder for custom extensions build + - Checks for custom-extensions.xml file + +5. **`initOrchestrator`** - Initialize orchestrator properties and directories + - Creates necessary directory structure + - Sets up build environment + +## Task Aliases + +For convenience, camelCase aliases are provided for all main tasks: + +- `buildDonkey` → `build-donkey` +- `buildWebadmin` → `build-webadmin` +- `buildServerExtensions` → `build-server-extensions` +- `buildClient` → `build-client` +- `buildManager` → `build-manager` +- `buildCli` → `build-cli` +- `testRun` → `test-run` +- `removeClasses` → `remove-classes` +- `appendLicense` → `append-license` +- `buildCustom` → `build-custom` + +## Build Order and Dependencies + +The orchestrator maintains the exact build order from the original Ant build: + +```bash +donkey → server extensions → client → manager/cli → webadmin +``` + +### Dependency Chain + +1. `build-donkey` (no dependencies) +2. `build-server-extensions` (depends on build-donkey) +3. `build-client` (depends on build-server-extensions) +4. `build-manager` and `build-cli` (both depend on build-client) +5. `build-webadmin` (independent) +6. `orchestratorBuild` (depends on build-manager, build-cli, build-webadmin) + +## File Copying Operations + +The orchestrator replicates all file copying operations from the original build: + +### Donkey to Server + +- `donkey/setup/donkey-model.jar` → `server/lib/donkey/` +- `donkey/setup/donkey-server.jar` → `server/lib/donkey/` +- `donkey/lib/*` → `server/lib/donkey/` (with exclusions) + +### Server Extensions to Client + +- `server/build/extensions/**/*-shared.jar` → `client/lib/` (flattened) + +### Client Dependencies + +- `donkey/setup/donkey-model.jar` → `client/lib/` +- `server/setup/server-lib/mirth-client-core.jar` → `client/lib/` +- `server/setup/server-lib/mirth-crypto.jar` → `client/lib/` +- `server/lib/mirth-vocab.jar` → `client/lib/` + +### Client to Server Setup + +- `client/build/libs/client.jar` → `server/setup/client-lib/mirth-client.jar` +- `client/lib/*` → `server/setup/client-lib/` (excluding shared JARs) +- `client/dist/extensions/*` → `server/setup/extensions/` + +### Manager to Server Setup + +- `manager/dist/mirth-manager-launcher.jar` → `server/setup/` +- `manager/lib/*` → `server/setup/manager-lib/` (excluding mirth-client.jar) + +### CLI to Server Setup + +- `command/build/mirth-cli.jar` → `server/setup/cli-lib/` +- `command/build/mirth-cli-launcher.jar` → `server/setup/` +- `command/lib/*` → `server/setup/cli-lib/` (excluding mirth-client.jar) +- `command/conf/mirth-cli-config.properties` → `server/setup/conf/` +- `command/conf/log4j2-cli.properties` → `server/setup/conf/` + +### Final Integration + +- `server/setup/extensions/*` → `server/build/extensions/` +- `server/setup/client-lib/*` → `server/build/client-lib/` + +## Usage Examples + +### Build Everything + +```bash +./gradlew build +# or +./gradlew orchestratorBuild +``` + +### Build Specific Components + +```bash +./gradlew build-donkey +./gradlew build-client +./gradlew build-manager +``` + +### Run Tests + +```bash +./gradlew test-run +``` + +### Clean Everything + +```bash +./gradlew remove-classes +``` + +### Create Distribution + +```bash +./gradlew dist +``` + +### Add License Headers + +```bash +./gradlew append-license +``` + +## Integration with Existing Gradle Build + +The orchestrator integrates seamlessly with the existing Gradle build system: + +- Uses existing module build.gradle.kts files +- Leverages existing task dependencies +- Maintains compatibility with standard Gradle commands +- Preserves individual module build capabilities + +## Key Features + +1. **Exact Replication**: Replicates all functionality from the original mirth-build.xml +2. **Proper Dependencies**: Maintains correct build order and dependencies +3. **File Management**: Handles all file copying operations accurately +4. **Error Handling**: Provides proper error handling and status reporting +5. **Flexibility**: Supports both individual component builds and full orchestration +6. **Compatibility**: Works with existing Gradle ecosystem and tooling + +## Directory Structure Created + +The orchestrator automatically creates the following directory structure: + +```bash +server/ +├── lib/donkey/ +├── setup/ +│ ├── webapps/ +│ ├── client-lib/ +│ ├── extensions/ +│ ├── manager-lib/ +│ ├── cli-lib/ +│ └── conf/ +└── build/ + ├── webapps/ + ├── extensions/ + └── client-lib/ +``` + +This comprehensive orchestrator build configuration provides a complete Gradle-based replacement for the original Ant build system while maintaining full compatibility and functionality. diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000..83f1d79a5d --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,1256 @@ +import java.security.MessageDigest +import java.time.LocalDateTime + +plugins { + java + jacoco + distribution +} + +group = "com.mirth.connect" +version = "4.5.2" + +// Configure all projects +allprojects { + group = "com.mirth.connect" + version = "4.5.2" + + repositories { + mavenCentral() + + // Support for existing lib folders in each module + flatDir { + dirs("lib") + } + + // Support for testlib folders + flatDir { + dirs("testlib") + } + } +} + +// Configure all subprojects +subprojects { + apply(plugin = "java") + apply(plugin = "jacoco") + + // Java 8 compatibility + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + // Handle duplicate files in distributions + tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } + + tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } + + // Common compiler options + tasks.withType { + options.encoding = "UTF-8" + options.compilerArgs.addAll(listOf("-Xlint:deprecation", "-Xlint:unchecked")) + } + + // Common test configuration + tasks.test { + filter { + // Exclude all tests whose class name ends with "Tests" + includeTestsMatching("*Test") + } + + useJUnit() + testLogging { + events("passed", "skipped", "failed") + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + } + + // JaCoCo test coverage + finalizedBy(tasks.jacocoTestReport) + } + + // JaCoCo configuration + tasks.jacocoTestReport { + dependsOn(tasks.test) + reports { + xml.required.set(true) + html.required.set(true) + } + } + + // Common dependencies that most modules will need + dependencies { + // Test dependencies + testImplementation("junit:junit:4.8.1") + + // Logging dependencies (most modules use these) + implementation("org.apache.logging.log4j:log4j-api:2.17.2") + implementation("org.apache.logging.log4j:log4j-core:2.17.2") + implementation("org.apache.logging.log4j:log4j-1.2-api:2.17.2") + implementation("org.slf4j:slf4j-api:1.7.30") + implementation("org.slf4j:slf4j-log4j12:1.7.30") + } +} + +// Root project tasks - clean task is already provided by java plugin + +// Aggregate JaCoCo report for all subprojects +tasks.register("jacocoRootReport") { + description = "Generates an aggregate report from all subprojects" + + dependsOn(subprojects.map { it.tasks.named("jacocoTestReport") }) + + additionalSourceDirs.from(subprojects.map { it.the()["main"].allSource.srcDirs }) + sourceDirectories.from(subprojects.map { it.the()["main"].allSource.srcDirs }) + classDirectories.from(subprojects.map { it.the()["main"].output }) + executionData.from(project.fileTree(".") { include("**/build/jacoco/test.exec") }) + + reports { + xml.required.set(true) + html.required.set(true) + csv.required.set(false) + } + + onlyIf { true } + + doFirst { + executionData.from(executionData.filter { it.exists() }) + } +} + +// Build all modules +tasks.register("buildAll") { + description = "Builds all subprojects" + dependsOn(subprojects.map { it.tasks.named("build") }) +} + +// Print project information +tasks.register("projectInfo") { + description = "Displays project information" + doLast { + println("Project: ${rootProject.name}") + println("Version: ${rootProject.version}") + println("Group: ${rootProject.group}") + println("Modules:") + subprojects.forEach { project -> + println(" - ${project.name}") + } + } +} + +// ============================================================================= +// ORCHESTRATOR TASKS - Replicating mirth-build.xml functionality +// ============================================================================= + +// Initialize properties and directories +tasks.register("initOrchestrator") { + description = "Initialize orchestrator properties and directories" + doLast { + // Create necessary directories using File constructor instead of file() function + File(projectDir, "server/lib/donkey").mkdirs() + File(projectDir, "server/setup").mkdirs() + File(projectDir, "server/build").mkdirs() + File(projectDir, "server/setup/webapps").mkdirs() + File(projectDir, "server/setup/client-lib").mkdirs() + File(projectDir, "server/setup/extensions").mkdirs() + File(projectDir, "server/setup/manager-lib").mkdirs() + File(projectDir, "server/setup/cli-lib").mkdirs() + File(projectDir, "server/setup/conf").mkdirs() + File(projectDir, "server/build/webapps").mkdirs() + File(projectDir, "server/build/extensions").mkdirs() + File(projectDir, "server/build/client-lib").mkdirs() + + println("Orchestrator directories initialized") + } +} + +// Build donkey and copy JARs to server/lib/donkey +tasks.register("build-donkey") { + description = "Build donkey and copy JARs to server/lib/donkey" + dependsOn("initOrchestrator", ":donkey:build") + + doLast { + // Delete existing donkey lib directory + delete(File(projectDir, "server/lib/donkey")) + File(projectDir, "server/lib/donkey").mkdirs() + + // Copy donkey JARs + copy { + from(File(projectDir, "donkey/setup/donkey-model.jar")) + into(File(projectDir, "server/lib/donkey")) + } + copy { + from(File(projectDir, "donkey/setup/donkey-server.jar")) + into(File(projectDir, "server/lib/donkey")) + } + + // Copy donkey lib dependencies with exclusions + copy { + from(File(projectDir, "donkey/lib")) { + exclude("log4j-1.2.16.jar") + exclude("HikariCP-java6-2.0.1.jar") + exclude("javassist-3.19.0-GA.jar") + exclude("xstream/**") + exclude("commons/**") + exclude("database/**") + } + into(File(projectDir, "server/lib/donkey")) + } + + println("Donkey build completed and JARs copied to server/lib/donkey") + } +} + +// Build webadmin and copy WAR to server setup +tasks.register("build-webadmin") { + description = "Build webadmin and copy WAR to server setup" + dependsOn("initOrchestrator", ":webadmin:war") + + doLast { + // Copy webadmin.war to both build and setup directories + copy { + from(File(projectDir, "webadmin/build/libs/webadmin.war")) + into(File(projectDir, "server/build/webapps")) + } + copy { + from(File(projectDir, "webadmin/build/libs/webadmin.war")) + into(File(projectDir, "server/setup/webapps")) + } + + println("WebAdmin build completed and WAR copied to server directories") + } +} + +// Build server extensions and copy shared JARs to client/lib +tasks.register("build-server-extensions") { + description = "Build server extensions and copy shared JARs to client/lib" + dependsOn("build-donkey", ":server:copyExtensionsToSetup") + + doLast { + // Copy shared extension JARs to client lib + copy { + from(fileTree(File(projectDir, "server/build/extensions")) { + include("**/*-shared.jar") + }) + into(File(projectDir, "client/lib")) + eachFile { + // Flatten the directory structure + relativePath = RelativePath(true, name) + } + } + + println("Server extensions built and shared JARs copied to client/lib") + } +} + +// Build client and copy JARs/extensions to server setup +tasks.register("build-client") { + description = "Build client and copy JARs/extensions to server setup" + dependsOn("build-server-extensions", ":server:createSetup") + + // Capture project version during configuration time + val projectVersion = version.toString() + + doFirst { + // Copy required JARs to client/lib before building + copy { + from(File(projectDir, "donkey/setup/donkey-model.jar")) + into(File(projectDir, "client/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-client-core.jar")) + into(File(projectDir, "client/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-crypto.jar")) + into(File(projectDir, "client/lib")) + } + copy { + from(File(projectDir, "server/lib/mirth-vocab.jar")) + into(File(projectDir, "client/lib")) + } + } + + finalizedBy(":client:build") + + doLast { + // Copy client JAR to server setup + copy { + from(File(projectDir, "client/build/libs/client-${projectVersion}.jar")) + into(File(projectDir, "server/setup/client-lib")) + rename { "mirth-client.jar" } + } + + // Copy client lib dependencies (excluding shared JARs and extensions) + copy { + from(File(projectDir, "client/lib")) { + exclude("*-shared.jar") + exclude("extensions") + } + into(File(projectDir, "server/setup/client-lib")) + } + + // Copy client extensions to server setup + copy { + from(File(projectDir, "client/dist/extensions")) + into(File(projectDir, "server/setup/extensions")) + } + + println("Client build completed and artifacts copied to server setup") + } +} + +// Build manager and copy to server setup +tasks.register("build-manager") { + description = "Build manager and copy to server setup" + dependsOn("build-client") + + doFirst { + // Copy required JARs to manager/lib before building + copy { + from(File(projectDir, "donkey/setup/donkey-model.jar")) + into(File(projectDir, "manager/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-client-core.jar")) + into(File(projectDir, "manager/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-crypto.jar")) + into(File(projectDir, "manager/lib")) + } + } + + finalizedBy(":manager:build") + + doLast { + // Copy manager launcher JAR to server setup + copy { + from(File(projectDir, "manager/build/libs/mirth-manager-launcher.jar")) + into(File(projectDir, "server/setup")) + } + + // Copy manager lib dependencies (excluding mirth-client.jar) + copy { + from(File(projectDir, "manager/lib")) { + exclude("mirth-client.jar") + } + into(File(projectDir, "server/setup/manager-lib")) + } + + println("Manager build completed and artifacts copied to server setup") + } +} + +// Build CLI and copy to server setup +tasks.register("build-cli") { + description = "Build CLI and copy to server setup" + dependsOn("build-client") + + doFirst { + // Copy required JARs to CLI lib before building + copy { + from(File(projectDir, "donkey/setup/donkey-model.jar")) + into(File(projectDir, "command/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-client-core.jar")) + into(File(projectDir, "command/lib")) + } + copy { + from(File(projectDir, "server/setup/server-lib/mirth-crypto.jar")) + into(File(projectDir, "command/lib")) + } + } + + finalizedBy(":command:build") + + doLast { + // Copy CLI JARs to server setup + copy { + from(File(projectDir, "command/build/libs/mirth-cli.jar")) + into(File(projectDir, "server/setup/cli-lib")) + } + copy { + from(File(projectDir, "command/build/libs/mirth-cli-launcher.jar")) + into(File(projectDir, "server/setup")) + } + + // Copy CLI lib dependencies (excluding mirth-client.jar) + copy { + from(File(projectDir, "command/lib")) { + exclude("mirth-client.jar") + } + into(File(projectDir, "server/setup/cli-lib")) + } + + // Copy CLI configuration files + copy { + from(File(projectDir, "command/conf")) { + include("mirth-cli-config.properties") + include("log4j2-cli.properties") + } + into(File(projectDir, "server/setup/conf")) + } + + println("CLI build completed and artifacts copied to server setup") + } +} + +// Main build target that orchestrates everything +tasks.register("orchestratorBuild") { + description = "Main build target that orchestrates the entire build process" + dependsOn("build-manager", "build-cli", "build-webadmin", ":server:createSetup") + + doLast { + // Copy extensions to server build + copy { + from(File(projectDir, "server/setup/extensions")) + into(File(projectDir, "server/build/extensions")) + } + + // Copy client-lib to server build + copy { + from(File(projectDir, "server/setup/client-lib")) + into(File(projectDir, "server/build/client-lib")) + } + + println("Main build completed successfully") + } + + finalizedBy("test-run") +} + +// Override the default build task to use our orchestrator +tasks.named("build") { + dependsOn("orchestratorBuild") +} + +// ============================================================================= +// DISTRIBUTION TASKS - Create final .tar and .zip distributions +// ============================================================================= + +// Create extension zips (matching original Ant build) +tasks.register("createExtensionZips") { + description = "Create individual extension zip files" + dependsOn("orchestratorBuild") + + doLast { + val distExtensionsDir = file("server/dist/extensions") + distExtensionsDir.mkdirs() + + val extensionsDir = file("server/setup/extensions") + if (extensionsDir.exists()) { + // Connector extensions + val connectors = listOf("jms", "jdbc", "dicom", "http", "doc", "smtp", "tcp", "file", "js", "ws", "vm") + connectors.forEach { connector -> + val connectorDir = file("$extensionsDir/$connector") + if (connectorDir.exists()) { + ant.withGroovyBuilder { + "zip"("destfile" to "$distExtensionsDir/$connector-${project.version}.zip", + "basedir" to extensionsDir, + "includes" to "$connector/**/*") + } + } + } + + // Datatype extensions + val datatypes = listOf("datatype-delimited", "datatype-dicom", "datatype-edi", "datatype-hl7v2", + "datatype-hl7v3", "datatype-ncpdp", "datatype-xml", "datatype-raw", "datatype-json") + datatypes.forEach { datatype -> + val datatypeDir = file("$extensionsDir/$datatype") + if (datatypeDir.exists()) { + ant.withGroovyBuilder { + "zip"("destfile" to "$distExtensionsDir/$datatype-${project.version}.zip", + "basedir" to extensionsDir, + "includes" to "$datatype/**/*") + } + } + } + + // Plugin extensions + val plugins = listOf("directoryresource", "dashboardstatus", "destinationsetfilter", "serverlog", + "datapruner", "javascriptstep", "mapper", "messagebuilder", "scriptfilestep", + "rulebuilder", "javascriptrule", "dicomviewer", "pdfviewer", "textviewer", + "httpauth", "imageviewer", "globalmapviewer", "mllpmode") + plugins.forEach { plugin -> + val pluginDir = file("$extensionsDir/$plugin") + if (pluginDir.exists()) { + ant.withGroovyBuilder { + "zip"("destfile" to "$distExtensionsDir/$plugin-${project.version}.zip", + "basedir" to extensionsDir, + "includes" to "$plugin/**/*") + } + } + } + } + + println("Extension zips created in server/dist/extensions/") + } +} + +// Prepare distribution directory with complete Mirth Connect structure +tasks.register("prepareDistribution") { + description = "Prepare the complete distribution directory structure" + dependsOn("orchestratorBuild", "createExtensionZips") + + doLast { + val distDir = file("server/dist") + val setupDir = file("server/setup") + + // Clean and create distribution directory + delete(distDir) + distDir.mkdirs() + + // Copy the complete setup directory structure + copy { + from(setupDir) + into(distDir) + } + + // Ensure all required directories exist + listOf( + "server-lib", "client-lib", "manager-lib", "cli-lib", "extensions", + "conf", "logs", "docs", "public_html", "public_api_html", "webapps" + ).forEach { dir -> + file("$distDir/$dir").mkdirs() + } + + // Copy documentation if it exists + val docsSource = file("server/docs") + if (docsSource.exists()) { + copy { + from(docsSource) + into("$distDir/docs") + } + } + + // Copy any additional configuration files + val confSource = file("server/conf") + if (confSource.exists()) { + copy { + from(confSource) + into("$distDir/conf") + } + } + + // Copy public HTML files + val publicHtmlSource = file("server/public_html") + if (publicHtmlSource.exists()) { + copy { + from(publicHtmlSource) + into("$distDir/public_html") + } + } + + // Copy public API HTML files + val publicApiHtmlSource = file("server/public_api_html") + if (publicApiHtmlSource.exists()) { + copy { + from(publicApiHtmlSource) + into("$distDir/public_api_html") + } + } + + // Create version info file + val versionFile = file("$distDir/VERSION.txt") + versionFile.writeText(""" + Mirth Connect ${project.version} + Build Date: ${LocalDateTime.now()} + + This distribution contains: + - Mirth Connect Server + - Mirth Connect Client + - Mirth Connect Manager + - Mirth Connect CLI + - WebAdmin Interface + - Extensions and Connectors + - Documentation + + For installation and usage instructions, see the docs/ directory. + """.trimIndent()) + + println("Distribution prepared in server/dist/") + println("Distribution contains:") + distDir.listFiles()?.forEach { file -> + if (file.isDirectory()) { + val fileCount = file.walkTopDown().filter { it.isFile() }.count() + println(" - ${file.name}/ ($fileCount files)") + } else { + println(" - ${file.name}") + } + } + } +} + +// Create TAR distribution +tasks.register("createTarDistribution") { + description = "Create .tar.gz distribution of Mirth Connect" + dependsOn("prepareDistribution") + + archiveFileName.set("mirth-connect-${project.version}.tar.gz") + destinationDirectory.set(file("build/distributions")) + compression = Compression.GZIP + + from("server/dist") { + into("mirth-connect-${project.version}") + } + + // Set executable permissions for launcher scripts + filesMatching("**/*.sh") { + mode = 0b111101101 // 0755 in octal + } + filesMatching("**/mirth-*launcher*.jar") { + mode = 0b111101101 // 0755 in octal + } + + doLast { + println("TAR distribution created: ${archiveFile.get().asFile}") + } +} + +// Create ZIP distribution +tasks.register("createZipDistribution") { + description = "Create .zip distribution of Mirth Connect" + dependsOn("prepareDistribution") + + archiveFileName.set("mirth-connect-${project.version}.zip") + destinationDirectory.set(file("build/distributions")) + + from("server/dist") { + into("mirth-connect-${project.version}") + } + + doLast { + println("ZIP distribution created: ${archiveFile.get().asFile}") + } +} + +// Main distribution task that creates both TAR and ZIP +tasks.register("dist") { + description = "Create complete Mirth Connect distributions (.tar.gz and .zip)" + dependsOn("createTarDistribution", "createZipDistribution") + + doLast { + println("=".repeat(60)) + println("Distribution creation completed successfully!") + println("Application version: ${project.version}") + println("") + println("Created distributions:") + val distDir = file("build/distributions") + distDir.listFiles()?.forEach { file -> + if (file.name.contains("mirth-connect")) { + val sizeInMB = String.format("%.2f", file.length() / (1024.0 * 1024.0)) + println(" - ${file.name} (${sizeInMB} MB)") + } + } + println("") + println("Distribution contents include:") + println(" - Mirth Connect Server with all libraries") + println(" - Mirth Connect Client application") + println(" - Mirth Connect Manager tool") + println(" - Mirth Connect CLI tool") + println(" - WebAdmin web interface") + println(" - All connectors and extensions") + println(" - Configuration files") + println(" - Documentation") + println(" - Public HTML and API documentation") + println("=".repeat(60)) + } +} + +// Distribution validation task +tasks.register("validateDistribution") { + description = "Validate that the distribution contains all required components" + dependsOn("prepareDistribution") + + doLast { + val distDir = file("server/dist") + val requiredFiles = listOf( + "mirth-server-launcher.jar", + "server-lib/mirth-server.jar", + "server-lib/mirth-client-core.jar", + "server-lib/mirth-crypto.jar", + "client-lib/mirth-client.jar", + "webapps/webadmin.war", + "conf" + ) + + val requiredDirs = listOf( + "server-lib", "client-lib", "manager-lib", "cli-lib", + "extensions", "conf", "docs", "public_html" + ) + + var validationPassed = true + + println("Validating distribution structure...") + + // Check required files + requiredFiles.forEach { filePath -> + val file = file("$distDir/$filePath") + if (file.exists()) { + println(" ✓ $filePath") + } else { + println(" ✗ $filePath (MISSING)") + validationPassed = false + } + } + + // Check required directories + requiredDirs.forEach { dirPath -> + val dir = file("$distDir/$dirPath") + if (dir.exists() && dir.isDirectory()) { + val fileCount = dir.walkTopDown().filter { it.isFile() }.count() + println(" ✓ $dirPath/ ($fileCount files)") + } else { + println(" ✗ $dirPath/ (MISSING)") + validationPassed = false + } + } + + if (validationPassed) { + println("✓ Distribution validation PASSED") + } else { + println("✗ Distribution validation FAILED") + throw GradleException("Distribution validation failed - missing required files or directories") + } + } +} + +// Add validation to distribution tasks +tasks.named("createTarDistribution") { + dependsOn("validateDistribution") +} + +tasks.named("createZipDistribution") { + dependsOn("validateDistribution") +} + +// Run tests across all modules +tasks.register("test-run") { + description = "Run tests across all modules" + dependsOn("initOrchestrator") + + doLast { + // Run tests for each module that has tests + listOf("donkey", "server", "client", "command").forEach { module -> + try { + val moduleProject = project(":$module") + val testTask = moduleProject.tasks.findByName("test") + if (testTask != null) { + println("Running tests for module: $module") + // Tests will be run via dependency, not direct execution + } else { + println("No test task found for module: $module") + } + } catch (e: Exception) { + println("Warning: Tests failed or not available for module: $module - ${e.message}") + } + } + } + + // Add test dependencies + dependsOn(":donkey:test", ":server:test") +} + +// Clean compiled classes across all modules +tasks.register("remove-classes") { + description = "Clean compiled classes across all modules" + dependsOn("initOrchestrator") + + doLast { + println("Cleaning compiled classes across all modules") + } + + // Add clean dependencies for all modules + dependsOn(subprojects.map { ":${it.name}:clean" }) +} + +// License header management +tasks.register("append-license") { + description = "Append license headers to source files" + dependsOn("initOrchestrator") + + doLast { + val licenseHeader = file("server/license-header.txt") + if (!licenseHeader.exists()) { + println("Warning: License header file not found at server/license-header.txt") + return@doLast + } + + val headerText = licenseHeader.readText() + + // Process each module's Java files + val moduleConfigs = mapOf( + "server" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to listOf("src/io/**/*.java", "src/org/**/*.java", "src/com/mirth/connect/server/logging/LogOutputStream.java") + ), + "client" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to listOf("src/com/mirth/connect/client/ui/BareBonesBrowserLaunch.java", "src/com/mirth/connect/client/ui/BeanBinder.java", "src/com/mirth/connect/client/ui/OSXAdapter.java", "src/org/**/*.java") + ), + "command" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to emptyList() + ), + "manager" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to listOf("src/com/mirth/connect/manager/BareBonesBrowserLaunch.java") + ), + "donkey" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to emptyList() + ), + "webadmin" to mapOf( + "includes" to listOf("**/*.java"), + "excludes" to emptyList() + ) + ) + + moduleConfigs.forEach { (module, config) -> + val moduleDir = file(module) + if (moduleDir.exists()) { + val javaFiles = fileTree(moduleDir) { + include(config["includes"] as List) + exclude(config["excludes"] as List) + }.filter { it.name.endsWith(".java") }.files + + javaFiles.forEach { javaFile -> + val content = javaFile.readText() + if (!content.startsWith("/*")) { + javaFile.writeText("$headerText\n$content") + } + } + + println("License headers processed for module: $module (${javaFiles.size} files)") + } + } + } +} + +// Build custom extensions +tasks.register("build-custom") { + description = "Build custom extensions" + dependsOn("initOrchestrator") + + doLast { + val customExtensionsFile = file("custom-extensions.xml") + if (customExtensionsFile.exists()) { + // This would require Ant integration or custom implementation + println("Custom extensions build would be executed here") + println("Note: custom-extensions.xml found but Ant integration needed for full implementation") + } else { + println("No custom-extensions.xml found, skipping custom extensions build") + } + } +} + +// Convenience task aliases matching original build targets +tasks.register("buildDonkey") { + description = "Alias for build-donkey" + dependsOn("build-donkey") +} + +tasks.register("buildWebadmin") { + description = "Alias for build-webadmin" + dependsOn("build-webadmin") +} + +tasks.register("buildServerExtensions") { + description = "Alias for build-server-extensions" + dependsOn("build-server-extensions") +} + +tasks.register("buildClient") { + description = "Alias for build-client" + dependsOn("build-client") +} + +tasks.register("buildManager") { + description = "Alias for build-manager" + dependsOn("build-manager") +} + +tasks.register("buildCli") { + description = "Alias for build-cli" + dependsOn("build-cli") +} + +tasks.register("testRun") { + description = "Alias for test-run" + dependsOn("test-run") +} + +tasks.register("removeClasses") { + description = "Alias for remove-classes" + dependsOn("remove-classes") +} + +tasks.register("appendLicense") { + description = "Alias for append-license" + dependsOn("append-license") +} + +tasks.register("buildCustom") { + description = "Alias for build-custom" + dependsOn("build-custom") +} + +// ============================================================================= +// LAUNCHER SCRIPTS AND ADDITIONAL DISTRIBUTION ENHANCEMENTS +// ============================================================================= + +// Create launcher scripts for different platforms +tasks.register("createLauncherScripts") { + description = "Create platform-specific launcher scripts" + dependsOn("prepareDistribution") + + doLast { + val distDir = file("server/dist") + + // Create Unix/Linux launcher script + val unixLauncher = file("$distDir/mirth-connect.sh") + unixLauncher.writeText(""" + #!/bin/bash + + # Mirth Connect Server Launcher Script + # Version: ${project.version} + + # Get the directory where this script is located + SCRIPT_DIR="$( cd "$( dirname "${'$'}{BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + + # Set MIRTH_HOME to the script directory + export MIRTH_HOME="${'$'}SCRIPT_DIR" + + # Set Java options + JAVA_OPTS="-Xms512m -Xmx2048m -XX:MaxMetaspaceSize=256m" + JAVA_OPTS="${'$'}JAVA_OPTS -Djava.awt.headless=true" + JAVA_OPTS="${'$'}JAVA_OPTS -Dmirth.home=${'$'}MIRTH_HOME" + + # Launch Mirth Connect + echo "Starting Mirth Connect ${project.version}..." + echo "MIRTH_HOME: ${'$'}MIRTH_HOME" + + java ${'$'}JAVA_OPTS -jar "${'$'}MIRTH_HOME/mirth-server-launcher.jar" + """.trimIndent()) + + // Create Windows launcher script + val windowsLauncher = file("$distDir/mirth-connect.bat") + windowsLauncher.writeText(""" + @echo off + + REM Mirth Connect Server Launcher Script + REM Version: ${project.version} + + REM Get the directory where this script is located + set SCRIPT_DIR=%~dp0 + + REM Set MIRTH_HOME to the script directory + set MIRTH_HOME=%SCRIPT_DIR% + + REM Set Java options + set JAVA_OPTS=-Xms512m -Xmx2048m -XX:MaxMetaspaceSize=256m + set JAVA_OPTS=%JAVA_OPTS% -Djava.awt.headless=true + set JAVA_OPTS=%JAVA_OPTS% -Dmirth.home=%MIRTH_HOME% + + REM Launch Mirth Connect + echo Starting Mirth Connect ${project.version}... + echo MIRTH_HOME: %MIRTH_HOME% + + java %JAVA_OPTS% -jar "%MIRTH_HOME%\mirth-server-launcher.jar" + """.trimIndent()) + + // Create CLI launcher scripts + val unixCliLauncher = file("$distDir/mirth-cli.sh") + unixCliLauncher.writeText(""" + #!/bin/bash + + # Mirth Connect CLI Launcher Script + # Version: ${project.version} + + # Get the directory where this script is located + SCRIPT_DIR="$( cd "$( dirname "${'$'}{BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + + # Set MIRTH_HOME to the script directory + export MIRTH_HOME="${'$'}SCRIPT_DIR" + + # Set Java options + JAVA_OPTS="-Xms256m -Xmx512m" + JAVA_OPTS="${'$'}JAVA_OPTS -Dmirth.home=${'$'}MIRTH_HOME" + + # Launch Mirth CLI + java ${'$'}JAVA_OPTS -jar "${'$'}MIRTH_HOME/mirth-cli-launcher.jar" "${'$'}@" + """.trimIndent()) + + val windowsCliLauncher = file("$distDir/mirth-cli.bat") + windowsCliLauncher.writeText(""" + @echo off + + REM Mirth Connect CLI Launcher Script + REM Version: ${project.version} + + REM Get the directory where this script is located + set SCRIPT_DIR=%~dp0 + + REM Set MIRTH_HOME to the script directory + set MIRTH_HOME=%SCRIPT_DIR% + + REM Set Java options + set JAVA_OPTS=-Xms256m -Xmx512m + set JAVA_OPTS=%JAVA_OPTS% -Dmirth.home=%MIRTH_HOME% + + REM Launch Mirth CLI + java %JAVA_OPTS% -jar "%MIRTH_HOME%\mirth-cli-launcher.jar" %* + """.trimIndent()) + + // Create Manager launcher scripts + val unixManagerLauncher = file("$distDir/mirth-manager.sh") + unixManagerLauncher.writeText(""" + #!/bin/bash + + # Mirth Connect Manager Launcher Script + # Version: ${project.version} + + # Get the directory where this script is located + SCRIPT_DIR="$( cd "$( dirname "${'$'}{BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + + # Set MIRTH_HOME to the script directory + export MIRTH_HOME="${'$'}SCRIPT_DIR" + + # Set Java options + JAVA_OPTS="-Xms256m -Xmx1024m" + JAVA_OPTS="${'$'}JAVA_OPTS -Dmirth.home=${'$'}MIRTH_HOME" + + # Launch Mirth Manager + java ${'$'}JAVA_OPTS -jar "${'$'}MIRTH_HOME/mirth-manager-launcher.jar" "${'$'}@" + """.trimIndent()) + + val windowsManagerLauncher = file("$distDir/mirth-manager.bat") + windowsManagerLauncher.writeText(""" + @echo off + + REM Mirth Connect Manager Launcher Script + REM Version: ${project.version} + + REM Get the directory where this script is located + set SCRIPT_DIR=%~dp0 + + REM Set MIRTH_HOME to the script directory + set MIRTH_HOME=%SCRIPT_DIR% + + REM Set Java options + set JAVA_OPTS=-Xms256m -Xmx1024m + set JAVA_OPTS=%JAVA_OPTS% -Dmirth.home=%MIRTH_HOME% + + REM Launch Mirth Manager + java %JAVA_OPTS% -jar "%MIRTH_HOME%\mirth-manager-launcher.jar" %* + """.trimIndent()) + + // Create README file + val readmeFile = file("$distDir/README.txt") + readmeFile.writeText(""" + Mirth Connect ${project.version} + ================================ + + Thank you for downloading Mirth Connect! + + QUICK START + ----------- + + 1. Server: + - Unix/Linux/Mac: ./mirth-connect.sh + - Windows: mirth-connect.bat + + 2. CLI: + - Unix/Linux/Mac: ./mirth-cli.sh + - Windows: mirth-cli.bat + + 3. Manager: + - Unix/Linux/Mac: ./mirth-manager.sh + - Windows: mirth-manager.bat + + 4. Web Admin: + - Access via http://localhost:8080/webadmin after starting the server + + DIRECTORY STRUCTURE + ------------------- + + server-lib/ - Server libraries and core JARs + client-lib/ - Client application libraries + manager-lib/ - Manager tool libraries + cli-lib/ - CLI tool libraries + extensions/ - Connectors, datatypes, and plugins + conf/ - Configuration files + docs/ - Documentation + public_html/ - Web interface files + webapps/ - Web applications (WebAdmin) + logs/ - Log files (created at runtime) + + SYSTEM REQUIREMENTS + ------------------- + + - Java 8 or higher + - Minimum 1GB RAM (2GB+ recommended) + - 500MB disk space for installation + - Network access for connectors + + CONFIGURATION + ------------- + + Main configuration file: conf/mirth.properties + Database configuration: conf/ + + For detailed installation and configuration instructions, + please refer to the documentation in the docs/ directory + or visit: https://www.nextgen.com/products-and-services/mirth-connect + + SUPPORT + ------- + + Community: https://github.com/nextgenhealthcare/connect + Documentation: docs/ directory + + """.trimIndent()) + + println("Launcher scripts created:") + println(" - mirth-connect.sh / mirth-connect.bat (Server)") + println(" - mirth-cli.sh / mirth-cli.bat (CLI)") + println(" - mirth-manager.sh / mirth-manager.bat (Manager)") + println(" - README.txt") + } +} + +// Enhanced distribution preparation that includes launcher scripts +tasks.named("prepareDistribution") { + finalizedBy("createLauncherScripts") +} + +// Create development distribution (without signing, faster build) +tasks.register("distDev") { + description = "Create development distribution (faster, no signing)" + dependsOn("orchestratorBuild") + + doFirst { + // Set a property to skip signing for development builds + project.extra["skipSigning"] = true + } + + finalizedBy("dist") + + doLast { + println("Development distribution created (signing skipped for faster build)") + } +} + +// Create checksums for distributions +tasks.register("createDistributionChecksums") { + description = "Create SHA-256 checksums for distribution files" + dependsOn("dist") + + doLast { + val distDir = file("build/distributions") + distDir.listFiles()?.filter { + it.name.endsWith(".tar.gz") || it.name.endsWith(".zip") + }?.forEach { distFile -> + val checksumFile = file("${distFile.absolutePath}.sha256") + val checksum = MessageDigest.getInstance("SHA-256") + .digest(distFile.readBytes()) + .joinToString("") { byte -> "%02x".format(byte) } + + checksumFile.writeText("$checksum ${distFile.name}\n") + println("Created checksum: ${checksumFile.name}") + } + } +} + +// Complete distribution with checksums +tasks.register("distComplete") { + description = "Create complete distribution with checksums" + dependsOn("dist", "createDistributionChecksums") + + doLast { + println("Complete distribution with checksums created successfully!") + } +} + +// Clean distribution files +tasks.register("cleanDist") { + description = "Clean distribution files and directories" + + doLast { + delete("server/dist") + delete("build/distributions") + println("Distribution files cleaned") + } +} + +// Add cleanDist to main clean task +tasks.named("clean") { + dependsOn("cleanDist") +} + +// ============================================================================= +// CONVENIENCE TASKS FOR COMMON WORKFLOWS +// ============================================================================= + +// Quick build and test +tasks.register("quickBuild") { + description = "Quick build without tests for development" + dependsOn("orchestratorBuild") + + doLast { + println("Quick build completed (tests skipped)") + } +} + +// Full build with tests and distribution +tasks.register("fullBuild") { + description = "Complete build with tests and distribution" + dependsOn("build", "test-run", "dist") + + doLast { + println("Full build with tests and distribution completed!") + } +} + +// Show build information +tasks.register("buildInfo") { + description = "Display comprehensive build information" + + doLast { + println("=".repeat(60)) + println("MIRTH CONNECT BUILD INFORMATION") + println("=".repeat(60)) + println("Project: ${rootProject.name}") + println("Version: ${rootProject.version}") + println("Group: ${rootProject.group}") + println("Java Version: ${System.getProperty("java.version")}") + println("Gradle Version: ${gradle.gradleVersion}") + println("") + println("Available Modules:") + subprojects.forEach { project -> + println(" - ${project.name}") + } + println("") + println("Key Build Tasks:") + println(" ./gradlew build - Complete build") + println(" ./gradlew quickBuild - Fast build (no tests)") + println(" ./gradlew fullBuild - Build + tests + distribution") + println(" ./gradlew dist - Create distributions") + println(" ./gradlew distDev - Fast development distribution") + println(" ./gradlew distComplete - Distribution with checksums") + println(" ./gradlew test-run - Run all tests") + println(" ./gradlew clean - Clean all build artifacts") + println("") + println("Distribution Tasks:") + println(" ./gradlew createTarDistribution - Create .tar.gz") + println(" ./gradlew createZipDistribution - Create .zip") + println(" ./gradlew validateDistribution - Validate distribution") + println("=".repeat(60)) + } +} \ No newline at end of file diff --git a/client/.classpath b/client/.classpath deleted file mode 100644 index ebaff99648..0000000000 --- a/client/.classpath +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/.project b/client/.project deleted file mode 100644 index 26fbc4505e..0000000000 --- a/client/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Client - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/client/build.gradle.kts b/client/build.gradle.kts new file mode 100644 index 0000000000..44993a8f39 --- /dev/null +++ b/client/build.gradle.kts @@ -0,0 +1,208 @@ +plugins { + java + application +} + +// Configure application plugin +application { + mainClass.set("com.mirth.connect.client.ui.Frame") + applicationDefaultJvmArgs = listOf("-Xms512m", "-Xmx2048m") +} + +// Project dependencies +dependencies { + // Donkey dependency - use the JAR output instead of project dependency to avoid transitive deps + implementation(files("../donkey/setup/donkey-model.jar")) + + // Server core dependencies - needed for client compilation + implementation(files("../server/setup/server-lib/mirth-client-core.jar")) + implementation(files("../server/setup/server-lib/mirth-crypto.jar")) + + // Flat directory repository for client/lib dependencies + implementation(fileTree("lib") { include("*.jar") }) + + // Dependencies from server extensions (needed for client compilation) + implementation(fileTree("../server/build/extensions") { include("**/*.jar") }) + + // Test dependencies + testImplementation(fileTree("../server/testlib") { include("*.jar") }) +} + +// Make sure donkey JAR and server core JARs are built before client compilation +tasks.compileJava { + dependsOn(":donkey:donkeyModelJar") + dependsOn(":server:createClientCoreJar") + dependsOn(":server:createCryptoJar") + dependsOn(":server:copySetupFiles") + dependsOn(":server:copyExtensionsToSetup") + dependsOn(":server:createVocabJar") +} + +// Source sets configuration +sourceSets { + main { + java { + srcDirs("src") + } + resources { + srcDirs("src") + include("**/*.properties", "**/*.html", "**/*.css", "**/*.js", "**/*.form", "**/*.png") + } + } + test { + java { + srcDirs("test") + } + } +} + +// Application configuration +application { + mainClass.set("com.mirth.connect.client.ui.Frame") +} + +// Create setup directories +val createClientSetupDirs by tasks.registering { + doLast { + listOf( + "dist", + "dist/extensions" + ).forEach { dir -> + file(dir).mkdirs() + } + } +} + +// Main client JAR task +val createClientJar by tasks.registering(Jar::class) { + dependsOn(tasks.classes, createClientSetupDirs) + archiveFileName.set("mirth-client.jar") + destinationDirectory.set(file("dist")) + from(sourceSets.main.get().output) + + // Exclude connector classes (they go into separate extension JARs) + exclude("com/mirth/connect/connectors/**") + // Include only the base ConnectorClass + include("com/mirth/connect/connectors/ConnectorClass.class") + include("com/mirth/connect/client/**") + include("com/mirth/connect/plugins/**") + include("org/**") + + manifest { + attributes( + "Main-Class" to "com.mirth.connect.client.ui.Mirth" + ) + } +} + +// Connector names for client extension JARs +val connectorNames = listOf("dicom", "jdbc", "jms", "http", "doc", "smtp", "tcp", "file", "js", "ws", "vm") + +// Create connector client extension JARs +val connectorTasks = mutableListOf>() + +connectorNames.forEach { connectorName -> + val createConnectorClientJar = tasks.register("create${connectorName.capitalize()}ClientJar") { + dependsOn(tasks.classes, createClientSetupDirs) + archiveFileName.set("${connectorName}-client.jar") + destinationDirectory.set(file("dist/extensions/${connectorName}")) + from(sourceSets.main.get().output) + + when (connectorName) { + "dicom" -> include("com/mirth/connect/connectors/dimse/**") + "jdbc" -> include("com/mirth/connect/connectors/jdbc/**") + "jms" -> include("com/mirth/connect/connectors/jms/**") + "http" -> include("com/mirth/connect/connectors/http/**") + "doc" -> include("com/mirth/connect/connectors/doc/**") + "smtp" -> include("com/mirth/connect/connectors/smtp/**") + "tcp" -> include("com/mirth/connect/connectors/tcp/**") + "file" -> include("com/mirth/connect/connectors/file/**") + "js" -> include("com/mirth/connect/connectors/js/**") + "ws" -> include("com/mirth/connect/connectors/ws/**") + "vm" -> include("com/mirth/connect/connectors/vm/**") + } + } + connectorTasks.add(createConnectorClientJar) +} + +// Datatype names for client extension JARs +val datatypeNames = listOf("delimited", "dicom", "edi", "hl7v2", "hl7v3", "ncpdp", "xml", "raw", "json") + +// Create datatype client extension JARs +val datatypeTasks = mutableListOf>() + +datatypeNames.forEach { datatypeName -> + val createDatatypeClientJar = tasks.register("createDatatype${datatypeName.capitalize()}ClientJar") { + dependsOn(tasks.classes, createClientSetupDirs) + archiveFileName.set("datatype-${datatypeName}-client.jar") + destinationDirectory.set(file("dist/extensions/datatype-${datatypeName}")) + from(sourceSets.main.get().output) + include("com/mirth/connect/plugins/datatypes/${datatypeName}/**") + } + datatypeTasks.add(createDatatypeClientJar) +} + +// Plugin names for client extension JARs +val pluginNames = listOf( + "directoryresource", "dashboardstatus", "destinationsetfilter", "dicomviewer", + "extensionmanager", "httpauth", "imageviewer", "javascriptrule", "javascriptstep", + "mapper", "messagebuilder", "datapruner", "globalmapviewer", "mllpmode", + "pdfviewer", "textviewer", "rulebuilder", "serverlog", "scriptfilerule", + "scriptfilestep", "xsltstep" +) + +// Create plugin client extension JARs +val pluginTasks = mutableListOf>() + +pluginNames.forEach { pluginName -> + val createPluginClientJar = tasks.register("create${pluginName.capitalize()}ClientJar") { + dependsOn(tasks.classes, createClientSetupDirs) + archiveFileName.set("${pluginName}-client.jar") + destinationDirectory.set(file("dist/extensions/${pluginName}")) + from(sourceSets.main.get().output) + include("com/mirth/connect/plugins/${pluginName}/**") + } + pluginTasks.add(createPluginClientJar) +} + +// Copy shared extension JARs from server build (when available) +val copySharedExtensionJars by tasks.registering(Copy::class) { + dependsOn(":server:copyExtensionsToSetup") + from("../server/build/extensions") { + include("**/*-shared.jar") + } + into("dist/extensions") + // Only copy if the source directory exists + onlyIf { file("../server/build/extensions").exists() } +} + +// Main build task +val buildClient by tasks.registering { + dependsOn( + createClientJar, + connectorTasks, + datatypeTasks, + pluginTasks, + copySharedExtensionJars + ) +} + +// Test tasks +tasks.test { + dependsOn(buildClient) + useJUnit() + testLogging { + events("passed", "skipped", "failed") + } +} + +// Main build task +tasks.build { + dependsOn(buildClient) +} + +// Run task for the client application +tasks.named("run") { + dependsOn(buildClient) + systemProperty("java.library.path", "lib") +} \ No newline at end of file diff --git a/command/.classpath b/command/.classpath deleted file mode 100644 index e3b787ac0b..0000000000 --- a/command/.classpath +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/command/.project b/command/.project deleted file mode 100644 index e0884d3e51..0000000000 --- a/command/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Command - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/command/build.gradle.kts b/command/build.gradle.kts new file mode 100644 index 0000000000..4927e7409b --- /dev/null +++ b/command/build.gradle.kts @@ -0,0 +1,138 @@ +plugins { + java + application +} + +repositories { + // Add donkey's lib directories for transitive dependencies + flatDir { + dirs("../donkey/lib", "../donkey/lib/commons", "../donkey/lib/database", "../donkey/lib/guava", "../donkey/lib/xstream") + } + // Add server's lib directories for transitive dependencies + flatDir { + dirs("../server/lib", "../server/lib/commons", "../server/lib/database", "../server/lib/extensions") + } +} + +application { + mainClass.set("com.mirth.connect.cli.launcher.CommandLineLauncher") +} + +dependencies { + // Project dependencies + implementation(project(":donkey")) + implementation(project(":server")) + implementation(project(":client")) + + // Local lib dependencies + implementation(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar")))) + + // Test dependencies + testImplementation(fileTree(mapOf("dir" to "testlib", "include" to listOf("*.jar")))) +} + +// Ensure donkey JARs are built and copied before command compilation +tasks.compileJava { + dependsOn(":donkey:copyToServer", ":server:copyEdiXmlFiles") +} + +// Fix task dependencies for distribution tasks +tasks.named("startScripts") { + dependsOn(":donkey:copyToServer") + dependsOn(":server:createVocabJar") +} + +tasks.named("distTar") { + dependsOn(":donkey:copyToServer") +} + +tasks.named("distZip") { + dependsOn(":donkey:copyToServer") +} + +sourceSets { + main { + java { + srcDirs("src") + } + } + test { + java { + srcDirs("test") + } + } +} + +// Create CLI JAR (without launcher) +tasks.register("cliJar") { + archiveFileName.set("mirth-cli.jar") + from(sourceSets.main.get().output) + include("com/mirth/connect/cli/**") + exclude("com/mirth/connect/cli/launcher/**") +} + +// Create CLI Launcher JAR +tasks.register("cliLauncherJar") { + archiveFileName.set("mirth-cli-launcher.jar") + from(sourceSets.main.get().output) + include("com/mirth/connect/cli/launcher/**") + + manifest { + attributes( + "Main-Class" to "com.mirth.connect.cli.launcher.CommandLineLauncher", + "Class-Path" to "cli-lib/log4j-api-2.17.2.jar cli-lib/log4j-core-2.17.2.jar cli-lib/commons-io-2.13.0.jar conf/" + ) + } +} + +// Copy configuration files +tasks.register("copyConf", Copy::class) { + from("conf") + into("${buildDir}/libs/conf") +} + +// Copy CLI libraries +tasks.register("copyCliLibs", Copy::class) { + from("lib") + into("${buildDir}/libs/cli-lib") + include("*.jar") +} + +// Copy project dependencies to cli-lib +tasks.register("copyDependencies", Copy::class) { + dependsOn(":donkey:copyToServer") + from(configurations.runtimeClasspath) + into("${buildDir}/libs/cli-lib") + include("*.jar") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +tasks.register("dist") { + dependsOn("cliJar", "cliLauncherJar", "copyConf", "copyCliLibs", "copyDependencies") + description = "Build CLI distribution with all components" + + doLast { + copy { + from(tasks.named("cliJar").get().outputs.files) + from(tasks.named("cliLauncherJar").get().outputs.files) + into("${buildDir}/libs") + } + } +} + +tasks.named("build") { + dependsOn("dist") +} + +// Disable the default jar task since we have custom jars +tasks.jar { + enabled = false +} + +// Test configuration +tasks.test { + useJUnit() + testLogging { + events("passed", "skipped", "failed") + } +} \ No newline at end of file diff --git a/donkey/.classpath b/donkey/.classpath deleted file mode 100644 index 54b8cc9972..0000000000 --- a/donkey/.classpath +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/donkey/.project b/donkey/.project deleted file mode 100644 index e2a5d1be04..0000000000 --- a/donkey/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Donkey - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/donkey/build.gradle.kts b/donkey/build.gradle.kts new file mode 100644 index 0000000000..7ce916b780 --- /dev/null +++ b/donkey/build.gradle.kts @@ -0,0 +1,216 @@ +plugins { + java + jacoco +} + +// Configure repositories to include lib subdirectories +repositories { + mavenCentral() + flatDir { + dirs("lib", "lib/commons", "lib/database", "lib/guava", "lib/xstream") + } + flatDir { + dirs("testlib") + } +} + +// Configure source sets to match existing structure +sourceSets { + main { + java { + srcDirs("src/main/java") + } + resources { + srcDirs("donkeydbconf") + } + } + test { + java { + srcDirs("src/test/java") + } + resources { + srcDirs("src/test/resources", "conf") + } + } +} + +// Dependencies from lib folder using flatDir repository +dependencies { + // Core dependencies from lib root + implementation(":guice-4.1.0") + implementation(":HikariCP-2.5.1") + implementation(":javassist-3.26.0-GA") + implementation(":quartz-2.3.2") + + // Commons dependencies + implementation(":commons-beanutils-1.9.4") + implementation(":commons-codec-1.16.0") + implementation(":commons-collections4-4.4") + implementation(":commons-dbcp2-2.0.1") + implementation(":commons-dbutils-1.7") + implementation(":commons-io-2.13.0") + implementation(":commons-lang3-3.13.0") + implementation(":commons-logging-1.2") + implementation(":commons-math3-3.0") + implementation(":commons-pool2-2.3") + + // Database drivers + implementation(":derby-10.10.2.0") + implementation(":jtds-1.3.1") + implementation(":mssql-jdbc-8.4.1.jre8") + implementation(":mysql-connector-j-8.2.0") + implementation(":ojdbc8-12.2.0.1") + implementation(":postgresql-42.6.0") + + // Guava dependencies + implementation(":checker-qual-2.10.0") + implementation(":error_prone_annotations-2.3.4") + implementation(":failureaccess-1.0.1") + implementation(":guava-28.2-jre") + implementation(":j2objc-annotations-1.3") + implementation(":jsr305-3.0.2") + implementation(":listenablefuture-9999.0-empty-to-avoid-conflict-with-guava") + + // XStream dependencies + implementation(":xpp3-1.1.4c") + implementation(":xstream-1.4.20") + + // Test dependencies + testImplementation(":junit-4.8.1") + testImplementation(":mockito-core-2.7.9") + testImplementation(":byte-buddy-1.8.8") + testImplementation(":byte-buddy-agent-1.8.8") + testImplementation(":objenesis-2.5.1") + testImplementation(":aopalliance-repackaged-2.4.0-b31") + testImplementation(":javax.inject-2.4.0-b31") +} + +// Create donkey-model.jar task +tasks.register("donkeyModelJar") { + archiveBaseName.set("donkey-model") + archiveVersion.set("") + destinationDirectory.set(file("setup")) + + from(sourceSets.main.get().output) { + include("com/mirth/connect/donkey/model/**") + include("com/mirth/connect/donkey/util/**") + } +} + +// Create donkey-server.jar task +tasks.register("donkeyServerJar") { + archiveBaseName.set("donkey-server") + archiveVersion.set("") + destinationDirectory.set(file("setup")) + + from(sourceSets.main.get().output) { + include("com/mirth/connect/donkey/server/**") + include("com/mirth/connect/donkey/model/**") + include("com/mirth/connect/donkey/util/**") + } + + // Include donkeydbconf resources + from("donkeydbconf") +} + +// Create setup directory and copy libs +tasks.register("createSetup") { + dependsOn("donkeyModelJar", "donkeyServerJar") + + from("lib") + into("setup/lib") + + doFirst { + file("setup").mkdirs() + file("setup/lib").mkdirs() + file("setup/docs").mkdirs() + } +} + +// Copy docs to setup +tasks.register("copyDocs") { + from("docs") + into("setup/docs") +} + +// Copy donkey JARs to server/lib/donkey (mimicking Ant build behavior) +tasks.register("copyToServer") { + dependsOn("donkeyModelJar", "donkeyServerJar") + + // Copy the JAR files + from("setup") { + include("donkey-model.jar") + include("donkey-server.jar") + } + into("../server/lib/donkey") + + // Copy lib dependencies with exclusions + from("lib") { + exclude("log4j-1.2.16.jar") + exclude("HikariCP-java6-2.0.1.jar") + exclude("javassist-3.19.0-GA.jar") + exclude("xstream/**") + exclude("commons/**") + exclude("database/**") + } + into("../server/lib/donkey") + + doFirst { + delete("../server/lib/donkey") + file("../server/lib/donkey").mkdirs() + } +} + +// Main build task +tasks.named("build") { + dependsOn("createSetup", "copyDocs", "copyToServer") +} + +// Clean task +tasks.named("clean") { + doLast { + delete("setup") + delete("classes") + delete("test_classes") + } +} + +// Test configuration +tasks.test { + useJUnit() + + // JVM arguments for tests + jvmArgs("-Xms128m", "-Xmx2048m") + + testLogging { + events("passed", "skipped", "failed") + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + } + + // Generate test reports + reports { + junitXml.required.set(true) + html.required.set(true) + } + + finalizedBy(tasks.jacocoTestReport) +} + +// JaCoCo configuration +tasks.jacocoTestReport { + dependsOn(tasks.test) + + reports { + xml.required.set(true) + html.required.set(true) + csv.required.set(false) + } + + // Configure output directories + executionData.setFrom(fileTree(layout.buildDirectory.dir("jacoco")).include("**/*.exec")) +} + +// Configure JaCoCo test coverage +jacoco { + toolVersion = "0.8.7" +} \ No newline at end of file diff --git a/generator/.classpath b/generator/.classpath deleted file mode 100644 index cb075c277e..0000000000 --- a/generator/.classpath +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/generator/.project b/generator/.project deleted file mode 100644 index 2c663857ca..0000000000 --- a/generator/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Generator - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/generator/build.gradle.kts b/generator/build.gradle.kts new file mode 100644 index 0000000000..f2a7e936d3 --- /dev/null +++ b/generator/build.gradle.kts @@ -0,0 +1,103 @@ +plugins { + java + application +} + +application { + mainClass.set("com.mirth.connect.model.generator.HL7ModelGenerator") +} + +dependencies { + // Local lib dependencies - exclude problematic SLF4J jar + implementation(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar"), "exclude" to listOf("slf4j-log4j12-*.jar")))) + + // Use only one SLF4J binding - prefer the one from root project + implementation("org.slf4j:slf4j-api:1.7.30") + implementation("org.slf4j:slf4j-log4j12:1.7.30") +} + +sourceSets { + main { + java { + srcDirs("src") + exclude("**/test/**") + } + } +} + +// Create the model generator JAR +tasks.jar { + archiveFileName.set("model-generator.jar") + from(sourceSets.main.get().output) +} + +// Task to generate vocabulary source code +tasks.register("generateVocabSource") { + dependsOn("jar") + description = "Generate HL7 vocabulary source code" + + classpath = configurations.runtimeClasspath.get() + files("${buildDir}/libs/model-generator.jar") + mainClass.set("com.mirth.connect.model.generator.HL7ModelGenerator") + + args("reference", "${buildDir}/vocab/src", "templates") + + doFirst { + file("${buildDir}/vocab/src").mkdirs() + } +} + +// Compile generated vocabulary source +tasks.register("compileVocab") { + dependsOn("generateVocabSource") + description = "Compile generated vocabulary classes" + + source = fileTree("${buildDir}/vocab/src") + destinationDirectory.set(file("${buildDir}/vocab/classes")) + classpath = files("${buildDir}/libs/model-generator.jar") + + doFirst { + file("${buildDir}/vocab/classes").mkdirs() + } +} + +// Create vocabulary JAR +tasks.register("vocabJar") { + dependsOn("compileVocab") + description = "Create vocabulary JAR" + + archiveFileName.set("mirth-vocab-1.2.jar") + from("${buildDir}/vocab/classes") + from(sourceSets.main.get().output) { + include("**/hl7v2/**/*.class") + } + + destinationDirectory.set(file("${buildDir}/vocab/dist")) + + doFirst { + file("${buildDir}/vocab/dist").mkdirs() + } +} + +// Main distribution task +tasks.register("dist") { + dependsOn("jar", "vocabJar") + description = "Build complete distribution including vocabulary" +} + +tasks.named("build") { + dependsOn("dist") +} + +// Configure distribution tasks to handle duplicates +tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +// Clean task to remove vocab directory +tasks.clean { + delete("${buildDir}/vocab") +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..6dacef281c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,31 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties + +# Temporarily disable configuration cache due to compatibility issues with Gradle 8.14 +# This will be re-enabled once all configuration cache problems are resolved +org.gradle.configuration-cache=false + +# Project Information +org.gradle.project.name=OIE +org.gradle.project.group=com.mirth.connect +org.gradle.project.version=4.5.2 + +# Gradle Configuration +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=false +org.gradle.configureondemand=false + +# JVM Configuration +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError + +# Java Configuration +java.sourceCompatibility=1.8 +java.targetCompatibility=1.8 + +# Build Configuration +build.encoding=UTF-8 + +# Test Configuration +test.maxParallelForks=4 +test.forkEvery=100 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..4ac3234a6a --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,2 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..afba109285 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..3c44eb1b6f --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..65dcd68d65 --- /dev/null +++ b/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..93e3f59f13 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/manager/.classpath b/manager/.classpath deleted file mode 100644 index 391b7aba01..0000000000 --- a/manager/.classpath +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/manager/.project b/manager/.project deleted file mode 100644 index c6e58661fd..0000000000 --- a/manager/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Manager - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts new file mode 100644 index 0000000000..bfaa6bdc61 --- /dev/null +++ b/manager/build.gradle.kts @@ -0,0 +1,121 @@ +plugins { + java + application +} + +repositories { + flatDir { + dirs("lib") + } + // Add donkey's lib directories for transitive dependencies + flatDir { + dirs("../donkey/lib", "../donkey/lib/commons", "../donkey/lib/database", "../donkey/lib/guava", "../donkey/lib/xstream") + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +// Configure duplicate handling for distribution tasks +tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +application { + mainClass.set("com.mirth.connect.manager.Manager") +} + +dependencies { + // Project dependencies + implementation(project(":donkey")) + implementation(project(":server")) + implementation(project(":client")) + + // Local lib dependencies + implementation(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar")))) +} + +sourceSets { + main { + java { + srcDirs("src") + } + resources { + srcDirs("src") + include("**/*.properties", "**/*.png", "**/*.jpg", "**/*.gif") + } + } +} + +tasks.jar { + // Add explicit dependency on donkey copyToServer task + dependsOn(":donkey:copyToServer") + archiveFileName.set("mirth-manager-launcher.jar") + + manifest { + attributes( + "Main-Class" to "com.mirth.connect.manager.Manager", + "Class-Path" to configurations.runtimeClasspath.get().files + .filter { it.name.endsWith(".jar") } + .joinToString(" ") { "manager-lib/${it.name}" } + ) + } +} + +tasks.register("copyDependencies", Copy::class) { + dependsOn(":donkey:copyToServer") + from(configurations.runtimeClasspath) + into("${buildDir}/libs/manager-lib") + include("*.jar") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +tasks.register("copyLibs", Copy::class) { + from("lib") + into("${buildDir}/libs/manager-lib") + include("*.jar") +} + +tasks.register("dist") { + dependsOn("jar", "copyDependencies", "copyLibs") + description = "Build distribution with all dependencies" +} + +tasks.named("build") { + dependsOn("dist") +} + +// Add explicit dependencies for compilation tasks +tasks.compileJava { + dependsOn(":donkey:copyToServer") + dependsOn(":server:copyEdiXmlFiles") +} + +// Add explicit dependencies for distribution tasks +tasks.withType { + dependsOn(":donkey:copyToServer") + dependsOn(":server:createVocabJar") +} + +tasks.withType { + dependsOn(":donkey:copyToServer") +} + +tasks.withType { + dependsOn(":donkey:copyToServer") +} + +// Copy log4j2.properties and images to classes +tasks.processResources { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from("src") { + include("log4j2.properties") + include("**/images/**") + } +} \ No newline at end of file diff --git a/server/.classpath b/server/.classpath deleted file mode 100644 index 4c107334c3..0000000000 --- a/server/.classpath +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/server/.project b/server/.project deleted file mode 100644 index d4d4f9ae99..0000000000 --- a/server/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Server - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/server/build.gradle.kts b/server/build.gradle.kts new file mode 100644 index 0000000000..3e71bb8a6b --- /dev/null +++ b/server/build.gradle.kts @@ -0,0 +1,849 @@ +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +plugins { + java + `java-library` +} + +// Configure repositories to include lib subdirectories +repositories { + mavenCentral() + flatDir { + dirs("../donkey/lib", "../donkey/lib/commons", "../donkey/lib/database", "../donkey/lib/guava") + } +} + +// Project dependencies +dependencies { + implementation(project(":donkey")) + + // Flat directory repository for server/lib dependencies + implementation(fileTree("lib") { include("*.jar") }) + implementation(fileTree("lib/commons") { include("*.jar") }) + implementation(fileTree("lib/database") { include("*.jar") }) + implementation(fileTree("lib/aws") { include("*.jar") }) + implementation(fileTree("lib/aws/ext") { include("*.jar") }) + implementation(fileTree("lib/aws/ext/netty") { include("*.jar") }) + implementation(fileTree("lib/hapi") { include("*.jar") }) + implementation(fileTree("lib/jackson") { include("*.jar") }) + implementation(fileTree("lib/javax") { include("*.jar") }) + implementation(fileTree("lib/javax/jaxb") { include("*.jar") }) + implementation(fileTree("lib/javax/jaxb/ext") { include("*.jar") }) + implementation(fileTree("lib/javax/jaxws") { include("*.jar") }) + implementation(fileTree("lib/javax/jaxws/ext") { include("*.jar") }) + implementation(fileTree("lib/jersey") { include("*.jar") }) + implementation(fileTree("lib/jersey/ext") { include("*.jar") }) + implementation(fileTree("lib/jetty") { include("*.jar") }) + implementation(fileTree("lib/jetty/jsp") { include("*.jar") }) + implementation(fileTree("lib/jms") { include("*.jar") }) + implementation(fileTree("lib/log4j") { include("*.jar") }) + implementation(fileTree("lib/swagger") { include("*.jar") }) + implementation(fileTree("lib/swagger/ext") { include("*.jar") }) + implementation(fileTree("lib/extensions/dimse") { include("*.jar") }) + implementation(fileTree("lib/extensions/doc") { include("*.jar") }) + implementation(fileTree("lib/extensions/file") { include("*.jar") }) + implementation(fileTree("lib/extensions/ws") { include("*.jar") }) + implementation(fileTree("lib/extensions/dicomviewer") { include("*.jar") }) + + // Donkey lib dependencies (needed for Guava and other shared libs) + implementation(fileTree("lib/donkey") { include("*.jar") }) + implementation(fileTree("lib/donkey/guava") { include("*.jar") }) + + // Test dependencies + testImplementation(fileTree("testlib") { include("*.jar") }) + testImplementation(project(":donkey")) +} + +// Source sets configuration +sourceSets { + main { + java { + srcDirs("src") + } + resources { + srcDirs("src") + include("**/*.js", "**/*.txt", "**/*.xml", "**/*.properties") + } + } + test { + java { + srcDirs("test") + } + resources { + srcDirs("test") + include("**/*.xml") + } + } +} + +// Custom task to create version.properties +val createVersionProperties by tasks.registering { + // Capture project version during configuration time + val projectVersion = version.toString() + val buildDate = LocalDate.now().format(DateTimeFormatter.ofPattern("MMMM d, yyyy")) + + doLast { + val versionFile = File(projectDir, "version.properties") + versionFile.writeText(""" + mirth.version=${projectVersion} + mirth.date=${buildDate} + """.trimIndent()) + } +} + +// Compile task depends on version properties +tasks.compileJava { + dependsOn(createVersionProperties) + // Add explicit dependency on donkey copyToServer task + dependsOn(":donkey:copyToServer") +} + +// Copy version.properties and other resources to classes +tasks.processResources { + dependsOn(createVersionProperties) + from("version.properties") + from("mirth-client.jnlp") +} + +// Create setup directories +val createSetupDirs by tasks.registering { + doLast { + listOf( + "setup", + "setup/conf", + "setup/extensions", + "setup/public_html", + "setup/public_api_html", + "setup/server-lib", + "setup/client-lib", + "setup/manager-lib", + "setup/cli-lib", + "setup/logs", + "setup/docs", + "setup/server-launcher-lib", + "setup/webapps", + "build/extensions" + ).forEach { dir -> + File(projectDir, dir).mkdirs() + } + } +} + +// Crypto JAR task +val createCryptoJar by tasks.registering(Jar::class) { + dependsOn(tasks.classes) + archiveFileName.set("mirth-crypto.jar") + destinationDirectory.set(File(projectDir, "setup/server-lib")) + from(sourceSets.main.get().output) + include("com/mirth/commons/encryption/**") +} + +// Client Core JAR task +val createClientCoreJar by tasks.registering(Jar::class) { + dependsOn(tasks.classes, createCryptoJar) + archiveFileName.set("mirth-client-core.jar") + destinationDirectory.set(File(projectDir, "setup/server-lib")) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(sourceSets.main.get().output) + include("com/mirth/connect/client/core/**") + include("com/mirth/connect/model/**") + include("com/mirth/connect/userutil/**") + include("com/mirth/connect/util/**") + include("com/mirth/connect/server/util/ResourceUtil.class") + include("com/mirth/connect/server/util/DebuggerUtil.class") + include("org/mozilla/**") + include("org/glassfish/jersey/**") + include("de/**") + include("net/lingala/zip4j/unzip/**") + include("version.properties") +} + +// Server JAR task +val createServerJar by tasks.registering(Jar::class) { + dependsOn(tasks.classes, createClientCoreJar) + archiveFileName.set("mirth-server.jar") + destinationDirectory.set(File(projectDir, "setup/server-lib")) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(sourceSets.main.get().output) + include("com/mirth/connect/server/**") + include("com/mirth/connect/model/**") + include("com/mirth/connect/util/**") + include("com/mirth/connect/plugins/*.class") + include("com/mirth/connect/connectors/*.class") + include("org/**") + include("net/sourceforge/jtds/ssl/**") + include("mirth-client.jnlp") + exclude("com/mirth/connect/server/launcher/**") + exclude("org/dcm4che2/**") +} + +// Vocab JAR task (if mirth-vocab.jar exists in lib) +val createVocabJar by tasks.registering(Copy::class) { + from(File(projectDir, "lib/mirth-vocab.jar")) + into(File(projectDir, "setup/server-lib")) +} + +// DBConf JAR task +val createDbconfJar by tasks.registering(Jar::class) { + archiveFileName.set("mirth-dbconf.jar") + destinationDirectory.set(File(projectDir, "setup/server-lib")) + from(File(projectDir, "dbconf")) +} + +// Launcher JAR task +val createLauncherJar by tasks.registering(Jar::class) { + dependsOn(tasks.classes) + archiveFileName.set("mirth-server-launcher.jar") + destinationDirectory.set(File(projectDir, "setup")) + from(sourceSets.main.get().output) + include("com/mirth/connect/server/launcher/**") + include("com/mirth/connect/server/extprops/**") + manifest { + attributes( + "Main-Class" to "com.mirth.connect.server.launcher.MirthLauncher", + "Class-Path" to "server-lib/commons/commons-io-2.13.0.jar server-lib/commons/commons-configuration2-2.8.0.jar server-lib/commons/commons-lang3-3.13.0.jar server-lib/commons/commons-logging-1.2.jar server-lib/commons/commons-beanutils-1.9.4.jar server-lib/commons/commons-text-1.10.0.jar server-lib/commons/commons-collections-3.2.2.jar conf/" + ) + } +} + +// UserUtil Sources JAR task +val createUserutilSourcesJar by tasks.registering(Jar::class) { + archiveFileName.set("userutil-sources.jar") + destinationDirectory.set(File(projectDir, "setup/client-lib")) + from(File(projectDir, "src")) + include("com/mirth/connect/userutil/**/*.java") + include("com/mirth/connect/server/userutil/**/*.java") + exclude("**/package-info.java") +} + +// Connector JAR creation tasks +val connectorNames = listOf("dicom", "doc", "file", "http", "jdbc", "jms", "js", "smtp", "tcp", "vm", "ws") + +// Create connector tasks +val connectorTasks = mutableListOf>() + +connectorNames.forEach { connectorName -> + val createConnectorSharedJar = tasks.register("create${connectorName.capitalize()}SharedJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("${connectorName}-shared.jar") + destinationDirectory.set(File(projectDir, "build/extensions/${connectorName}")) + from(sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (connectorName) { + "dicom" -> { + include("com/mirth/connect/connectors/dimse/DICOMReceiverProperties.class") + include("com/mirth/connect/connectors/dimse/DICOMDispatcherProperties.class") + } + "doc" -> { + include("com/mirth/connect/connectors/doc/DocumentDispatcherProperties.class") + include("com/mirth/connect/connectors/doc/DocumentConnectorServletInterface.class") + include("com/mirth/connect/connectors/doc/PageSize.class") + include("com/mirth/connect/connectors/doc/Unit.class") + } + "file" -> { + include("com/mirth/connect/connectors/file/SchemeProperties.class") + include("com/mirth/connect/connectors/file/FTPSchemeProperties.class") + include("com/mirth/connect/connectors/file/SmbDialectVersion.class") + include("com/mirth/connect/connectors/file/SmbSchemeProperties.class") + include("com/mirth/connect/connectors/file/SftpSchemeProperties.class") + include("com/mirth/connect/connectors/file/S3SchemeProperties.class") + include("com/mirth/connect/connectors/file/FileReceiverProperties.class") + include("com/mirth/connect/connectors/file/FileDispatcherProperties.class") + include("com/mirth/connect/connectors/file/FileScheme.class") + include("com/mirth/connect/connectors/file/FileAction.class") + include("com/mirth/connect/connectors/file/FileConnectorServletInterface.class") + } + "http" -> { + include("com/mirth/connect/connectors/http/HttpReceiverProperties.class") + include("com/mirth/connect/connectors/http/HttpDispatcherProperties.class") + include("com/mirth/connect/connectors/http/HttpStaticResource.class") + include("com/mirth/connect/connectors/http/HttpStaticResource\$ResourceType.class") + include("com/mirth/connect/connectors/http/HttpConnectorServletInterface.class") + } + "jdbc" -> { + include("com/mirth/connect/connectors/jdbc/DatabaseReceiverProperties.class") + include("com/mirth/connect/connectors/jdbc/DatabaseDispatcherProperties.class") + include("com/mirth/connect/connectors/jdbc/DatabaseConnectionInfo.class") + include("com/mirth/connect/connectors/jdbc/Table.class") + include("com/mirth/connect/connectors/jdbc/Column.class") + include("com/mirth/connect/connectors/jdbc/DatabaseConnectorServletInterface.class") + } + "jms" -> { + include("com/mirth/connect/connectors/jms/JmsConnectorProperties.class") + include("com/mirth/connect/connectors/jms/JmsReceiverProperties.class") + include("com/mirth/connect/connectors/jms/JmsDispatcherProperties.class") + include("com/mirth/connect/connectors/jms/JmsConnectorServletInterface.class") + } + "js" -> { + include("com/mirth/connect/connectors/js/JavaScriptReceiverProperties.class") + include("com/mirth/connect/connectors/js/JavaScriptDispatcherProperties.class") + } + "smtp" -> { + include("com/mirth/connect/connectors/smtp/SmtpDispatcherProperties.class") + include("com/mirth/connect/connectors/smtp/SmtpConnectorServletInterface.class") + include("com/mirth/connect/connectors/smtp/Attachment.class") + } + "tcp" -> { + include("com/mirth/connect/connectors/tcp/TcpReceiverProperties.class") + include("com/mirth/connect/connectors/tcp/TcpDispatcherProperties.class") + include("com/mirth/connect/connectors/tcp/TcpConnectorServletInterface.class") + } + "vm" -> { + include("com/mirth/connect/connectors/vm/VmReceiverProperties.class") + include("com/mirth/connect/connectors/vm/VmDispatcherProperties.class") + } + "ws" -> { + include("com/mirth/connect/connectors/ws/Binding.class") + include("com/mirth/connect/connectors/ws/WebServiceReceiverProperties.class") + include("com/mirth/connect/connectors/ws/WebServiceDispatcherProperties.class") + include("com/mirth/connect/connectors/ws/DefinitionServiceMap.class") + include("com/mirth/connect/connectors/ws/DefinitionServiceMap\$DefinitionPortMap.class") + include("com/mirth/connect/connectors/ws/DefinitionServiceMap\$PortInformation.class") + include("com/mirth/connect/connectors/ws/WebServiceConnectorServletInterface.class") + } + } + } + + val createConnectorServerJar = tasks.register("create${connectorName.capitalize()}ServerJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("${connectorName}-server.jar") + destinationDirectory.set(File(projectDir, "build/extensions/${connectorName}")) + from(sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (connectorName) { + "dicom" -> { + include("com/mirth/connect/connectors/dimse/**") + include("org/dcm4che2/**") + exclude("com/mirth/connect/connectors/dimse/DICOMReceiverProperties.class") + exclude("com/mirth/connect/connectors/dimse/DICOMDispatcherProperties.class") + } + "doc" -> { + include("com/mirth/connect/connectors/doc/**") + exclude("com/mirth/connect/connectors/doc/DocumentDispatcherProperties.class") + exclude("com/mirth/connect/connectors/doc/DocumentConnectorServletInterface.class") + exclude("com/mirth/connect/connectors/doc/PageSize.class") + exclude("com/mirth/connect/connectors/doc/Unit.class") + } + "file" -> { + include("com/mirth/connect/connectors/file/**") + exclude("com/mirth/connect/connectors/file/SchemeProperties.class") + exclude("com/mirth/connect/connectors/file/FTPSchemeProperties.class") + exclude("com/mirth/connect/connectors/file/SftpSchemeProperties.class") + exclude("com/mirth/connect/connectors/file/S3SchemeProperties.class") + exclude("com/mirth/connect/connectors/file/FileReceiverProperties.class") + exclude("com/mirth/connect/connectors/file/FileDispatcherProperties.class") + exclude("com/mirth/connect/connectors/file/FileScheme.class") + exclude("com/mirth/connect/connectors/file/FileAction.class") + exclude("com/mirth/connect/connectors/file/FileConnectorServletInterface.class") + } + "http" -> { + include("com/mirth/connect/connectors/http/**") + exclude("com/mirth/connect/connectors/http/HttpReceiverProperties.class") + exclude("com/mirth/connect/connectors/http/HttpDispatcherProperties.class") + exclude("com/mirth/connect/connectors/http/HttpStaticResource.class") + exclude("com/mirth/connect/connectors/http/HttpStaticResource\$ResourceType.class") + exclude("com/mirth/connect/connectors/http/HttpConnectorServletInterface.class") + } + "jdbc" -> { + include("com/mirth/connect/connectors/jdbc/**") + exclude("com/mirth/connect/connectors/jdbc/DatabaseReceiverProperties.class") + exclude("com/mirth/connect/connectors/jdbc/DatabaseDispatcherProperties.class") + exclude("com/mirth/connect/connectors/jdbc/DatabaseConnectionInfo.class") + exclude("com/mirth/connect/connectors/jdbc/Table.class") + exclude("com/mirth/connect/connectors/jdbc/Column.class") + exclude("com/mirth/connect/connectors/jdbc/DatabaseConnectorServletInterface.class") + } + "jms" -> { + include("com/mirth/connect/connectors/jms/**") + exclude("com/mirth/connect/connectors/jms/JmsConnectorProperties.class") + exclude("com/mirth/connect/connectors/jms/JmsReceiverProperties.class") + exclude("com/mirth/connect/connectors/jms/JmsDispatcherProperties.class") + exclude("com/mirth/connect/connectors/jms/JmsConnectorServletInterface.class") + } + "js" -> { + include("com/mirth/connect/connectors/js/**") + exclude("com/mirth/connect/connectors/js/JavaScriptReceiverProperties.class") + exclude("com/mirth/connect/connectors/js/JavaScriptDispatcherProperties.class") + } + "smtp" -> { + include("com/mirth/connect/connectors/smtp/**") + exclude("com/mirth/connect/connectors/smtp/SmtpDispatcherProperties.class") + exclude("com/mirth/connect/connectors/smtp/SmtpConnectorServletInterface.class") + exclude("com/mirth/connect/connectors/smtp/Attachment.class") + } + "tcp" -> { + include("com/mirth/connect/connectors/tcp/**") + exclude("com/mirth/connect/connectors/tcp/TcpReceiverProperties.class") + exclude("com/mirth/connect/connectors/tcp/TcpDispatcherProperties.class") + exclude("com/mirth/connect/connectors/tcp/TcpConnectorServletInterface.class") + } + "vm" -> { + include("com/mirth/connect/connectors/vm/**") + exclude("com/mirth/connect/connectors/vm/VmReceiverProperties.class") + exclude("com/mirth/connect/connectors/vm/VmDispatcherProperties.class") + } + "ws" -> { + include("com/mirth/connect/connectors/ws/**") + exclude("com/mirth/connect/connectors/ws/Binding.class") + exclude("com/mirth/connect/connectors/ws/WebServiceReceiverProperties.class") + exclude("com/mirth/connect/connectors/ws/WebServiceDispatcherProperties.class") + exclude("com/mirth/connect/connectors/ws/DefinitionServiceMap.class") + exclude("com/mirth/connect/connectors/ws/DefinitionServiceMap\$DefinitionPortMap.class") + exclude("com/mirth/connect/connectors/ws/DefinitionServiceMap\$PortInformation.class") + exclude("com/mirth/connect/connectors/ws/WebServiceConnectorServletInterface.class") + } + } + } + + val copyConnectorXml = tasks.register("copy${connectorName.capitalize()}Xml") { + from(File(projectDir, "src/com/mirth/connect/connectors/${if (connectorName == "dicom") "dimse" else connectorName}")) + into(File(projectDir, "build/extensions/${connectorName}")) + include("*.xml") + } + + val copyConnectorLib = tasks.register("copy${connectorName.capitalize()}Lib") { + from(File(projectDir, "lib/extensions/${if (connectorName == "dicom") "dimse" else connectorName}")) + into(File(projectDir, "build/extensions/${connectorName}/lib")) + include("*.jar") + } + + connectorTasks.addAll(listOf(createConnectorSharedJar, createConnectorServerJar, copyConnectorXml, copyConnectorLib)) +} + +// Datatype JAR creation tasks +val datatypeNames = listOf("delimited", "dicom", "edi", "hl7v2", "hl7v3", "ncpdp", "xml", "raw", "json") + +// Create datatype tasks +val datatypeTasks = mutableListOf>() + +datatypeNames.forEach { datatypeName -> + val createDatatypeSharedJar = tasks.register("createDatatype${datatypeName.capitalize()}SharedJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("datatype-${datatypeName}-shared.jar") + destinationDirectory.set(File(projectDir, "build/extensions/datatype-${datatypeName}")) + from(sourceSets.main.get().output) + include("com/mirth/connect/plugins/datatypes/${datatypeName}/**") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (datatypeName) { + "delimited" -> { + exclude("com/mirth/connect/plugins/datatypes/delimited/DelimitedDataTypeServerPlugin.class") + exclude("com/mirth/connect/plugins/datatypes/delimited/DelimitedBatchAdaptor.class") + exclude("com/mirth/connect/plugins/datatypes/delimited/DelimitedBatchReader.class") + } + "dicom" -> { + exclude("com/mirth/connect/plugins/datatypes/dicom/DICOMDataTypeServerPlugin.class") + } + "edi" -> { + exclude("com/mirth/connect/plugins/datatypes/edi/EDIDataTypeServerPlugin.class") + } + "hl7v2" -> { + exclude("com/mirth/connect/plugins/datatypes/hl7v2/HL7v2DataTypeServerPlugin.class") + exclude("com/mirth/connect/plugins/datatypes/hl7v2/HL7v2BatchAdaptor.class") + } + "hl7v3" -> { + exclude("com/mirth/connect/plugins/datatypes/hl7v3/HL7V3DataTypeServerPlugin.class") + } + "ncpdp" -> { + exclude("com/mirth/connect/plugins/datatypes/ncpdp/NCPDPDataTypeServerPlugin.class") + } + "xml" -> { + exclude("com/mirth/connect/plugins/datatypes/xml/XMLDataTypeServerPlugin.class") + } + "raw" -> { + exclude("com/mirth/connect/plugins/datatypes/raw/RawDataTypeServerPlugin.class") + } + "json" -> { + exclude("com/mirth/connect/plugins/datatypes/json/JSONDataTypeServerPlugin.class") + } + } + } + + val createDatatypeServerJar = tasks.register("createDatatype${datatypeName.capitalize()}ServerJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("datatype-${datatypeName}-server.jar") + destinationDirectory.set(File(projectDir, "build/extensions/datatype-${datatypeName}")) + from(sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (datatypeName) { + "delimited" -> { + include("com/mirth/connect/plugins/datatypes/delimited/DelimitedDataTypeServerPlugin.class") + include("com/mirth/connect/plugins/datatypes/delimited/DelimitedBatchAdaptor.class") + include("com/mirth/connect/plugins/datatypes/delimited/DelimitedBatchReader.class") + } + "dicom" -> { + include("com/mirth/connect/plugins/datatypes/dicom/DICOMDataTypeServerPlugin.class") + } + "edi" -> { + include("com/mirth/connect/plugins/datatypes/edi/EDIDataTypeServerPlugin.class") + } + "hl7v2" -> { + include("com/mirth/connect/plugins/datatypes/hl7v2/HL7v2DataTypeServerPlugin.class") + include("com/mirth/connect/plugins/datatypes/hl7v2/HL7v2BatchAdaptor.class") + } + "hl7v3" -> { + include("com/mirth/connect/plugins/datatypes/hl7v3/HL7V3DataTypeServerPlugin.class") + } + "ncpdp" -> { + include("com/mirth/connect/plugins/datatypes/ncpdp/NCPDPDataTypeServerPlugin.class") + } + "xml" -> { + include("com/mirth/connect/plugins/datatypes/xml/XMLDataTypeServerPlugin.class") + } + "raw" -> { + include("com/mirth/connect/plugins/datatypes/raw/RawDataTypeServerPlugin.class") + } + "json" -> { + include("com/mirth/connect/plugins/datatypes/json/JSONDataTypeServerPlugin.class") + } + } + } + + val copyDatatypeXml = tasks.register("copyDatatype${datatypeName.capitalize()}Xml") { + from(File(projectDir, "src/com/mirth/connect/plugins/datatypes/${datatypeName}")) + into(File(projectDir, "build/extensions/datatype-${datatypeName}")) + include("*.xml") + } + + val copyDatatypeLib = tasks.register("copyDatatype${datatypeName.capitalize()}Lib") { + from(File(projectDir, "lib/extensions/datatypes/${datatypeName}")) + into(File(projectDir, "build/extensions/datatype-${datatypeName}/lib")) + include("*.jar") + } + + datatypeTasks.addAll(listOf(createDatatypeSharedJar, createDatatypeServerJar, copyDatatypeXml, copyDatatypeLib)) + + // Special handling for EDI datatype XML files + if (datatypeName == "edi") { + val copyEdiXmlFiles = tasks.register("copyEdiXmlFiles") { + from(File(projectDir, "src/com/mirth/connect/plugins/datatypes/edi/xml")) + into(File(projectDir, "build/classes/java/main/com/mirth/connect/plugins/datatypes/edi/xml")) + } + datatypeTasks.add(copyEdiXmlFiles) + + // Add dependency to shared and server JAR tasks for EDI + createDatatypeSharedJar.configure { + dependsOn(copyEdiXmlFiles) + } + createDatatypeServerJar.configure { + dependsOn(copyEdiXmlFiles) + } + + // Add dependency to main server JAR tasks + createServerJar.configure { + dependsOn(copyEdiXmlFiles) + } + tasks.jar { + dependsOn(copyEdiXmlFiles) + } + + // Add dependency to test compilation task + tasks.compileTestJava { + dependsOn(copyEdiXmlFiles) + } + } +} + +// Plugin JAR creation tasks +val pluginNames = listOf( + "directoryresource", "dashboardstatus", "destinationsetfilter", "dicomviewer", + "httpauth", "imageviewer", "javascriptrule", "javascriptstep", "mapper", + "messagebuilder", "datapruner", "globalmapviewer", "mllpmode", "pdfviewer", + "textviewer", "rulebuilder", "serverlog", "scriptfilerule", "scriptfilestep", "xsltstep" +) + +// Create plugin tasks +val pluginTasks = mutableListOf>() + +pluginNames.forEach { pluginName -> + // Some plugins only have shared JARs, some have both shared and server + val hasServerJar = pluginName in listOf( + "directoryresource", "dashboardstatus", "httpauth", "globalmapviewer", + "datapruner", "mllpmode", "serverlog" + ) + + val hasSharedJar = pluginName !in listOf("dicomviewer", "imageviewer", "pdfviewer", "textviewer") + + if (hasSharedJar) { + val createPluginSharedJar = tasks.register("create${pluginName.capitalize()}SharedJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("${pluginName}-shared.jar") + destinationDirectory.set(File(projectDir, "build/extensions/${pluginName}")) + from(sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (pluginName) { + "directoryresource" -> { + include("com/mirth/connect/plugins/directoryresource/DirectoryResourceProperties.class") + include("com/mirth/connect/plugins/directoryresource/DirectoryResourceServletInterface.class") + } + "dashboardstatus" -> { + include("com/mirth/connect/plugins/dashboardstatus/ConnectionLogItem.class") + include("com/mirth/connect/plugins/dashboardstatus/DashboardConnectorStatusServletInterface.class") + } + "destinationsetfilter" -> { + include("com/mirth/connect/plugins/destinationsetfilter/DestinationSetFilterStep.class") + include("com/mirth/connect/plugins/destinationsetfilter/DestinationSetFilterStep\$Behavior.class") + include("com/mirth/connect/plugins/destinationsetfilter/DestinationSetFilterStep\$Condition.class") + } + "httpauth" -> { + include("com/mirth/connect/plugins/httpauth/HttpAuthConnectorPluginProperties.class") + include("com/mirth/connect/plugins/httpauth/HttpAuthConnectorPluginProperties\$AuthType.class") + include("com/mirth/connect/plugins/httpauth/NoneHttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/basic/BasicHttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties\$Algorithm.class") + include("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties\$QOPMode.class") + include("com/mirth/connect/plugins/httpauth/custom/CustomHttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/javascript/JavaScriptHttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/oauth2/OAuth2HttpAuthProperties.class") + include("com/mirth/connect/plugins/httpauth/oauth2/OAuth2HttpAuthProperties\$TokenLocation.class") + } + "javascriptrule" -> { + include("com/mirth/connect/plugins/javascriptrule/JavaScriptRule.class") + } + "javascriptstep" -> { + include("com/mirth/connect/plugins/javascriptstep/JavaScriptStep.class") + } + "mapper" -> { + include("com/mirth/connect/plugins/mapper/MapperStep.class") + include("com/mirth/connect/plugins/mapper/MapperStep\$Scope.class") + } + "messagebuilder" -> { + include("com/mirth/connect/plugins/messagebuilder/MessageBuilderStep.class") + } + "datapruner" -> { + include("com/mirth/connect/plugins/datapruner/DataPrunerServletInterface.class") + } + "globalmapviewer" -> { + include("com/mirth/connect/plugins/globalmapviewer/GlobalMapServletInterface.class") + } + "mllpmode" -> { + include("com/mirth/connect/plugins/mllpmode/MLLPModeProperties.class") + } + "rulebuilder" -> { + include("com/mirth/connect/plugins/rulebuilder/RuleBuilderRule.class") + include("com/mirth/connect/plugins/rulebuilder/RuleBuilderRule\$Condition.class") + } + "serverlog" -> { + include("com/mirth/connect/plugins/serverlog/ServerLogItem.class") + include("com/mirth/connect/plugins/serverlog/ServerLogServletInterface.class") + } + "scriptfilerule" -> { + include("com/mirth/connect/plugins/scriptfilerule/ExternalScriptRule.class") + } + "scriptfilestep" -> { + include("com/mirth/connect/plugins/scriptfilestep/ExternalScriptStep.class") + } + "xsltstep" -> { + include("com/mirth/connect/plugins/xsltstep/XsltStep.class") + } + } + } + pluginTasks.add(createPluginSharedJar) + } + + if (hasServerJar) { + val createPluginServerJar = tasks.register("create${pluginName.capitalize()}ServerJar") { + dependsOn(tasks.compileJava) + archiveFileName.set("${pluginName}-server.jar") + destinationDirectory.set(File(projectDir, "build/extensions/${pluginName}")) + from(sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + when (pluginName) { + "directoryresource" -> { + include("com/mirth/connect/plugins/directoryresource/**") + exclude("com/mirth/connect/plugins/directoryresource/DirectoryResourceProperties.class") + exclude("com/mirth/connect/plugins/directoryresource/DirectoryResourceServletInterface.class") + } + "dashboardstatus" -> { + include("com/mirth/connect/plugins/dashboardstatus/**") + exclude("com/mirth/connect/plugins/dashboardstatus/ConnectionLogItem.class") + exclude("com/mirth/connect/plugins/dashboardstatus/DashboardConnectorStatusServletInterface.class") + } + "httpauth" -> { + include("com/mirth/connect/plugins/httpauth/**") + exclude("com/mirth/connect/plugins/httpauth/HttpAuthConnectorPluginProperties.class") + exclude("com/mirth/connect/plugins/httpauth/HttpAuthConnectorPluginProperties\$AuthType.class") + exclude("com/mirth/connect/plugins/httpauth/NoneHttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/basic/BasicHttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties\$Algorithm.class") + exclude("com/mirth/connect/plugins/httpauth/digest/DigestHttpAuthProperties\$QOPMode.class") + exclude("com/mirth/connect/plugins/httpauth/custom/CustomHttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/javascript/JavaScriptHttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/oauth2/OAuth2HttpAuthProperties.class") + exclude("com/mirth/connect/plugins/httpauth/oauth2/OAuth2HttpAuthProperties\$TokenLocation.class") + } + "globalmapviewer" -> { + include("com/mirth/connect/plugins/globalmapviewer/**") + exclude("com/mirth/connect/plugins/globalmapviewer/GlobalMapServletInterface.class") + } + "datapruner" -> { + include("com/mirth/connect/plugins/datapruner/**") + exclude("com/mirth/connect/plugins/datapruner/DataPrunerServletInterface.class") + } + "mllpmode" -> { + include("com/mirth/connect/plugins/mllpmode/**") + exclude("com/mirth/connect/plugins/mllpmode/MLLPModeProperties.class") + } + "serverlog" -> { + include("com/mirth/connect/plugins/serverlog/**") + exclude("com/mirth/connect/plugins/serverlog/ServerLogItem.class") + exclude("com/mirth/connect/plugins/serverlog/ServerLogServletInterface.class") + } + } + } + pluginTasks.add(createPluginServerJar) + } + + val copyPluginXml = tasks.register("copy${pluginName.capitalize()}Xml") { + from(File(projectDir, "src/com/mirth/connect/plugins/${pluginName}")) + into(File(projectDir, "build/extensions/${pluginName}")) + include("*.xml") + } + pluginTasks.add(copyPluginXml) + + val copyPluginLib = tasks.register("copy${pluginName.capitalize()}Lib") { + from(File(projectDir, "lib/extensions/${pluginName}")) + into(File(projectDir, "build/extensions/${pluginName}/lib")) + include("*.jar") + } + pluginTasks.add(copyPluginLib) +} + +// Special task for httpauth userutil sources +val createHttpauthUserutilSources = tasks.register("createHttpauthUserutilSources") { + archiveFileName.set("httpauth-userutil-sources.jar") + destinationDirectory.set(File(projectDir, "build/extensions/httpauth/src")) + from(File(projectDir, "src")) + include("com/mirth/connect/plugins/httpauth/userutil/**") +} + +// Copy setup files task +val copySetupFiles by tasks.registering(Copy::class) { + dependsOn(createSetupDirs, ":donkey:copyToServer") + duplicatesStrategy = DuplicatesStrategy.WARN + + // Copy lib files + from(File(projectDir, "lib")) { + exclude("ant/**") + exclude("extensions/**") + into("server-lib") + } + + // Copy conf files + from(File(projectDir, "conf")) { + into("conf") + } + + // Copy public html files + from(File(projectDir, "public_html")) { + exclude("Thumbs.db") + into("public_html") + } + + // Copy public API html files + from(File(projectDir, "public_api_html")) { + exclude("Thumbs.db") + into("public_api_html") + } + + // Copy docs files + from(File(projectDir, "docs")) { + into("docs") + } + + into(File(projectDir, "setup")) +} + +// Copy client JARs from client build +val copyClientJars by tasks.registering(Copy::class) { + dependsOn(":client:buildClient") + from(File(projectDir, "../client/dist")) { + include("mirth-client.jar") + } + into(File(projectDir, "setup/client-lib")) + + // Also copy client extension JARs + from(File(projectDir, "../client/dist/extensions")) { + include("**/*-client.jar") + } + into(File(projectDir, "setup/client-lib")) +} + +// Copy extensions to setup +val copyExtensionsToSetup by tasks.registering(Copy::class) { + dependsOn(connectorTasks + datatypeTasks + pluginTasks + createHttpauthUserutilSources) + from(File(projectDir, "build/extensions")) + into(File(projectDir, "setup/extensions")) +} + +// Replace version tokens in extensions +val replaceVersionTokens by tasks.registering { + dependsOn(copyExtensionsToSetup) + // Capture project version during configuration time + val projectVersion = version.toString() + + doLast { + fileTree(File(projectDir, "setup/extensions")).matching { + include("**/*.xml") + }.forEach { file -> + val content = file.readText() + file.writeText(content.replace("@mirthversion", projectVersion)) + } + + fileTree(File(projectDir, "setup/public_html")).matching { + include("*.html") + }.forEach { file -> + val content = file.readText() + file.writeText(content.replace("@mirthversion", projectVersion)) + } + } +} + +// Main build task that creates all JARs and setup +val createSetup by tasks.registering { + dependsOn( + createSetupDirs, + createCryptoJar, + createClientCoreJar, + createServerJar, + createVocabJar, + createDbconfJar, + createLauncherJar, + createUserutilSourcesJar, + copySetupFiles, + copyClientJars, + copyExtensionsToSetup, + replaceVersionTokens + ) +} + +// Test tasks +tasks.test { + dependsOn(createSetup) + useJUnit() + filter { + // Exclude cryptography tests that cause memory issues + excludeTestsMatching("com.mirth.commons.encryption.test.*") + } + testLogging { + events("passed", "skipped", "failed") + } +} + +// Configure default JAR task to handle duplicates +tasks.jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +// Main build task +tasks.build { + dependsOn(createSetup) +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000000..2f31322cda --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,10 @@ +rootProject.name = "mirth-connect" + +include("donkey") +include("server") +include("client") +include("webadmin") +include("manager") +include("command") +include("generator") +include("simplesender") diff --git a/simplesender/.classpath b/simplesender/.classpath deleted file mode 100644 index 0b61792e99..0000000000 --- a/simplesender/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/simplesender/.project b/simplesender/.project deleted file mode 100644 index 56981deb41..0000000000 --- a/simplesender/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - SimpleSender - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/simplesender/build.gradle.kts b/simplesender/build.gradle.kts new file mode 100644 index 0000000000..df253d59ff --- /dev/null +++ b/simplesender/build.gradle.kts @@ -0,0 +1,62 @@ +plugins { + java + application +} + +application { + mainClass.set("com.mirth.connect.simplesender.SimpleSender") +} + +dependencies { + // Local lib dependencies + implementation(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar")))) + + // PostgreSQL JDBC driver (using local lib version) + // implementation("org.postgresql:postgresql:42.5.0") // Modern version if needed +} + +sourceSets { + main { + java { + srcDirs("src") + } + } +} + +tasks.jar { + archiveFileName.set("simplesender.jar") + + manifest { + attributes( + "Main-Class" to "com.mirth.connect.simplesender.SimpleSender" + ) + } +} + +// Create distribution with dependencies +tasks.register("copyDependencies", Copy::class) { + from(configurations.runtimeClasspath) + into("${buildDir}/libs/lib") + include("*.jar") +} + +tasks.register("copyLibs", Copy::class) { + from("lib") + into("${buildDir}/libs/lib") + include("*.jar") +} + +// Copy samples +tasks.register("copySamples", Copy::class) { + from("samples") + into("${buildDir}/libs/samples") +} + +tasks.register("dist") { + dependsOn("jar", "copyDependencies", "copyLibs", "copySamples") + description = "Build distribution with all dependencies and samples" +} + +tasks.named("build") { + dependsOn("dist") +} \ No newline at end of file diff --git a/webadmin/.classpath b/webadmin/.classpath deleted file mode 100644 index 79ab88054a..0000000000 --- a/webadmin/.classpath +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/webadmin/.project b/webadmin/.project deleted file mode 100644 index e449fab99f..0000000000 --- a/webadmin/.project +++ /dev/null @@ -1,36 +0,0 @@ - - - WebAdmin - - - - - - org.eclipse.wst.jsdt.core.javascriptValidator - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.wst.validation.validationbuilder - - - - - - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.jdt.core.javanature - org.eclipse.wst.jsdt.core.jsNature - - diff --git a/webadmin/build.gradle.kts b/webadmin/build.gradle.kts new file mode 100644 index 0000000000..cb392b359b --- /dev/null +++ b/webadmin/build.gradle.kts @@ -0,0 +1,99 @@ +plugins { + java + war +} + +repositories { + // Add donkey's lib directories for transitive dependencies + flatDir { + dirs("../donkey/lib", "../donkey/lib/commons", "../donkey/lib/database", "../donkey/lib/guava", "../donkey/lib/xstream") + } + // Add server's lib directories for transitive dependencies + flatDir { + dirs("../server/lib", "../server/lib/commons", "../server/lib/database", "../server/lib/extensions") + } + // Add client's lib directories for transitive dependencies + flatDir { + dirs("../client/lib") + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +// Configure duplicate handling for WAR task +tasks.war { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +dependencies { + // Project dependencies + implementation(project(":donkey")) + implementation(project(":client")) + implementation(project(":server")) + + // Servlet API and JSP dependencies + compileOnly("javax.servlet:javax.servlet-api:4.0.1") + // Note: jetty-jsp and jetty-schemas are included via local file dependencies below + + // XStream dependency + implementation("com.thoughtworks.xstream:xstream:1.4.20") + + // WebAdmin specific dependencies (Stripes, JSON, etc.) + implementation(fileTree(mapOf("dir" to "WebContent/WEB-INF/lib", "include" to listOf("*.jar")))) + + // Local lib dependencies from server + implementation(fileTree(mapOf("dir" to "../server/lib/javax", "include" to listOf("*.jar")))) + implementation(fileTree(mapOf("dir" to "../server/lib/jetty", "include" to listOf("*.jar")))) + implementation(fileTree(mapOf("dir" to "../server/lib/jetty/jsp", "include" to listOf("*.jar")))) +} + +// Ensure client and server JARs are built before webadmin compilation +tasks.compileJava { + dependsOn(":client:jar", ":server:jar", ":donkey:copyToServer", ":server:copyEdiXmlFiles") +} + +sourceSets { + main { + java { + srcDirs("src") + } + resources { + srcDirs("src") + } + } +} + +tasks.war { + dependsOn(":server:createVocabJar") + archiveFileName.set("webadmin.war") + from("WebContent") + + webInf { + from("WebContent/WEB-INF") + } +} + +tasks.register("copyWebContent", Copy::class) { + from("WebContent") + into("${buildDir}/tmp/war") +} + +tasks.named("war") { + dependsOn("copyWebContent") +} + +// JSP compilation task (simplified - may need adjustment based on actual JSP usage) +tasks.register("compileJsps") { + description = "Compile JSP files" + // This is a placeholder - actual JSP compilation would need more setup + doLast { + println("JSP compilation would happen here") + } +} + +tasks.named("compileJava") { + dependsOn("compileJsps") +} \ No newline at end of file