From e8f1b593095bba2c592753766862fde6f0efdebb Mon Sep 17 00:00:00 2001 From: Serap Aydin Date: Mon, 24 Nov 2025 14:40:43 +0100 Subject: [PATCH 1/5] -added dsf linter tool documentation to both api 1 and api 2 - changed file name - changed name for routing --- docs/src/.vuepress/theme.ts | 4 +- .../api-v1/tooling/README.md | 2 +- .../api-v1/tooling/linter-tool.md | 1744 +++++++++++++++++ .../api-v1/tooling/validator.md | 234 --- .../api-v2/tooling/README.md | 2 +- .../api-v2/tooling/linter-tool.md | 1744 +++++++++++++++++ .../api-v2/tooling/validator.md | 234 --- 7 files changed, 3492 insertions(+), 472 deletions(-) create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool.md delete mode 100644 docs/src/process-development/api-v1/tooling/validator.md create mode 100644 docs/src/process-development/api-v2/tooling/linter-tool.md delete mode 100644 docs/src/process-development/api-v2/tooling/validator.md diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts index dde8dd4d9..0fd9b5782 100644 --- a/docs/src/.vuepress/theme.ts +++ b/docs/src/.vuepress/theme.ts @@ -229,7 +229,7 @@ export default hopeTheme({ prefix: "tooling", collapsible: true, children: [ - "validator"], + "linter-tool",], },] }, { @@ -315,7 +315,7 @@ export default hopeTheme({ prefix: "tooling", collapsible: true, children: [ - "validator"], + "linter-tool"], },] }, ], diff --git a/docs/src/process-development/api-v1/tooling/README.md b/docs/src/process-development/api-v1/tooling/README.md index 88e246da3..e2a4de1c6 100644 --- a/docs/src/process-development/api-v1/tooling/README.md +++ b/docs/src/process-development/api-v1/tooling/README.md @@ -4,4 +4,4 @@ icon: operate --- ## Process Plugin Dev Tools -- [ DSF Process Plugin Validator](validator.md) \ No newline at end of file +- [ DSF Linter](linter-tool.md) \ No newline at end of file diff --git a/docs/src/process-development/api-v1/tooling/linter-tool.md b/docs/src/process-development/api-v1/tooling/linter-tool.md new file mode 100644 index 000000000..b960c28a2 --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool.md @@ -0,0 +1,1744 @@ +--- +title: DSF Linter +icon: operate +--- +# DSF Linter - Complete Documentation + +A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. + +## Table of Contents + +1. [Overview](#overview) +2. [Quick Start](#quick-start) +3. [Installation](#installation) +4. [Usage](#usage) +5. [CLI Options](#cli-options) +6. [Validation Rules](#validation-rules) +7. [Report Generation](#report-generation) +8. [Architecture](#architecture) +9. [Development](#development) +10. [Troubleshooting](#troubleshooting) +11. [API Reference](#api-reference) + +## Overview + +The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: + +- **BPMN Process Definitions**: Validates Camunda BPMN 2.0 models, task implementations, event configurations, and FHIR resource references +- **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources +- **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure + +### Key Features + +- ✅ Validates BPMN processes against DSF conventions +- ✅ Validates FHIR resources against DSF profiles and HL7 specifications +- ✅ Detects unreferenced (leftover) resources +- ✅ Generates detailed HTML and JSON reports +- ✅ Supports local and remote JAR file input +- ✅ Multi-plugin project support +- ✅ CI/CD integration ready +- ✅ Comprehensive error reporting with severity levels +- ✅ Extensible architecture for custom validation rules + +### What is DSF? + +The Data Sharing Framework (DSF) is a framework for implementing interoperable healthcare data sharing processes. DSF process plugins contain: + +- **BPMN Processes**: Business process definitions using Camunda BPMN 2.0 +- **FHIR Resources**: Healthcare data resources conforming to HL7 FHIR specifications +- **Plugin Classes**: Java classes implementing the DSF ProcessPlugin interface + +## Quick Start + +### Build the Project + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster build +mvn clean package -DskipTests + +# Verbose output +mvn clean package -X +``` + +### Basic Usage + +```bash +# Lint a local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path your-plugin.jar --html + +# Lint a remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html + +# View report at: /tmp/dsf-linter-report-/dsf-linter-report/index.html +``` + +## Installation + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **Operating System**: Windows, Linux, or macOS + +### Building from Source + +```bash +# Clone the repository +git clone +cd dsf-linter + +# Build the project +mvn clean package + +# The executable JAR will be at: +# linter-cli/target/linter-cli-1.0-SNAPSHOT.jar +``` + +### Distribution + +The linter is distributed as a single executable JAR file that includes all dependencies. After building, the JAR can be used standalone: + +```bash +# Copy to a convenient location +cp linter-cli/target/linter-cli-1.0-SNAPSHOT.jar ~/bin/dsf-linter.jar + +# Use from anywhere +java -jar ~/bin/dsf-linter.jar --path plugin.jar --html +``` + +## Usage + +### Input Types + +The linter accepts only **JAR files** as input: + +| Input Type | Example | Description | +|------------|---------|-------------| +| Local JAR | `--path C:\path\to\plugin.jar` | JAR file in local filesystem | +| Remote JAR | `--path https://example.com/plugin.jar` | JAR file via HTTP/HTTPS URL | + +**Important:** Maven projects must first be built with `mvn clean package` before the resulting JAR file can be linted. + +### Expected JAR Structure + +The linter expects the following structure in the JAR file: + +``` +plugin.jar +├── META-INF/ +│ └── services/ +│ ├── dev.dsf.bpe.process.ProcessPlugin (v1) +│ └── dev.dsf.bpe.process.v2.ProcessPlugin (v2) +├── bpe/ +│ └── *.bpmn (BPMN process definitions) +└── fhir/ + ├── ActivityDefinition/ + │ └── *.xml or *.json + ├── Task/ + │ └── *.xml or *.json + ├── StructureDefinition/ + │ └── *.xml or *.json + ├── ValueSet/ + │ └── *.xml or *.json + ├── CodeSystem/ + │ └── *.xml or *.json + └── Questionnaire/ + └── *.xml or *.json +``` + +### Usage Examples + +#### Basic Linting + +```bash +# Local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path C:\path\to\plugin.jar --html + +# Remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html +``` + +#### Advanced Configuration + +```bash +# Multiple report formats with custom path +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --report-path ./reports + +# Verbose output with colored console +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose --color + +# Lint Maven project (two-step process) +# Step 1: Build the project +cd /path/to/project && mvn clean package + +# Step 2: Lint the resulting JAR +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +#### CI/CD Integration + +```bash +# GitHub Actions / GitLab CI +FORCE_COLOR=1 java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --verbose + +# Jenkins (fail on errors) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +# Exit code: 0 = success, 1 = errors + +# Don't fail build (gradual adoption) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --no-fail +``` + +## CLI Options + +| Option | Short | Description | Required | +|--------|-------|-------------|----------| +| `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | +| `--html` | | Generate HTML report | No | +| `--json` | | Generate JSON report | No | +| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | +| `--verbose` | `-v` | Enable verbose logging output | No | +| `--color` | | Enable colored console output | No | +| `--no-fail` | | Exit with code 0 even if linter errors are found | No | +| `--help` | `-h` | Display help message | No | +| `--version` | | Display version information | No | + +### Environment Variables + +| Variable | Effect | +|----------|--------| +| `NO_COLOR` | Disables colored output | +| `FORCE_COLOR` | Forces colored output (useful in CI) | +| `TERM=dumb` | Disables colored output | +| `WT_SESSION`, `ANSICON` | Windows color detection | + +### Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success (no errors, or `--no-fail` was used) | +| 1 | Failure (errors found, or fatal error occurred) | + +## Validation Rules + +The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. + +### BPMN Validation + +The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. + +#### Task Validation + +##### Service Tasks + +- **Name Validation**: + - Task must have a non-empty name + - Error: `BpmnServiceTaskNameEmptyLintItem` + +- **Implementation Class Validation**: + - `camunda:class` or `camunda:delegateExpression` must be specified + - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` + - Implementation class must exist in the classpath + - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` + - Class must implement DSF-specific task interface (if applicable) + - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` + +##### User Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Form Key Validation**: + - `camunda:formKey` must be present and valid + - Must reference a valid Questionnaire resource + +- **Listener Validation**: + - Listener classes must exist + - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` + - Listener must have class attribute + - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` + - Listener must extend/implement required class + - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + +##### Send Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Implementation Class Validation**: + - Implementation class must exist + - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` + - Class must implement required interface + - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` + +- **Field Injection Validation**: + - Message-related field injections must be valid + - FHIR resource references must be correct + +##### Receive Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Message Definition Validation**: + - Message definition must be valid + - FHIR message name cross-checks + +#### Event Validation + +##### Message Events (Start/Intermediate/End) + +- **Event Name Validation**: + - Event must have a non-empty name + - Error: `BpmnEventNameEmptyLintItem` + - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` + - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` + - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` + +- **Implementation Class Validation**: + - For send events, implementation class must exist + - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` + - Class must implement JavaDelegate + - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` + - Intermediate throw events should not have message definitions + - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` + - Throw events must implement required interface + - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` + +- **Field Injection Validation**: + - `profile` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionProfileEmptyLintItem` + - Must contain version placeholder `#{version}` + - Error: `BpmnFieldInjectionProfileNoVersionPlaceholderLintItem` + - Must reference existing StructureDefinition + - Error: `BpmnNoStructureDefinitionFoundForMessageLintItem` + + - `messageName` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionMessageValueEmptyLintItem` + - Must be a string literal + - Error: `BpmnFieldInjectionNotStringLiteralLintItem` + + - `instantiatesCanonical` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionInstantiatesCanonicalEmptyLintItem` + - Must end with version placeholder `|#{version}` + - Error: `BpmnFieldInjectionInstantiatesCanonicalNoVersionPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `BpmnNoActivityDefinitionFoundForMessageLintItem` + +##### Timer Events + +- **Time Expression Validation**: + - Time cycle/date/duration expressions must be valid + - Placeholder usage validation + +##### Error Boundary Events + +- **Error Configuration Validation**: + - Error reference must be present + - Error code must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeEmptyLintItem` + - Error name must not be empty (warning) + - Error: `BpmnErrorBoundaryEventErrorNameEmptyLintItem` + - Error: `BpmnErrorBoundaryEventNameEmptyLintItem` + - Error code variable must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeVariableEmptyLintItem` + +##### Signal Events + +- **Signal Definition Validation**: + - Signal definitions must be valid + - Signal references must be correct + +##### Conditional Events + +- **Condition Expression Validation**: + - Condition expressions must be valid + +#### Gateway and Flow Validation + +##### Exclusive Gateways + +- **Sequence Flow Validation**: + - Outgoing sequence flows must have appropriate names + - Conditional expressions required when multiple paths exist + - Default flow validation + +##### Inclusive Gateways + +- **Sequence Flow Validation**: + - Similar requirements as exclusive gateways + - Multiple path handling + +##### Event-Based Gateways + +- **Configuration Validation**: + - Proper configuration required + - Outgoing flow setup validation + +##### Sequence Flows + +- **Naming and Conditions**: + - Naming conventions + - Conditional expressions for non-default flows from splitting gateways + - Error: `BpmnFlowElementLintItem` + +#### SubProcess Validation + +##### Multi-Instance SubProcesses + +- **Asynchronous Execution**: + - `asyncBefore` must be set to `true` for proper asynchronous execution + - Required for multi-instance subprocesses + +##### Start/End Events in SubProcesses + +- **Structural Validation**: + - Start events must be part of subprocess + - Error: `BpmnStartEventNotPartOfSubProcessLintItem` + - End events must be part of subprocess + - Error: `BpmnEndEventNotPartOfSubProcessLintItem` + +#### Floating Elements + +- **Element Placement**: + - Elements must be properly connected + - Error: `BpmnFloatingElementLintItem` + +#### Unknown Field Injections + +- **Field Injection Validation**: + - Only known field injections are allowed + - Error: `BpmnUnknownFieldInjectionLintItem` + +### FHIR Resource Validation + +The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. + +#### Task Resources + +Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). + +##### Metadata and Profile Validation + +- **Profile Validation**: + - `meta.profile` must be present and point to a DSF Task profile + - Error: `FhirTaskMissingProfileLintItem` + - Profile must be loadable + - Error: `FhirTaskCouldNotLoadProfileLintItem` + +- **InstantiatesCanonical Validation**: + - `instantiatesCanonical` must be present + - Error: `FhirTaskMissingInstantiatesCanonicalLintItem` + - Must end with version placeholder `|#{version}` + - Error: `FhirTaskInstantiatesCanonicalPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `FhirTaskUnknownInstantiatesCanonicalLintItem` + +##### Fixed Elements + +- **Status Validation**: + - `status` must be present + - Error: `FhirTaskMissingStatusLintItem` + - Must be `"draft"` for template Task instances + - Error: `FhirTaskStatusNotDraftLintItem` + - Must be a valid TaskStatus value + - Error: `FhirTaskUnknownStatusLintItem` + +- **Intent Validation**: + - `intent` must be `"order"` + - Error: `FhirTaskValueIsNotSetAsOrderLintItem` + +- **Requester Validation**: + - Requester must be present + - Error: `FhirTaskMissingRequesterLintItem` + - `requester.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRequesterLintItem` + - `requester.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRequesterOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNotExistLintItem` + +- **Recipient Validation**: + - Recipient must be present + - Error: `FhirTaskMissingRecipientLintItem` + - `restriction.recipient.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRecipientLintItem` + - `restriction.recipient.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRecipientOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNotExistLintItem` + +##### Development Placeholders + +- **Date Placeholder**: + - `authoredOn` must contain `#{date}` + - Error: `FhirTaskDateNoPlaceholderLintItem` + +##### Task.input Validation + +- **Input Presence**: + - `Task.input` must not be empty + - Error: `FhirTaskMissingInputLintItem` + +- **Structural Validation**: + - Each input must have `type.coding.system` and `type.coding.code` + - Error: `FhirTaskInputRequiredCodingSystemAndCodingCodeLintItem` + - Each input must have a `value[x]` element + - Error: `FhirTaskInputMissingValueLintItem` + +- **Duplicate Detection**: + - No two inputs may share the same `system#code` combination + - Error: `FhirTaskInputDuplicateSliceLintItem` + +- **BPMN Slice Validation**: + - `message-name` slice: Required (min=1, max=1) + - Error: `FhirTaskRequiredInputWithCodeMessageNameLintItem` + - `business-key` slice: + - Required when status is "in-progress", "completed", or "failed" + - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` + - Must be absent when status is "draft" + - Error: `FhirTaskBusinessKeyExistsLintItem` + - `correlation-key` slice: + - Validated against StructureDefinition cardinality + - Error: `FhirTaskCorrelationExistsLintItem` + - Error: `FhirTaskCorrelationMissingButRequiredLintItem` + +- **Cardinality Validation**: + - Total input count validated against base cardinality + - Error: `FhirTaskInputInstanceCountBelowMinLintItem` + - Error: `FhirTaskInputInstanceCountExceedsMaxLintItem` + - Slice occurrence counts validated against slice-specific cardinality + - Error: `FhirTaskInputSliceCountBelowSliceMinLintItem` + - Error: `FhirTaskInputSliceCountExceedsSliceMaxLintItem` + +- **Terminology Validation**: + - Code/system combinations validated against DSF CodeSystems + - Error: `FhirTaskUnknownCodeLintItem` + +#### StructureDefinition Resources + +StructureDefinition resources are validated against DSF-specific constraints. + +##### Metadata Validation + +- **Read Access Tag**: + - Must contain valid read-access tag + - Error: `FhirStructureDefinitionMissingReadAccessTagLintItem` + +- **URL Validation**: + - `url` must be present and non-empty + - Error: `FhirStructureDefinitionMissingUrlLintItem` + +- **Status Validation**: + - `status` must be `"unknown"` (DSF convention) + - Error: `FhirStructureDefinitionInvalidStatusLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must contain exactly `#{version}` + - Error: `FhirStructureDefinitionVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must contain exactly `#{date}` + - Error: `FhirStructureDefinitionDateNoPlaceholderLintItem` + +##### Structure Validation + +- **Differential**: + - `differential` element must exist + - Error: `FhirStructureDefinitionMissingDifferentialLintItem` + +- **Snapshot**: + - `snapshot` element should not be present (warning) + - Error: `FhirStructureDefinitionSnapshotPresentLintItem` + +- **Element IDs**: + - Every `element` must have an `@id` attribute + - Error: `FhirStructureDefinitionElementWithoutIdLintItem` + - Element IDs must be unique + - Error: `FhirStructureDefinitionDuplicateElementIdLintItem` + +##### Slice Cardinality Validation + +According to FHIR profiling specification §5.1.0.14: + +- **SHOULD Rule**: + - Sum of all slice minimum cardinalities should be ≤ base element's minimum + - Error: `FhirStructureDefinitionSliceMinSumAboveBaseMinLintItem` + +- **MUST Rule (Min Sum)**: + - Sum of all slice minimum cardinalities must not exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMinSumExceedsMaxLintItem` + +- **MUST Rule (Slice Max)**: + - No individual slice's maximum cardinality may exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMaxExceedsBaseMaxLintItem` + +#### ValueSet Resources + +ValueSet resources are validated against the DSF ValueSet base profile. + +##### Metadata Validation + +- **Read Access Tags**: + - Must contain at least one read-access tag (ALL or LOCAL) + - Error: `FhirValueSetMissingReadAccessTagAllOrLocalLintItem` + - Organization role codes must be valid + - Error: `FhirValueSetOrganizationRoleMissingValidCodeValueLintItem` + +- **Required Elements**: + - `url` must be present + - Error: `FhirValueSetMissingUrlLintItem` + - `name` must be present + - Error: `FhirValueSetMissingNameLintItem` + - `title` must be present + - Error: `FhirValueSetMissingTitleLintItem` + - `publisher` must be present + - Error: `FhirValueSetMissingPublisherLintItem` + - `description` must be present + - Error: `FhirValueSetMissingDescriptionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must be `#{version}` + - Error: `FhirValueSetVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must be `#{date}` + - Error: `FhirValueSetDateNoPlaceholderLintItem` + +- **Include Version Placeholder**: + - `compose.include.version` must be `#{version}` + - Error: `FhirValueSetIncludeVersionPlaceholderLintItem` + +##### Compose Structure Validation + +- **Include Elements**: + - At least one `compose.include` required + - Error: `FhirValueSetMissingComposeIncludeLintItem` + - Each include must have a `system` attribute + - Error: `FhirValueSetIncludeMissingSystemLintItem` + +- **Concept Validation**: + - Concept codes must be non-blank + - Error: `FhirValueSetConceptMissingCodeLintItem` + - Duplicate codes detected + - Error: `FhirValueSetDuplicateConceptCodeLintItem` + +##### Terminology Compliance + +- **CodeSystem Validation**: + - CodeSystem URLs validated against DSF terminology cache + - Error: `FhirValueSetUnknownCodeLintItem` + - Code exists but in different CodeSystem + - Error: `FhirValueSetFalseUrlReferencedLintItem` + +#### ActivityDefinition Resources + +##### Profile Validation + +- **Profile**: + - Must have valid profile + - Error: `FhirActivityDefinitionMissingProfileLintItem` + - Profile must not have version number + - Error: `FhirActivityDefinitionProfileHasVersionNumberLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirActivityDefinitionInvalidFhirUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirActivityDefinitionInvalidFhirStatusLintItem` + +##### Authorization Validation + +- **Requester**: + - Requester entry must be present + - Error: `FhirActivityDefinitionEntryMissingRequesterLintItem` + - Requester entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRequesterLintItem` + +- **Recipient**: + - Recipient entry must be present + - Error: `FhirActivityDefinitionEntryMissingRecipientLintItem` + - Recipient entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRecipientLintItem` + +#### CodeSystem Resources + +##### Metadata Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirCodeSystemMissingReadAccessTagLintItem` + +- **Required Elements**: + - Required elements must be present + - Error: `FhirCodeSystemMissingElementLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirCodeSystemInvalidUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirCodeSystemInvalidStatusLintItem` + +##### Concept Validation + +- **Concepts**: + - Must have at least one concept + - Error: `FhirCodeSystemMissingConceptLintItem` + - Concepts must have code + - Error: `FhirCodeSystemConceptMissingCodeLintItem` + - Concepts must have display + - Error: `FhirCodeSystemConceptMissingDisplayLintItem` + - Duplicate codes detected + - Error: `FhirCodeSystemDuplicateCodeLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirCodeSystemVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirCodeSystemDateNoPlaceholderLintItem` + +#### Questionnaire Resources + +##### Metadata Validation + +- **Meta Profile**: + - Must have meta profile + - Error: `FhirQuestionnaireMissingMetaProfileLintItem` + - Meta profile must be valid + - Error: `FhirQuestionnaireInvalidMetaProfileLintItem` + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirQuestionnaireMissingReadAccessTagLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirQuestionnaireInvalidStatusLintItem` + +##### Item Validation + +- **Items**: + - Must have at least one item + - Error: `FhirQuestionnaireMissingItemLintItem` + - Items must have linkId + - Error: `FhirQuestionnaireItemMissingAttributesLinkIdLintItem` + - Items must have text + - Error: `FhirQuestionnaireItemMissingAttributesTextLintItem` + - Items must have type + - Error: `FhirQuestionnaireItemMissingAttributesTypeLintItem` + - Link IDs must be unique + - Error: `FhirQuestionnaireDuplicateLinkIdLintItem` + - Unusual link IDs detected + - Error: `FhirQuestionnaireUnusualLinkIdLintItem` + +##### Mandatory Item Validation + +- **Required Items**: + - Mandatory items must be required + - Error: `FhirQuestionnaireMandatoryItemNotRequiredLintItem` + - Mandatory items must have valid type + - Error: `FhirQuestionnaireMandatoryItemInvalidTypeLintItem` + +##### Definition Validation + +- **Definition**: + - Definition must be valid + - Error: `FhirQuestionnaireDefinitionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirQuestionnaireVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirQuestionnaireDateNoPlaceholderLintItem` + +#### Common FHIR Validations + +##### Access Tag Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirMissingFhirAccessTagLintItem` + - Access tag must be valid + - Error: `FhirInvalidFhirAccessTagLintItem` + +##### Kind Validation + +- **Kind**: + - Kind must be present + - Error: `FhirKindIsMissingOrEmptyLintItem` + - Kind must be "Task" for Task resources + - Error: `FhirKindNotSetAsTaskLintItem` + +##### Status Validation + +- **Status**: + - Status must be "unknown" (DSF convention) + - Error: `FhirStatusIsNotSetAsUnknownLintItem` + +##### Extension Validation + +- **Process Authorization Extension**: + - Must have process authorization extension + - Error: `FhirNoExtensionProcessAuthorizationFoundLintItem` + +### Plugin Configuration Validation + +#### ServiceLoader Registration + +- **Registration File**: + - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) + - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` + - Plugin class must be loadable + - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` + +#### Resource References + +- **BPMN File References**: + - BPMN files referenced in plugin must exist + - Error: `PluginDefinitionBpmnFileReferencedButNotFoundLintItem` + - BPMN files must be in expected root + - Error: `PluginDefinitionBpmnFileReferencedFoundOutsideExpectedRootLintItem` + - BPMN files must be parsable + - Error: `PluginDefinitionUnparsableBpmnResourceLintItem` + +- **FHIR File References**: + - FHIR resources referenced in BPMN must exist + - Error: `PluginDefinitionFhirFileReferencedButNotFoundLintItem` + - FHIR resources must be in expected root + - Error: `PluginDefinitionFhirFileReferencedFoundOutsideExpectedRootLintItem` + - FHIR resources must be parsable + - Error: `PluginDefinitionUnparsableFhirResourceLintItem` + +#### Resource Presence + +- **BPMN Processes**: + - At least one BPMN process must be defined + - Error: `PluginDefinitionNoProcessModelDefinedLintItem` + +- **FHIR Resources**: + - At least one FHIR resource must be defined + - Error: `PluginDefinitionNoFhirResourcesDefinedLintItem` + +#### Leftover Resource Detection + +The linter performs project-level analysis to identify unreferenced resources: + +- **Unreferenced BPMN Files**: + - BPMN files that are not referenced by any plugin + - Reported as warnings + +- **Unreferenced FHIR Resources**: + - FHIR resources that are not referenced by any BPMN process + - Reported as warnings + +This analysis works uniformly for single-plugin and multi-plugin projects. + +## Report Generation + +### Report Structure + +Reports are generated in the following structure: + +``` +/ +├── index.html # Summary report (all plugins) +├── plugin-name.html # Detailed report for each plugin +└── plugin-name.json # JSON report (if --json specified) +``` + +### HTML Report + +The HTML report provides a comprehensive, human-readable view of all linting results. + +#### Summary Page (`index.html`) + +The summary page includes: + +- **Header**: + - DSF Linter version + - Execution timestamp + - Project path + +- **Overall Statistics**: + - Total number of plugins + - Total errors + - Total warnings + - Execution time + +- **Plugin Summary Table**: + - Plugin name + - API version + - Error count + - Warning count + - Link to detailed report + +- **Leftover Resource Summary**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +#### Plugin Report (`plugin-name.html`) + +Each plugin has a detailed report page containing: + +- **Plugin Metadata**: + - Plugin name + - Plugin class name + - API version (v1 or v2) + +- **BPMN Validation Results**: + - List of all BPMN files + - Errors and warnings per file + - Detailed error messages with file and line references + +- **FHIR Validation Results**: + - List of all FHIR resources by type + - Errors and warnings per resource + - Detailed error messages with element paths + +- **Plugin Configuration Results**: + - ServiceLoader registration status + - Resource reference validation results + +- **Leftover Resource Analysis**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +- **Severity Indicators**: + - Color-coded severity levels (ERROR, WARNING, INFO, SUCCESS) + - Expandable/collapsible sections + +### JSON Report + +The JSON report provides machine-readable output for CI/CD integration and automated processing. + +#### Structure + +```json +{ + "version": "1.0.0", + "timestamp": "2024-01-15T10:30:00Z", + "projectPath": "/path/to/plugin.jar", + "executionTimeMs": 2300, + "success": true, + "summary": { + "totalPlugins": 1, + "totalErrors": 0, + "totalWarnings": 1, + "totalLeftoverBpmn": 0, + "totalLeftoverFhir": 0 + }, + "plugins": { + "plugin-name": { + "name": "plugin-name", + "class": "dev.dsf.bpe.plugin.ExamplePlugin", + "apiVersion": "V1", + "errors": 0, + "warnings": 1, + "bpmnFiles": [ + { + "path": "bpe/process.bpmn", + "errors": 0, + "warnings": 1, + "items": [...] + } + ], + "fhirResources": { + "ActivityDefinition": [...], + "Task": [...], + "StructureDefinition": [...] + }, + "pluginConfig": { + "serviceLoaderRegistered": true, + "items": [...] + } + } + }, + "leftoverAnalysis": { + "unreferencedBpmn": [], + "unreferencedFhir": [] + } +} +``` + +#### Lint Item Structure + +Each lint item in the JSON report has the following structure: + +```json +{ + "severity": "ERROR", + "type": "BpmnServiceTaskNameEmptyLintItem", + "message": "Service task must have a non-empty name", + "file": "bpe/process.bpmn", + "element": "ServiceTask_1", + "line": 42, + "column": 10 +} +``` + +### Example Console Output + +``` +DSF Linter v1.0.0 +================================================================= +Project: /path/to/plugin.jar +Report: /tmp/dsf-linter-report-plugin/dsf-linter-report +================================================================= + +Phase 1: Project Setup +✓ JAR file validated +✓ Resources extracted + +Phase 2: Resource Discovery +✓ Found 1 plugin(s) +✓ Plugin: my-process-plugin + - BPMN: 2 files + - FHIR: 15 resources + +Phase 3: Linting +✓ BPMN validation: 0 errors, 1 warning +✓ FHIR validation: 0 errors, 0 warnings +✓ Plugin validation: 0 errors + +Phase 4: Report Generation +✓ HTML report generated + +Summary +================================================================= +✓ SUCCESS - No errors found + Plugins: 1 + Errors: 0 + Warnings: 1 + Execution time: 2.3s +================================================================= +``` + +## Architecture + +### Project Structure + +``` +dsf-linter/ +├── linter-core/ # Core linting logic +│ ├── src/main/java/dev/dsf/linter/ +│ │ ├── analysis/ # Resource analysis +│ │ │ └── LeftoverResourceDetector.java +│ │ ├── bpmn/ # BPMN parsing & validation +│ │ │ ├── BpmnLinter.java +│ │ │ ├── BpmnModelLinter.java +│ │ │ ├── BpmnTaskLinter.java +│ │ │ ├── BpmnEventLinter.java +│ │ │ ├── BpmnGatewayAndFlowLinter.java +│ │ │ └── BpmnSubProcessLinter.java +│ │ ├── fhir/ # FHIR parsing & validation +│ │ │ ├── FhirResourceLinter.java +│ │ │ ├── FhirTaskLinter.java +│ │ │ ├── FhirStructureDefinitionLinter.java +│ │ │ ├── FhirValueSetLinter.java +│ │ │ ├── FhirActivityDefinitionLinter.java +│ │ │ ├── FhirCodeSystemLinter.java +│ │ │ └── FhirQuestionnaireLinter.java +│ │ ├── service/ # Linting services +│ │ │ ├── BpmnLintingService.java +│ │ │ ├── FhirLintingService.java +│ │ │ ├── PluginLintingService.java +│ │ │ └── PluginLintingOrchestrator.java +│ │ ├── output/ # Lint item definitions +│ │ │ └── item/ # Specific lint items (200+ classes) +│ │ ├── report/ # Report generation +│ │ │ └── LintingReportGenerator.java +│ │ ├── input/ # Input handling & JAR processing +│ │ │ └── InputResolver.java +│ │ ├── setup/ # Project setup & building +│ │ │ └── ProjectSetupHandler.java +│ │ ├── plugin/ # Plugin definition discovery +│ │ │ └── PluginDefinitionDiscovery.java +│ │ ├── classloading/ # Dynamic class loading +│ │ │ ├── ProjectClassLoaderFactory.java +│ │ │ └── ClassInspector.java +│ │ ├── logger/ # Logging infrastructure +│ │ │ ├── Logger.java +│ │ │ ├── ConsoleLogger.java +│ │ │ └── Console.java +│ │ ├── constants/ # Constants & configuration +│ │ │ └── DsfApiConstants.java +│ │ ├── exception/ # Custom exceptions +│ │ │ ├── ResourceLinterException.java +│ │ │ └── MissingServiceRegistrationException.java +│ │ └── util/ # Utilities +│ │ ├── api/ # API version detection +│ │ ├── cache/ # Caching utilities +│ │ ├── converter/ # Format converters +│ │ ├── linting/ # Linting utilities +│ │ ├── loader/ # Class/service loading +│ │ ├── maven/ # Maven utilities +│ │ └── resource/ # Resource management +│ ├── src/main/resources/ +│ │ ├── logback.xml # Logging configuration +│ │ ├── logback-verbose.xml # Verbose logging configuration +│ │ └── templates/ # HTML report templates +│ │ ├── logo.svg +│ │ ├── single_plugin_report.html +│ │ └── summary_report.html +│ └── src/test/ # Unit tests +│ ├── java/ +│ └── resources/ # Test fixtures +└── linter-cli/ # CLI interface + └── src/main/java/dev/dsf/linter/ + ├── Main.java # CLI entry point + ├── LinterExecutor.java # Execution wrapper + └── ResultPrinter.java # Result formatting +``` + +### Key Components + +| Component | Purpose | +|-----------|---------| +| `DsfLinter` | Main orchestrator coordinating all linting phases | +| `ProjectSetupHandler` | Handles JAR extraction and classloader setup | +| `ResourceDiscoveryService` | Discovers plugins, BPMN files, and FHIR resources | +| `BpmnLintingService` | Orchestrates BPMN validation | +| `FhirLintingService` | Orchestrates FHIR resource validation | +| `PluginLintingService` | Validates plugin configuration and ServiceLoader registration | +| `PluginLintingOrchestrator` | Coordinates per-plugin linting workflow | +| `LeftoverResourceDetector` | Identifies unreferenced resources | +| `LintingReportGenerator` | Generates HTML and JSON reports | +| `InputResolver` | Resolves and downloads remote JAR files | +| `BpmnModelLinter` | Validates BPMN model structure and elements | +| `FhirResourceLinter` | Validates FHIR resources using pluggable linters | + +### Linting Phases + +The linter executes in five phases: + +#### Phase 1: Project Setup + +1. **Input Validation**: + - Validates that input is a JAR file + - Checks file existence or URL accessibility + +2. **JAR Extraction**: + - Downloads remote JAR files if needed + - Extracts JAR contents to temporary directory + - Preserves directory structure + +3. **Classloader Setup**: + - Creates project-specific classloader + - Loads plugin classes and dependencies + - Sets up context classloader for resource access + +#### Phase 2: Resource Discovery + +1. **Plugin Discovery**: + - Scans `META-INF/services/` for plugin registrations + - Loads plugin classes + - Detects API version (v1 or v2) + +2. **BPMN Discovery**: + - Scans `bpe/` directory for BPMN files + - Parses BPMN files to extract process definitions + - Maps BPMN files to plugins + +3. **FHIR Discovery**: + - Scans `fhir/` directory for FHIR resources + - Organizes resources by type + - Maps FHIR resources to plugins + +4. **Reference Mapping**: + - Extracts BPMN references to FHIR resources + - Maps FHIR resource references + - Identifies cross-references + +#### Phase 3: Linting + +1. **Per-Plugin Linting**: + - For each discovered plugin: + - Validates BPMN processes + - Validates FHIR resources + - Validates plugin configuration + - Collects lint items + +2. **Project-Level Analysis**: + - Performs leftover resource analysis + - Aggregates referenced resources across all plugins + - Identifies unreferenced resources + +3. **Result Aggregation**: + - Combines results from all plugins + - Calculates totals (errors, warnings) + - Determines overall success status + +#### Phase 4: Report Generation + +1. **HTML Report Generation**: + - Generates summary page + - Generates detailed plugin pages + - Applies templates and styling + +2. **JSON Report Generation** (if requested): + - Serializes all results to JSON + - Includes metadata and statistics + - Provides machine-readable format + +#### Phase 5: Summary + +1. **Console Output**: + - Displays execution summary + - Shows error and warning counts + - Reports execution time + +2. **Exit Code Determination**: + - Sets exit code based on results + - Respects `--no-fail` flag + - Returns appropriate status code + +### Design Patterns + +The linter uses several design patterns: + +- **Template Method Pattern**: Abstract base classes define linting algorithm structure +- **Strategy Pattern**: Pluggable linters for different resource types +- **Factory Pattern**: Classloader and service creation +- **Service Locator Pattern**: Plugin discovery via ServiceLoader +- **Builder Pattern**: Configuration and result objects + +### Thread Safety + +- Most components are stateless and thread-safe +- Classloader isolation ensures no cross-plugin interference +- Temporary context classloader used for resource access +- Result objects are immutable + +## Development + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **IDE**: IntelliJ IDEA, Eclipse, or VS Code (optional) + +### IDE Setup + +1. **Import Project**: + - Import as Maven project + - Set JDK to 17 or higher + - Ensure Maven dependencies are resolved + +2. **Code Style** (optional): + - Configure code formatter + - Set up import organization + - Configure line endings + +3. **Run Configuration**: + - Create run configuration for `Main.java` + - Set program arguments: `--path --html --verbose` + - Configure working directory + +### Building + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster iteration +mvn clean package -DskipTests + +# Verbose Maven output +mvn clean package -X + +# Build only specific module +mvn clean package -pl linter-core + +# Install to local Maven repository +mvn clean install +``` + +### Testing + +```bash +# Run all tests +mvn test + +# Run specific test class +mvn test -Dtest=BpmnLoadingTest + +# Run specific test method +mvn test -Dtest=BpmnLoadingTest#testLoadBpmn + +# Run tests with verbose output +mvn test -X + +# Skip tests during build +mvn clean package -DskipTests + +# Run tests with coverage (if configured) +mvn test jacoco:report +``` + +### Development Workflow + +```bash +# 1. Make changes to source code +vim linter-core/src/main/java/dev/dsf/linter/service/BpmnLintingService.java + +# 2. Build the project +mvn clean package -DskipTests + +# 3. Test with a sample plugin +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test-plugin.jar --html --verbose + +# 4. Check the generated report +open /tmp/dsf-linter-report-test-plugin/dsf-linter-report/index.html + +# 5. Run unit tests +mvn test + +# 6. Commit changes +git add . +git commit -m "Description of changes" +``` + +### Debugging + +#### Remote Debugging + +```bash +# Start the linter with debugger enabled +java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ + -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Attach debugger from IDE to localhost:5005 +``` + +#### Logging + +The linter uses Logback for logging. Configuration files: + +- `logback.xml`: Standard logging (INFO level) +- `logback-verbose.xml`: Verbose logging (DEBUG level, activated with `--verbose`) + +Log levels: +- **ERROR**: Fatal errors and exceptions +- **WARN**: Warnings and non-fatal issues +- **INFO**: General information and progress +- **DEBUG**: Detailed debugging information (verbose mode only) + +#### Common Debugging Scenarios + +1. **Plugin Not Found**: + - Enable verbose logging + - Check ServiceLoader registration + - Verify classpath + +2. **Resource Not Found**: + - Check JAR structure + - Verify resource paths + - Enable verbose logging + +3. **Class Loading Issues**: + - Check classloader setup + - Verify dependencies + - Check API version compatibility + +### Code Style Guidelines + +- Follow Java naming conventions +- Use meaningful variable and method names +- Add JavaDoc comments for public APIs +- Keep methods focused and small +- Use immutable objects where possible +- Handle exceptions appropriately +- Write unit tests for new features + +## Troubleshooting + +### "Input must be a JAR file" Error + +**Problem**: The linter only accepts JAR files as input. + +**Solution**: +```bash +# Wrong - Maven project directly +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project --html + +# Correct - Build first, then lint JAR +cd /path/to/project && mvn clean package +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +### JAR File Not Found + +**Problem**: The specified JAR file path cannot be found. + +**Solution**: Verify the path and use absolute paths if needed: + +```bash +# Windows +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path "C:\Users\Username\project\target\plugin.jar" --html + +# Linux/Mac +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /home/username/project/target/plugin.jar --html +``` + +### Missing Dependencies + +**Problem**: ClassNotFoundException or similar errors during linting. + +**Solution**: +```bash +# Check Maven settings +ls ~/.m2/settings.xml + +# Use verbose mode to see detailed error messages +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Check if dependencies are in the JAR +jar -tf plugin.jar | grep -i "class" +``` + +### Report Not Generated + +**Problem**: No report files are created. + +**Solution**: +```bash +# --html or --json flag must be set +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html # ← Required + +# Use absolute path for report directory +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --report-path $(pwd)/reports + +# Check write permissions +ls -ld /tmp/dsf-linter-report-* +``` + +### Remote JAR Download Error + +**Problem**: Cannot download JAR from remote URL. + +**Solution**: +```bash +# Test download separately +curl -L -o test.jar https://example.com/plugin.jar + +# Verify the download +ls -lh test.jar + +# Check network connectivity +ping example.com + +# Then use the local file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test.jar --html +``` + +### Plugin Not Found + +**Problem**: "No plugins found" message. + +**Solution**: +- Verify ServiceLoader registration exists in `META-INF/services/` +- Check that plugin class is in the JAR file +- Ensure plugin class implements the correct interface +- Use `--verbose` to see detailed discovery logs +- Check API version compatibility + +### Out of Memory Errors + +**Problem**: `OutOfMemoryError` during linting. + +**Solution**: +```bash +# Increase heap size +java -Xmx2g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html + +# For very large projects +java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +``` + +### Slow Performance + +**Problem**: Linting takes too long. + +**Solution**: +- Use `-DskipTests` during build +- Disable verbose logging in production +- Check network latency for remote JARs +- Consider increasing heap size +- Profile with JVM tools if needed + +### Class Loading Issues + +**Problem**: Classes cannot be loaded from plugin JAR. + +**Solution**: +- Verify JAR structure +- Check classpath configuration +- Ensure dependencies are included +- Use verbose mode to see classloader logs +- Check API version compatibility + +## API Reference + +### Core Classes + +#### `DsfLinter` + +Main orchestrator class for the linting process. + +**Constructor**: +```java +DsfLinter(Config config) +``` + +**Methods**: +```java +OverallLinterResult lint() throws IOException +``` + +**Usage**: +```java +DsfLinter.Config config = new DsfLinter.Config( + projectPath, + reportPath, + generateHtmlReport, + generateJsonReport, + failOnErrors, + logger +); + +DsfLinter linter = new DsfLinter(config); +DsfLinter.OverallLinterResult result = linter.lint(); +``` + +#### `DsfLinter.Config` + +Configuration record for the linter. + +**Fields**: +- `Path projectPath`: Path to the project root +- `Path reportPath`: Path for report generation +- `boolean generateHtmlReport`: Whether to generate HTML report +- `boolean generateJsonReport`: Whether to generate JSON report +- `boolean failOnErrors`: Whether to fail on errors +- `Logger logger`: Logger instance + +#### `DsfLinter.OverallLinterResult` + +Result record containing all linting results. + +**Fields**: +- `Map pluginLinter`: Results per plugin +- `LeftoverResourceDetector.AnalysisResult leftoverAnalysis`: Leftover resource analysis +- `Path masterReportPath`: Path to master report +- `long executionTimeMs`: Execution time in milliseconds +- `boolean success`: Whether linting succeeded + +**Methods**: +- `int getPluginErrors()`: Total error count from plugins +- `int getPluginWarnings()`: Total warning count from plugins +- `int getLeftoverCount()`: Count of leftover resources +- `int getTotalErrors()`: Total errors including leftovers + +#### `DsfLinter.PluginLinter` + +Linting result for a single plugin. + +**Fields**: +- `String pluginName`: Name of the plugin +- `String pluginClass`: Fully qualified class name +- `ApiVersion apiVersion`: DSF API version (V1 or V2) +- `LintingOutput output`: Detailed linting output +- `Path reportPath`: Path to generated report + +### Linting Services + +#### `BpmnLintingService` + +Service for linting BPMN files. + +**Constructor**: +```java +BpmnLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List bpmnFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `FhirLintingService` + +Service for linting FHIR resources. + +**Constructor**: +```java +FhirLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List fhirFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `PluginLintingService` + +Service for linting plugin configuration. + +**Constructor**: +```java +PluginLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lintPlugin( + Path projectPath, + PluginAdapter pluginAdapter, + ApiVersion apiVersion, + List collectedPluginItems +) throws MissingServiceRegistrationException +``` + +### Lint Items + +All lint items extend `AbstractLintItem` and implement specific interfaces. + +#### Base Classes + +- `AbstractLintItem`: Base class for all lint items +- `BpmnElementLintItem`: Base class for BPMN-specific lint items +- `FhirElementLintItem`: Base class for FHIR-specific lint items +- `PluginLintItem`: Base class for plugin-specific lint items + +#### Severity Levels + +- `ERROR`: Critical issues that must be fixed +- `WARNING`: Issues that should be addressed +- `INFO`: Informational messages +- `SUCCESS`: Validation passed successfully + +#### Common Lint Item Methods + +```java +LinterSeverity getSeverity() +String getMessage() +File getFile() +String getElement() +``` + +### Utility Classes + +#### `Logger` + +Interface for logging functionality. + +**Methods**: +```java +void error(String message) +void error(String message, Throwable throwable) +void warn(String message) +void info(String message) +void debug(String message) +``` + +#### `InputResolver` + +Resolves and processes input JAR files. + +**Methods**: +```java +Optional resolve(String inputPath) +String extractInputName(String inputPath, InputType inputType) +void cleanup(ResolutionResult resolution) +``` + +#### `ResourceDiscoveryService` + +Discovers plugins and resources. + +**Methods**: +```java +DiscoveryResult discover(ProjectContext context) +``` + +## Changelog + +### Version 1.0.0 +- Initial release +- BPMN validation +- FHIR validation +- Plugin configuration validation +- HTML report generation + diff --git a/docs/src/process-development/api-v1/tooling/validator.md b/docs/src/process-development/api-v1/tooling/validator.md deleted file mode 100644 index 8605181b4..000000000 --- a/docs/src/process-development/api-v1/tooling/validator.md +++ /dev/null @@ -1,234 +0,0 @@ ---- -title: Process Plugin Validator -icon: operate ---- -# DSF Process Plugin Validator v 1.3.0 - -## 1  Introduction - -The **DSF Validator** is a quality‑assurance tool for Digital Sample Framework (DSF) process plugins. Version **1.3.0** extends the 1.2.0 release by adding  - -* a dedicated **FHIR *Task* validator** for the base profile `dsf-task-base`, -* a **StructureDefinition validator** with slice‑aware cardinality checks,  -* enhanced terminology look‑ups via **FhirAuthorizationCache**, and -* a streamlined **CLI & Maven plugin** that share the same validation core. - -The validator now supports end‑to‑end consistency checks across BPMN models and all core FHIR artefacts used in the DSF platform. It targets **Java 21** and can be embedded in CI/CD pipelines, local project builds, or executed as a standalone JAR. - - -## 2  Project Overview - -| Component | Purpose | -| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **BPMN analysis** | Verifies Camunda‑compatible workflows (tasks, events, gateways, multi‑instance sub‑processes, field injections). | -| **FHIR analysis** | Validates XML/JSON resources against DSF profiles (ActivityDefinition, CodeSystem, Questionnaire, Task, ValueSet, *Task (base)*, StructureDefinition). | -| **Aggregator** | `FhirInstanceValidatorAggregator` discovers concrete validators and produces a single `ValidationOutput`. | -| **Authorization cache** | `FhirAuthorizationCache` holds all known DSF `CodeSystem` codes in a thread‑safe map for high‑performance terminology look‑ups. | -| **Report generator** | Writes structured JSON reports under `report/` (CLI) or `target/dsf-validation-reports/` (Maven plugin). | - -Camunda models are parsed with the **Camunda BPMN Model API** ([github.com](https://github.com/camunda/camunda-bpm-platform/blob/master/model-api/bpmn-model/README.asciidoc?utm_source=chatgpt.com)), while FHIR resources are processed via standard DOM/XPath and validated by custom DSF-specific validators augmented by DSF‑specific rule sets. - - - -## 3  Validation Scope - -### 3.1 BPMN Model Validation (module `validator‑core`) - -| Validator | BPMN elements inspected | Key DSF rules enforced | -| ----------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `BpmnTaskValidator` | `ServiceTask`, `UserTask`, `SendTask`, `ReceiveTask` | \* camunda\:class/expression must reference a Java class implementing `JavaDelegate`.
\* Field injections validated against DSF profiles (`profile`, `message-name`, `instantiatesCanonical`).
\* `UserTask → camunda:formKey` must resolve to an existing `Questionnaire` file. | -| `BpmnEventValidator` | `StartEvent`, `EndEvent`, `IntermediateCatch`, `ThrowEvent`, `BoundaryEvent` | \* Message events require a non‑blank `` and `` pointing to an `ActivityDefinition.url`.
\* Timer/signal events: ISO‑8601 expressions and registered signal definitions. | -| `BpmnGatewayAndFlowValidator` | `ExclusiveGateway`, `EventBasedGateway`, `SequenceFlow` | \* Exclusive gateways: every outgoing `SequenceFlow` needs `name + conditionExpression`.
\* Event‑based gateways: exactly one incoming flow; only allowed outgoing event types. | -| `BpmnFieldInjectionValidator` | Camunda `` | \* `profile` must reference a `StructureDefinition` in `src/main/resources/fhir/StructureDefinition`.
\* `message-name` must exist as an `input` slice in a `Task`.
\* `instantiatesCanonical` must match an existing `ActivityDefinition`. | | -------------------------------------------------------------------------------------------------------------------------- | -| `BpmnSubProcessValidator` | `SubProcess` (+ `MultiInstanceLoopCharacteristics`) | • Requires `camunda:asyncBefore="true"` for multi-instance subprocesses. • Checks loop cardinality and clean termination. | - -### 3.2 FHIR Resource Validation (module `validator‑core`) - -| DSF Profile & Class | Mandatory elements | DSF‑specific checks | Shared checks | -| ----------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | -| **ActivityDefinition 1.0.0**  `FhirActivityDefinitionValidator` | `url`, `status="unknown"`, `kind="Task"` | \* First `meta.tag` = system `…/read-access-tag`, code `ALL`.
\* `extension-process-authorization`: every requester/recipient coding must be known to the authorization cache. | Placeholder enforcement (`#{version}`, `#{date}`) | -| **CodeSystem 1.0.0**  `FhirCodeSystemValidator` | `url`, `name`, `title`, `publisher`, `content`, `caseSensitive` | \* `status="unknown"`.
\* `url` must start with `http://dsf.dev/fhir/CodeSystem/`.
\* All `concept.code` values unique; each concept needs `code + display`. | Placeholder enforcement; read‑access tag | -| **Questionnaire 1.5.0**  `FhirQuestionnaireValidator` | `meta.profile`, `url`, `version`, `date`, `status` | \* Mandatory items `business-key` & `user-task-id` (type string, `required=true`).
\* Ensures unique `linkId`; warns on non‑conformant patterns. | Placeholder enforcement; read‑access tag | -| **Task 1.0.0**  `FhirTaskValidator` | `id`, `instantiatesCanonical`, `intent`, `status` | \* Required `input` slices `message-name`, `business-key`; optional `correlation-key`.
\* Duplicate `input` slices detected via `Map` counter.
\* Output slice rules: if `status=failed` → must contain `error` slice. | Placeholder enforcement (`#{date}`, `#{organization}`); terminology look‑ups via the authorization cache | -| **ValueSet 1.0.0**  `FhirValueSetValidator` | `url`, `name`, `title`, `publisher`, `description` | \* Enforces read‑access tag.
\* `compose.include`: each `system` present; `concept.code` non‑blank and known.
\* Flags duplicate concepts within the same `include` block. | Placeholder enforcement (`#{version}`, `#{date}`) | -| **StructureDefinition 1.0.0**  `FhirStructureDefinitionValidator`
(**NEW in v1.3.0**) | `meta.profile`, `differential`, `url` | \* Must contain `meta.tag` & `meta.profile`.
\* `version` and `date` fields require `#{version}` / `#{date}` placeholders.
\* No `snapshot` allowed; all element `@id`s unique.
\* **Slice cardinality**: min/max constraints are verified for each slice using rules from FHIR §5.1.0.14 ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)). | Placeholder enforcement; read‑access tag | - -### 3.3 Cross‑resource Consistency - -*The validator resolves every `` to its canonical URL and verifies that a corresponding `ActivityDefinition.url` exists. Field injections (`profile`, `message-name`, `instantiatesCanonical`) are likewise cross-checked against the available FHIR artefacts to ensure that referenced canonicals exist. **Slice-level conformity to the referenced `StructureDefinition` is not evaluated.*** - - -## 4  Validation Approach - -1. **File discovery** – Recursively searches for either full Maven-style paths (e.g., `src/main/resources/bpe`) or flat folder names (e.g., `bpe`). Supports both Maven projects and unpacked JARs in CI. -2. **BPMN pass** – Camunda Model API parses the model; validators run sequentially. -3. **FHIR pass** – XML/JSON files stream through `FhirInstanceValidatorAggregator`, which delegates to each concrete validator. -4. **Slice cardinality checks** – For every `StructureDefinition`, the validator loads min/max values of the base and sliced elements and enforces them according to FHIR profiling rules §5.1.0.14 ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)). -5. **Terminology** – `FhirAuthorizationCache` accelerates terminology look-ups (read-access tags, concept codes). Authorization checks for requester/recipient organisations rely on these look-ups at run time but are not cached.* -6. **Output generation** – All validation items are collected, sorted, and written to JSON reports. - - - -## 5  Implementation & Components - -``` -validator-core - ├─ BpmnModelValidator - │ ├─ BpmnEventValidator - │ ├─ BpmnGatewayAndFlowValidator - │ ├─ BpmnTaskValidator - │ ├─ BpmnFieldInjectionValidator - │ └─ BpmnSubProcessValidator - ├─ AbstractFhirInstanceValidator (base class) - │ ├─ FhirActivityDefinitionValidator - │ ├─ FhirCodeSystemValidator - │ ├─ FhirQuestionnaireValidator - │ ├─ FhirTaskValidator - │ ├─ FhirValueSetValidator - │ ├─ FhirStructureDefinitionValidator ← NEW - ├─ FhirResourceValidator - ├─ FhirInstanceValidatorAggregator - ├─ FhirAuthorizationCache - ├─ ValidationOutput (print + JSON export) - ├─ ReportCleaner - ├─ ApiVersionDetector / ApiVersionHolder - ├─ MavenBuilder - └─ DsfValidatorImpl -validator-cli - └─ Main (Picocli CLI entry point) -validator-maven-plugin - └─ ValidateMojo (goal bound to *verify* phase) -``` - - - -## 6  Build System & Dependencies - -* **Apache Maven** – multi‑module build (`dsf-validator`, `validator-core`, `validator-api`, `validator-cli`). -* **Java 21** target, **Byte Buddy** for test instrumentation. -* External libraries: Camunda BPMN Model API ([github.com](https://github.com/camunda/camunda-bpm-platform/blob/master/model-api/bpmn-model/README.asciidoc?utm_source=chatgpt.com)), **Picocli**, **JGit**, **Jackson**, **JUnit 5**, **Mockito**. - - - - -## 7 Running the Validator - -The DSF Validator supports multiple execution environments: - -| **Scenario** | **Command / Configuration** | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **CLI – local folder** | `java -jar dsf-validator-1.3.0.jar --localPath /path/to/project` | -| **CLI – remote Git repo** | `java -jar dsf-validator-1.3.0.jar --remoteRepo https://gitlab.com/org/repo.git` | -| **Maven (one-shot)** | `mvn dev.dsf.utils.validator:validator-maven-plugin:verify` | -| **Maven (POM snippet)** | `xml

dev.dsf.utils.validator
validator-maven-plugin
1.2


verify
verify


` | -| **CI Pipeline (GitLab)** | See below – fully automated GitLab CI validation pipeline using containerized validator image | - ---- - -### Maven Plugin Features - -* Runs during `verify`, `compile`, or `install` phase. -* Validates BPMN models (`src/main/resources/bpe`) and FHIR resources (`src/main/resources/fhir`). -* Reports are written to: - `target/dsf-validation-reports/` - -**Example Output Structure:** - -``` -target/dsf-validation-reports/ -├── bpmnReports/ -│ ├── success/ -│ ├── other/ -│ └── bpmn_issues_aggregated.json -├── fhirReports/ -│ ├── success/ -│ ├── other/ -│ └── fhir_issues_aggregated.json -└── aggregated.json -``` -The validator automatically runs -`mvn clean package dependency:copy-dependencies` before analysis. - ---- - -### GitLab CI Pipeline Features - -The DSF validation pipeline enables automated quality checks of submitted plugins using Dockerized jobs. - -#### **Pipeline Overview** - -```yaml -# Example job in .gitlab-ci.yml -analyze-dsf-validator: - stage: analyze - image: - name: registry.it.hs-heilbronn.de/dsf/qs/hub-qa-pipeline/dsf-validator:1.2-3 - entrypoint: [""] - dependencies: [build1] - script: - - java -jar /opt/validator/validator.jar --localPath output - - mkdir -p "$CI_PROJECT_DIR/reports/dsf-validator" - - cp -r report/* "$CI_PROJECT_DIR/reports/dsf-validator/" || true -``` - -#### **Features** - -* **Input:** Validated plugin is extracted from the submitted JAR. -* **Execution flow:** - - * `build1` stage prepares the plugin. - * `analyze-dsf-validator` performs static validation of BPMN and FHIR resources. - * `collect-reports` aggregates results from all analyzers into `final-reports/`. - -#### **Outputs** - -All JSON-formatted validation results are stored as GitLab artifacts under: - -``` -final-reports/ -└── dsf-validator/ - ├── bpmnReports/ - ├── fhirReports/ - └── aggregated.json -``` - -#### **Requirements** - -* Internet access (for downloading dependencies and validator image) -* Maven-compatible environment -* Container image: - `registry.it.hs-heilbronn.de/dsf/qs/hub-qa-pipeline/dsf-validator:1.2-3` - - ---- - -## 8  Data Processing & Storage - -Validation items are materialised as `BpmnElementValidationItem` or `FhirElementValidationItem` and serialised to JSON. The **top‑level `aggregated.json`** summarises overall status (`ERROR` / `WARN` / `INFO` / `SUCCESS`). - - -## 9  Execution Workflow - -1. **RepositoryManager** clones remote sources if requested. -2. **MavenBuilder** compiles the project. -3. **BpmnModelValidator** & **FhirInstanceValidatorAggregator** perform analysis. -4. **ReportCleaner** purges previous results; writers store fresh reports. -5. **ApiVersionDetector** prints the detected DSF BPE API version (v1 or v2). - - -## 10  Expected Output - -* **Errors** – fatal; block deployment. -* **Warnings** – non‑fatal but may break runtime paths. -* **Info** – best‑practice hints (e.g. missing `display` in `CodeSystem.concept`). - -Developers review `report/aggregated.json` or per‑file reports under `success/` and `other/`. - -## 11  Conclusion - -Version **1.3.0** turns the DSF Validator into a *profile‑aware* verification tool: - -* It validates every BPMN construct and all core FHIR artefacts *plus* the DSF‑specific `dsf-task-base` profile and StructureDefinitions. -* It caches authorised `CodeSystem` codes, enforces slice cardinalities ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)), and guards core metadata placeholders. -* It can be launched via an intuitive CLI or a zero‑configuration Maven plugin, making it an early quality gate that helps DSF process authors catch structural, semantic, and interoperability issues long before deployment. - diff --git a/docs/src/process-development/api-v2/tooling/README.md b/docs/src/process-development/api-v2/tooling/README.md index 88e246da3..e2a4de1c6 100644 --- a/docs/src/process-development/api-v2/tooling/README.md +++ b/docs/src/process-development/api-v2/tooling/README.md @@ -4,4 +4,4 @@ icon: operate --- ## Process Plugin Dev Tools -- [ DSF Process Plugin Validator](validator.md) \ No newline at end of file +- [ DSF Linter](linter-tool.md) \ No newline at end of file diff --git a/docs/src/process-development/api-v2/tooling/linter-tool.md b/docs/src/process-development/api-v2/tooling/linter-tool.md new file mode 100644 index 000000000..b960c28a2 --- /dev/null +++ b/docs/src/process-development/api-v2/tooling/linter-tool.md @@ -0,0 +1,1744 @@ +--- +title: DSF Linter +icon: operate +--- +# DSF Linter - Complete Documentation + +A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. + +## Table of Contents + +1. [Overview](#overview) +2. [Quick Start](#quick-start) +3. [Installation](#installation) +4. [Usage](#usage) +5. [CLI Options](#cli-options) +6. [Validation Rules](#validation-rules) +7. [Report Generation](#report-generation) +8. [Architecture](#architecture) +9. [Development](#development) +10. [Troubleshooting](#troubleshooting) +11. [API Reference](#api-reference) + +## Overview + +The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: + +- **BPMN Process Definitions**: Validates Camunda BPMN 2.0 models, task implementations, event configurations, and FHIR resource references +- **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources +- **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure + +### Key Features + +- ✅ Validates BPMN processes against DSF conventions +- ✅ Validates FHIR resources against DSF profiles and HL7 specifications +- ✅ Detects unreferenced (leftover) resources +- ✅ Generates detailed HTML and JSON reports +- ✅ Supports local and remote JAR file input +- ✅ Multi-plugin project support +- ✅ CI/CD integration ready +- ✅ Comprehensive error reporting with severity levels +- ✅ Extensible architecture for custom validation rules + +### What is DSF? + +The Data Sharing Framework (DSF) is a framework for implementing interoperable healthcare data sharing processes. DSF process plugins contain: + +- **BPMN Processes**: Business process definitions using Camunda BPMN 2.0 +- **FHIR Resources**: Healthcare data resources conforming to HL7 FHIR specifications +- **Plugin Classes**: Java classes implementing the DSF ProcessPlugin interface + +## Quick Start + +### Build the Project + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster build +mvn clean package -DskipTests + +# Verbose output +mvn clean package -X +``` + +### Basic Usage + +```bash +# Lint a local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path your-plugin.jar --html + +# Lint a remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html + +# View report at: /tmp/dsf-linter-report-/dsf-linter-report/index.html +``` + +## Installation + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **Operating System**: Windows, Linux, or macOS + +### Building from Source + +```bash +# Clone the repository +git clone +cd dsf-linter + +# Build the project +mvn clean package + +# The executable JAR will be at: +# linter-cli/target/linter-cli-1.0-SNAPSHOT.jar +``` + +### Distribution + +The linter is distributed as a single executable JAR file that includes all dependencies. After building, the JAR can be used standalone: + +```bash +# Copy to a convenient location +cp linter-cli/target/linter-cli-1.0-SNAPSHOT.jar ~/bin/dsf-linter.jar + +# Use from anywhere +java -jar ~/bin/dsf-linter.jar --path plugin.jar --html +``` + +## Usage + +### Input Types + +The linter accepts only **JAR files** as input: + +| Input Type | Example | Description | +|------------|---------|-------------| +| Local JAR | `--path C:\path\to\plugin.jar` | JAR file in local filesystem | +| Remote JAR | `--path https://example.com/plugin.jar` | JAR file via HTTP/HTTPS URL | + +**Important:** Maven projects must first be built with `mvn clean package` before the resulting JAR file can be linted. + +### Expected JAR Structure + +The linter expects the following structure in the JAR file: + +``` +plugin.jar +├── META-INF/ +│ └── services/ +│ ├── dev.dsf.bpe.process.ProcessPlugin (v1) +│ └── dev.dsf.bpe.process.v2.ProcessPlugin (v2) +├── bpe/ +│ └── *.bpmn (BPMN process definitions) +└── fhir/ + ├── ActivityDefinition/ + │ └── *.xml or *.json + ├── Task/ + │ └── *.xml or *.json + ├── StructureDefinition/ + │ └── *.xml or *.json + ├── ValueSet/ + │ └── *.xml or *.json + ├── CodeSystem/ + │ └── *.xml or *.json + └── Questionnaire/ + └── *.xml or *.json +``` + +### Usage Examples + +#### Basic Linting + +```bash +# Local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path C:\path\to\plugin.jar --html + +# Remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html +``` + +#### Advanced Configuration + +```bash +# Multiple report formats with custom path +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --report-path ./reports + +# Verbose output with colored console +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose --color + +# Lint Maven project (two-step process) +# Step 1: Build the project +cd /path/to/project && mvn clean package + +# Step 2: Lint the resulting JAR +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +#### CI/CD Integration + +```bash +# GitHub Actions / GitLab CI +FORCE_COLOR=1 java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --verbose + +# Jenkins (fail on errors) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +# Exit code: 0 = success, 1 = errors + +# Don't fail build (gradual adoption) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --no-fail +``` + +## CLI Options + +| Option | Short | Description | Required | +|--------|-------|-------------|----------| +| `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | +| `--html` | | Generate HTML report | No | +| `--json` | | Generate JSON report | No | +| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | +| `--verbose` | `-v` | Enable verbose logging output | No | +| `--color` | | Enable colored console output | No | +| `--no-fail` | | Exit with code 0 even if linter errors are found | No | +| `--help` | `-h` | Display help message | No | +| `--version` | | Display version information | No | + +### Environment Variables + +| Variable | Effect | +|----------|--------| +| `NO_COLOR` | Disables colored output | +| `FORCE_COLOR` | Forces colored output (useful in CI) | +| `TERM=dumb` | Disables colored output | +| `WT_SESSION`, `ANSICON` | Windows color detection | + +### Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success (no errors, or `--no-fail` was used) | +| 1 | Failure (errors found, or fatal error occurred) | + +## Validation Rules + +The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. + +### BPMN Validation + +The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. + +#### Task Validation + +##### Service Tasks + +- **Name Validation**: + - Task must have a non-empty name + - Error: `BpmnServiceTaskNameEmptyLintItem` + +- **Implementation Class Validation**: + - `camunda:class` or `camunda:delegateExpression` must be specified + - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` + - Implementation class must exist in the classpath + - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` + - Class must implement DSF-specific task interface (if applicable) + - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` + +##### User Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Form Key Validation**: + - `camunda:formKey` must be present and valid + - Must reference a valid Questionnaire resource + +- **Listener Validation**: + - Listener classes must exist + - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` + - Listener must have class attribute + - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` + - Listener must extend/implement required class + - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + +##### Send Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Implementation Class Validation**: + - Implementation class must exist + - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` + - Class must implement required interface + - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` + +- **Field Injection Validation**: + - Message-related field injections must be valid + - FHIR resource references must be correct + +##### Receive Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Message Definition Validation**: + - Message definition must be valid + - FHIR message name cross-checks + +#### Event Validation + +##### Message Events (Start/Intermediate/End) + +- **Event Name Validation**: + - Event must have a non-empty name + - Error: `BpmnEventNameEmptyLintItem` + - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` + - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` + - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` + +- **Implementation Class Validation**: + - For send events, implementation class must exist + - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` + - Class must implement JavaDelegate + - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` + - Intermediate throw events should not have message definitions + - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` + - Throw events must implement required interface + - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` + +- **Field Injection Validation**: + - `profile` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionProfileEmptyLintItem` + - Must contain version placeholder `#{version}` + - Error: `BpmnFieldInjectionProfileNoVersionPlaceholderLintItem` + - Must reference existing StructureDefinition + - Error: `BpmnNoStructureDefinitionFoundForMessageLintItem` + + - `messageName` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionMessageValueEmptyLintItem` + - Must be a string literal + - Error: `BpmnFieldInjectionNotStringLiteralLintItem` + + - `instantiatesCanonical` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionInstantiatesCanonicalEmptyLintItem` + - Must end with version placeholder `|#{version}` + - Error: `BpmnFieldInjectionInstantiatesCanonicalNoVersionPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `BpmnNoActivityDefinitionFoundForMessageLintItem` + +##### Timer Events + +- **Time Expression Validation**: + - Time cycle/date/duration expressions must be valid + - Placeholder usage validation + +##### Error Boundary Events + +- **Error Configuration Validation**: + - Error reference must be present + - Error code must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeEmptyLintItem` + - Error name must not be empty (warning) + - Error: `BpmnErrorBoundaryEventErrorNameEmptyLintItem` + - Error: `BpmnErrorBoundaryEventNameEmptyLintItem` + - Error code variable must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeVariableEmptyLintItem` + +##### Signal Events + +- **Signal Definition Validation**: + - Signal definitions must be valid + - Signal references must be correct + +##### Conditional Events + +- **Condition Expression Validation**: + - Condition expressions must be valid + +#### Gateway and Flow Validation + +##### Exclusive Gateways + +- **Sequence Flow Validation**: + - Outgoing sequence flows must have appropriate names + - Conditional expressions required when multiple paths exist + - Default flow validation + +##### Inclusive Gateways + +- **Sequence Flow Validation**: + - Similar requirements as exclusive gateways + - Multiple path handling + +##### Event-Based Gateways + +- **Configuration Validation**: + - Proper configuration required + - Outgoing flow setup validation + +##### Sequence Flows + +- **Naming and Conditions**: + - Naming conventions + - Conditional expressions for non-default flows from splitting gateways + - Error: `BpmnFlowElementLintItem` + +#### SubProcess Validation + +##### Multi-Instance SubProcesses + +- **Asynchronous Execution**: + - `asyncBefore` must be set to `true` for proper asynchronous execution + - Required for multi-instance subprocesses + +##### Start/End Events in SubProcesses + +- **Structural Validation**: + - Start events must be part of subprocess + - Error: `BpmnStartEventNotPartOfSubProcessLintItem` + - End events must be part of subprocess + - Error: `BpmnEndEventNotPartOfSubProcessLintItem` + +#### Floating Elements + +- **Element Placement**: + - Elements must be properly connected + - Error: `BpmnFloatingElementLintItem` + +#### Unknown Field Injections + +- **Field Injection Validation**: + - Only known field injections are allowed + - Error: `BpmnUnknownFieldInjectionLintItem` + +### FHIR Resource Validation + +The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. + +#### Task Resources + +Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). + +##### Metadata and Profile Validation + +- **Profile Validation**: + - `meta.profile` must be present and point to a DSF Task profile + - Error: `FhirTaskMissingProfileLintItem` + - Profile must be loadable + - Error: `FhirTaskCouldNotLoadProfileLintItem` + +- **InstantiatesCanonical Validation**: + - `instantiatesCanonical` must be present + - Error: `FhirTaskMissingInstantiatesCanonicalLintItem` + - Must end with version placeholder `|#{version}` + - Error: `FhirTaskInstantiatesCanonicalPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `FhirTaskUnknownInstantiatesCanonicalLintItem` + +##### Fixed Elements + +- **Status Validation**: + - `status` must be present + - Error: `FhirTaskMissingStatusLintItem` + - Must be `"draft"` for template Task instances + - Error: `FhirTaskStatusNotDraftLintItem` + - Must be a valid TaskStatus value + - Error: `FhirTaskUnknownStatusLintItem` + +- **Intent Validation**: + - `intent` must be `"order"` + - Error: `FhirTaskValueIsNotSetAsOrderLintItem` + +- **Requester Validation**: + - Requester must be present + - Error: `FhirTaskMissingRequesterLintItem` + - `requester.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRequesterLintItem` + - `requester.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRequesterOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNotExistLintItem` + +- **Recipient Validation**: + - Recipient must be present + - Error: `FhirTaskMissingRecipientLintItem` + - `restriction.recipient.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRecipientLintItem` + - `restriction.recipient.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRecipientOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNotExistLintItem` + +##### Development Placeholders + +- **Date Placeholder**: + - `authoredOn` must contain `#{date}` + - Error: `FhirTaskDateNoPlaceholderLintItem` + +##### Task.input Validation + +- **Input Presence**: + - `Task.input` must not be empty + - Error: `FhirTaskMissingInputLintItem` + +- **Structural Validation**: + - Each input must have `type.coding.system` and `type.coding.code` + - Error: `FhirTaskInputRequiredCodingSystemAndCodingCodeLintItem` + - Each input must have a `value[x]` element + - Error: `FhirTaskInputMissingValueLintItem` + +- **Duplicate Detection**: + - No two inputs may share the same `system#code` combination + - Error: `FhirTaskInputDuplicateSliceLintItem` + +- **BPMN Slice Validation**: + - `message-name` slice: Required (min=1, max=1) + - Error: `FhirTaskRequiredInputWithCodeMessageNameLintItem` + - `business-key` slice: + - Required when status is "in-progress", "completed", or "failed" + - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` + - Must be absent when status is "draft" + - Error: `FhirTaskBusinessKeyExistsLintItem` + - `correlation-key` slice: + - Validated against StructureDefinition cardinality + - Error: `FhirTaskCorrelationExistsLintItem` + - Error: `FhirTaskCorrelationMissingButRequiredLintItem` + +- **Cardinality Validation**: + - Total input count validated against base cardinality + - Error: `FhirTaskInputInstanceCountBelowMinLintItem` + - Error: `FhirTaskInputInstanceCountExceedsMaxLintItem` + - Slice occurrence counts validated against slice-specific cardinality + - Error: `FhirTaskInputSliceCountBelowSliceMinLintItem` + - Error: `FhirTaskInputSliceCountExceedsSliceMaxLintItem` + +- **Terminology Validation**: + - Code/system combinations validated against DSF CodeSystems + - Error: `FhirTaskUnknownCodeLintItem` + +#### StructureDefinition Resources + +StructureDefinition resources are validated against DSF-specific constraints. + +##### Metadata Validation + +- **Read Access Tag**: + - Must contain valid read-access tag + - Error: `FhirStructureDefinitionMissingReadAccessTagLintItem` + +- **URL Validation**: + - `url` must be present and non-empty + - Error: `FhirStructureDefinitionMissingUrlLintItem` + +- **Status Validation**: + - `status` must be `"unknown"` (DSF convention) + - Error: `FhirStructureDefinitionInvalidStatusLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must contain exactly `#{version}` + - Error: `FhirStructureDefinitionVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must contain exactly `#{date}` + - Error: `FhirStructureDefinitionDateNoPlaceholderLintItem` + +##### Structure Validation + +- **Differential**: + - `differential` element must exist + - Error: `FhirStructureDefinitionMissingDifferentialLintItem` + +- **Snapshot**: + - `snapshot` element should not be present (warning) + - Error: `FhirStructureDefinitionSnapshotPresentLintItem` + +- **Element IDs**: + - Every `element` must have an `@id` attribute + - Error: `FhirStructureDefinitionElementWithoutIdLintItem` + - Element IDs must be unique + - Error: `FhirStructureDefinitionDuplicateElementIdLintItem` + +##### Slice Cardinality Validation + +According to FHIR profiling specification §5.1.0.14: + +- **SHOULD Rule**: + - Sum of all slice minimum cardinalities should be ≤ base element's minimum + - Error: `FhirStructureDefinitionSliceMinSumAboveBaseMinLintItem` + +- **MUST Rule (Min Sum)**: + - Sum of all slice minimum cardinalities must not exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMinSumExceedsMaxLintItem` + +- **MUST Rule (Slice Max)**: + - No individual slice's maximum cardinality may exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMaxExceedsBaseMaxLintItem` + +#### ValueSet Resources + +ValueSet resources are validated against the DSF ValueSet base profile. + +##### Metadata Validation + +- **Read Access Tags**: + - Must contain at least one read-access tag (ALL or LOCAL) + - Error: `FhirValueSetMissingReadAccessTagAllOrLocalLintItem` + - Organization role codes must be valid + - Error: `FhirValueSetOrganizationRoleMissingValidCodeValueLintItem` + +- **Required Elements**: + - `url` must be present + - Error: `FhirValueSetMissingUrlLintItem` + - `name` must be present + - Error: `FhirValueSetMissingNameLintItem` + - `title` must be present + - Error: `FhirValueSetMissingTitleLintItem` + - `publisher` must be present + - Error: `FhirValueSetMissingPublisherLintItem` + - `description` must be present + - Error: `FhirValueSetMissingDescriptionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must be `#{version}` + - Error: `FhirValueSetVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must be `#{date}` + - Error: `FhirValueSetDateNoPlaceholderLintItem` + +- **Include Version Placeholder**: + - `compose.include.version` must be `#{version}` + - Error: `FhirValueSetIncludeVersionPlaceholderLintItem` + +##### Compose Structure Validation + +- **Include Elements**: + - At least one `compose.include` required + - Error: `FhirValueSetMissingComposeIncludeLintItem` + - Each include must have a `system` attribute + - Error: `FhirValueSetIncludeMissingSystemLintItem` + +- **Concept Validation**: + - Concept codes must be non-blank + - Error: `FhirValueSetConceptMissingCodeLintItem` + - Duplicate codes detected + - Error: `FhirValueSetDuplicateConceptCodeLintItem` + +##### Terminology Compliance + +- **CodeSystem Validation**: + - CodeSystem URLs validated against DSF terminology cache + - Error: `FhirValueSetUnknownCodeLintItem` + - Code exists but in different CodeSystem + - Error: `FhirValueSetFalseUrlReferencedLintItem` + +#### ActivityDefinition Resources + +##### Profile Validation + +- **Profile**: + - Must have valid profile + - Error: `FhirActivityDefinitionMissingProfileLintItem` + - Profile must not have version number + - Error: `FhirActivityDefinitionProfileHasVersionNumberLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirActivityDefinitionInvalidFhirUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirActivityDefinitionInvalidFhirStatusLintItem` + +##### Authorization Validation + +- **Requester**: + - Requester entry must be present + - Error: `FhirActivityDefinitionEntryMissingRequesterLintItem` + - Requester entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRequesterLintItem` + +- **Recipient**: + - Recipient entry must be present + - Error: `FhirActivityDefinitionEntryMissingRecipientLintItem` + - Recipient entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRecipientLintItem` + +#### CodeSystem Resources + +##### Metadata Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirCodeSystemMissingReadAccessTagLintItem` + +- **Required Elements**: + - Required elements must be present + - Error: `FhirCodeSystemMissingElementLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirCodeSystemInvalidUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirCodeSystemInvalidStatusLintItem` + +##### Concept Validation + +- **Concepts**: + - Must have at least one concept + - Error: `FhirCodeSystemMissingConceptLintItem` + - Concepts must have code + - Error: `FhirCodeSystemConceptMissingCodeLintItem` + - Concepts must have display + - Error: `FhirCodeSystemConceptMissingDisplayLintItem` + - Duplicate codes detected + - Error: `FhirCodeSystemDuplicateCodeLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirCodeSystemVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirCodeSystemDateNoPlaceholderLintItem` + +#### Questionnaire Resources + +##### Metadata Validation + +- **Meta Profile**: + - Must have meta profile + - Error: `FhirQuestionnaireMissingMetaProfileLintItem` + - Meta profile must be valid + - Error: `FhirQuestionnaireInvalidMetaProfileLintItem` + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirQuestionnaireMissingReadAccessTagLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirQuestionnaireInvalidStatusLintItem` + +##### Item Validation + +- **Items**: + - Must have at least one item + - Error: `FhirQuestionnaireMissingItemLintItem` + - Items must have linkId + - Error: `FhirQuestionnaireItemMissingAttributesLinkIdLintItem` + - Items must have text + - Error: `FhirQuestionnaireItemMissingAttributesTextLintItem` + - Items must have type + - Error: `FhirQuestionnaireItemMissingAttributesTypeLintItem` + - Link IDs must be unique + - Error: `FhirQuestionnaireDuplicateLinkIdLintItem` + - Unusual link IDs detected + - Error: `FhirQuestionnaireUnusualLinkIdLintItem` + +##### Mandatory Item Validation + +- **Required Items**: + - Mandatory items must be required + - Error: `FhirQuestionnaireMandatoryItemNotRequiredLintItem` + - Mandatory items must have valid type + - Error: `FhirQuestionnaireMandatoryItemInvalidTypeLintItem` + +##### Definition Validation + +- **Definition**: + - Definition must be valid + - Error: `FhirQuestionnaireDefinitionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirQuestionnaireVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirQuestionnaireDateNoPlaceholderLintItem` + +#### Common FHIR Validations + +##### Access Tag Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirMissingFhirAccessTagLintItem` + - Access tag must be valid + - Error: `FhirInvalidFhirAccessTagLintItem` + +##### Kind Validation + +- **Kind**: + - Kind must be present + - Error: `FhirKindIsMissingOrEmptyLintItem` + - Kind must be "Task" for Task resources + - Error: `FhirKindNotSetAsTaskLintItem` + +##### Status Validation + +- **Status**: + - Status must be "unknown" (DSF convention) + - Error: `FhirStatusIsNotSetAsUnknownLintItem` + +##### Extension Validation + +- **Process Authorization Extension**: + - Must have process authorization extension + - Error: `FhirNoExtensionProcessAuthorizationFoundLintItem` + +### Plugin Configuration Validation + +#### ServiceLoader Registration + +- **Registration File**: + - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) + - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` + - Plugin class must be loadable + - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` + +#### Resource References + +- **BPMN File References**: + - BPMN files referenced in plugin must exist + - Error: `PluginDefinitionBpmnFileReferencedButNotFoundLintItem` + - BPMN files must be in expected root + - Error: `PluginDefinitionBpmnFileReferencedFoundOutsideExpectedRootLintItem` + - BPMN files must be parsable + - Error: `PluginDefinitionUnparsableBpmnResourceLintItem` + +- **FHIR File References**: + - FHIR resources referenced in BPMN must exist + - Error: `PluginDefinitionFhirFileReferencedButNotFoundLintItem` + - FHIR resources must be in expected root + - Error: `PluginDefinitionFhirFileReferencedFoundOutsideExpectedRootLintItem` + - FHIR resources must be parsable + - Error: `PluginDefinitionUnparsableFhirResourceLintItem` + +#### Resource Presence + +- **BPMN Processes**: + - At least one BPMN process must be defined + - Error: `PluginDefinitionNoProcessModelDefinedLintItem` + +- **FHIR Resources**: + - At least one FHIR resource must be defined + - Error: `PluginDefinitionNoFhirResourcesDefinedLintItem` + +#### Leftover Resource Detection + +The linter performs project-level analysis to identify unreferenced resources: + +- **Unreferenced BPMN Files**: + - BPMN files that are not referenced by any plugin + - Reported as warnings + +- **Unreferenced FHIR Resources**: + - FHIR resources that are not referenced by any BPMN process + - Reported as warnings + +This analysis works uniformly for single-plugin and multi-plugin projects. + +## Report Generation + +### Report Structure + +Reports are generated in the following structure: + +``` +/ +├── index.html # Summary report (all plugins) +├── plugin-name.html # Detailed report for each plugin +└── plugin-name.json # JSON report (if --json specified) +``` + +### HTML Report + +The HTML report provides a comprehensive, human-readable view of all linting results. + +#### Summary Page (`index.html`) + +The summary page includes: + +- **Header**: + - DSF Linter version + - Execution timestamp + - Project path + +- **Overall Statistics**: + - Total number of plugins + - Total errors + - Total warnings + - Execution time + +- **Plugin Summary Table**: + - Plugin name + - API version + - Error count + - Warning count + - Link to detailed report + +- **Leftover Resource Summary**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +#### Plugin Report (`plugin-name.html`) + +Each plugin has a detailed report page containing: + +- **Plugin Metadata**: + - Plugin name + - Plugin class name + - API version (v1 or v2) + +- **BPMN Validation Results**: + - List of all BPMN files + - Errors and warnings per file + - Detailed error messages with file and line references + +- **FHIR Validation Results**: + - List of all FHIR resources by type + - Errors and warnings per resource + - Detailed error messages with element paths + +- **Plugin Configuration Results**: + - ServiceLoader registration status + - Resource reference validation results + +- **Leftover Resource Analysis**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +- **Severity Indicators**: + - Color-coded severity levels (ERROR, WARNING, INFO, SUCCESS) + - Expandable/collapsible sections + +### JSON Report + +The JSON report provides machine-readable output for CI/CD integration and automated processing. + +#### Structure + +```json +{ + "version": "1.0.0", + "timestamp": "2024-01-15T10:30:00Z", + "projectPath": "/path/to/plugin.jar", + "executionTimeMs": 2300, + "success": true, + "summary": { + "totalPlugins": 1, + "totalErrors": 0, + "totalWarnings": 1, + "totalLeftoverBpmn": 0, + "totalLeftoverFhir": 0 + }, + "plugins": { + "plugin-name": { + "name": "plugin-name", + "class": "dev.dsf.bpe.plugin.ExamplePlugin", + "apiVersion": "V1", + "errors": 0, + "warnings": 1, + "bpmnFiles": [ + { + "path": "bpe/process.bpmn", + "errors": 0, + "warnings": 1, + "items": [...] + } + ], + "fhirResources": { + "ActivityDefinition": [...], + "Task": [...], + "StructureDefinition": [...] + }, + "pluginConfig": { + "serviceLoaderRegistered": true, + "items": [...] + } + } + }, + "leftoverAnalysis": { + "unreferencedBpmn": [], + "unreferencedFhir": [] + } +} +``` + +#### Lint Item Structure + +Each lint item in the JSON report has the following structure: + +```json +{ + "severity": "ERROR", + "type": "BpmnServiceTaskNameEmptyLintItem", + "message": "Service task must have a non-empty name", + "file": "bpe/process.bpmn", + "element": "ServiceTask_1", + "line": 42, + "column": 10 +} +``` + +### Example Console Output + +``` +DSF Linter v1.0.0 +================================================================= +Project: /path/to/plugin.jar +Report: /tmp/dsf-linter-report-plugin/dsf-linter-report +================================================================= + +Phase 1: Project Setup +✓ JAR file validated +✓ Resources extracted + +Phase 2: Resource Discovery +✓ Found 1 plugin(s) +✓ Plugin: my-process-plugin + - BPMN: 2 files + - FHIR: 15 resources + +Phase 3: Linting +✓ BPMN validation: 0 errors, 1 warning +✓ FHIR validation: 0 errors, 0 warnings +✓ Plugin validation: 0 errors + +Phase 4: Report Generation +✓ HTML report generated + +Summary +================================================================= +✓ SUCCESS - No errors found + Plugins: 1 + Errors: 0 + Warnings: 1 + Execution time: 2.3s +================================================================= +``` + +## Architecture + +### Project Structure + +``` +dsf-linter/ +├── linter-core/ # Core linting logic +│ ├── src/main/java/dev/dsf/linter/ +│ │ ├── analysis/ # Resource analysis +│ │ │ └── LeftoverResourceDetector.java +│ │ ├── bpmn/ # BPMN parsing & validation +│ │ │ ├── BpmnLinter.java +│ │ │ ├── BpmnModelLinter.java +│ │ │ ├── BpmnTaskLinter.java +│ │ │ ├── BpmnEventLinter.java +│ │ │ ├── BpmnGatewayAndFlowLinter.java +│ │ │ └── BpmnSubProcessLinter.java +│ │ ├── fhir/ # FHIR parsing & validation +│ │ │ ├── FhirResourceLinter.java +│ │ │ ├── FhirTaskLinter.java +│ │ │ ├── FhirStructureDefinitionLinter.java +│ │ │ ├── FhirValueSetLinter.java +│ │ │ ├── FhirActivityDefinitionLinter.java +│ │ │ ├── FhirCodeSystemLinter.java +│ │ │ └── FhirQuestionnaireLinter.java +│ │ ├── service/ # Linting services +│ │ │ ├── BpmnLintingService.java +│ │ │ ├── FhirLintingService.java +│ │ │ ├── PluginLintingService.java +│ │ │ └── PluginLintingOrchestrator.java +│ │ ├── output/ # Lint item definitions +│ │ │ └── item/ # Specific lint items (200+ classes) +│ │ ├── report/ # Report generation +│ │ │ └── LintingReportGenerator.java +│ │ ├── input/ # Input handling & JAR processing +│ │ │ └── InputResolver.java +│ │ ├── setup/ # Project setup & building +│ │ │ └── ProjectSetupHandler.java +│ │ ├── plugin/ # Plugin definition discovery +│ │ │ └── PluginDefinitionDiscovery.java +│ │ ├── classloading/ # Dynamic class loading +│ │ │ ├── ProjectClassLoaderFactory.java +│ │ │ └── ClassInspector.java +│ │ ├── logger/ # Logging infrastructure +│ │ │ ├── Logger.java +│ │ │ ├── ConsoleLogger.java +│ │ │ └── Console.java +│ │ ├── constants/ # Constants & configuration +│ │ │ └── DsfApiConstants.java +│ │ ├── exception/ # Custom exceptions +│ │ │ ├── ResourceLinterException.java +│ │ │ └── MissingServiceRegistrationException.java +│ │ └── util/ # Utilities +│ │ ├── api/ # API version detection +│ │ ├── cache/ # Caching utilities +│ │ ├── converter/ # Format converters +│ │ ├── linting/ # Linting utilities +│ │ ├── loader/ # Class/service loading +│ │ ├── maven/ # Maven utilities +│ │ └── resource/ # Resource management +│ ├── src/main/resources/ +│ │ ├── logback.xml # Logging configuration +│ │ ├── logback-verbose.xml # Verbose logging configuration +│ │ └── templates/ # HTML report templates +│ │ ├── logo.svg +│ │ ├── single_plugin_report.html +│ │ └── summary_report.html +│ └── src/test/ # Unit tests +│ ├── java/ +│ └── resources/ # Test fixtures +└── linter-cli/ # CLI interface + └── src/main/java/dev/dsf/linter/ + ├── Main.java # CLI entry point + ├── LinterExecutor.java # Execution wrapper + └── ResultPrinter.java # Result formatting +``` + +### Key Components + +| Component | Purpose | +|-----------|---------| +| `DsfLinter` | Main orchestrator coordinating all linting phases | +| `ProjectSetupHandler` | Handles JAR extraction and classloader setup | +| `ResourceDiscoveryService` | Discovers plugins, BPMN files, and FHIR resources | +| `BpmnLintingService` | Orchestrates BPMN validation | +| `FhirLintingService` | Orchestrates FHIR resource validation | +| `PluginLintingService` | Validates plugin configuration and ServiceLoader registration | +| `PluginLintingOrchestrator` | Coordinates per-plugin linting workflow | +| `LeftoverResourceDetector` | Identifies unreferenced resources | +| `LintingReportGenerator` | Generates HTML and JSON reports | +| `InputResolver` | Resolves and downloads remote JAR files | +| `BpmnModelLinter` | Validates BPMN model structure and elements | +| `FhirResourceLinter` | Validates FHIR resources using pluggable linters | + +### Linting Phases + +The linter executes in five phases: + +#### Phase 1: Project Setup + +1. **Input Validation**: + - Validates that input is a JAR file + - Checks file existence or URL accessibility + +2. **JAR Extraction**: + - Downloads remote JAR files if needed + - Extracts JAR contents to temporary directory + - Preserves directory structure + +3. **Classloader Setup**: + - Creates project-specific classloader + - Loads plugin classes and dependencies + - Sets up context classloader for resource access + +#### Phase 2: Resource Discovery + +1. **Plugin Discovery**: + - Scans `META-INF/services/` for plugin registrations + - Loads plugin classes + - Detects API version (v1 or v2) + +2. **BPMN Discovery**: + - Scans `bpe/` directory for BPMN files + - Parses BPMN files to extract process definitions + - Maps BPMN files to plugins + +3. **FHIR Discovery**: + - Scans `fhir/` directory for FHIR resources + - Organizes resources by type + - Maps FHIR resources to plugins + +4. **Reference Mapping**: + - Extracts BPMN references to FHIR resources + - Maps FHIR resource references + - Identifies cross-references + +#### Phase 3: Linting + +1. **Per-Plugin Linting**: + - For each discovered plugin: + - Validates BPMN processes + - Validates FHIR resources + - Validates plugin configuration + - Collects lint items + +2. **Project-Level Analysis**: + - Performs leftover resource analysis + - Aggregates referenced resources across all plugins + - Identifies unreferenced resources + +3. **Result Aggregation**: + - Combines results from all plugins + - Calculates totals (errors, warnings) + - Determines overall success status + +#### Phase 4: Report Generation + +1. **HTML Report Generation**: + - Generates summary page + - Generates detailed plugin pages + - Applies templates and styling + +2. **JSON Report Generation** (if requested): + - Serializes all results to JSON + - Includes metadata and statistics + - Provides machine-readable format + +#### Phase 5: Summary + +1. **Console Output**: + - Displays execution summary + - Shows error and warning counts + - Reports execution time + +2. **Exit Code Determination**: + - Sets exit code based on results + - Respects `--no-fail` flag + - Returns appropriate status code + +### Design Patterns + +The linter uses several design patterns: + +- **Template Method Pattern**: Abstract base classes define linting algorithm structure +- **Strategy Pattern**: Pluggable linters for different resource types +- **Factory Pattern**: Classloader and service creation +- **Service Locator Pattern**: Plugin discovery via ServiceLoader +- **Builder Pattern**: Configuration and result objects + +### Thread Safety + +- Most components are stateless and thread-safe +- Classloader isolation ensures no cross-plugin interference +- Temporary context classloader used for resource access +- Result objects are immutable + +## Development + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **IDE**: IntelliJ IDEA, Eclipse, or VS Code (optional) + +### IDE Setup + +1. **Import Project**: + - Import as Maven project + - Set JDK to 17 or higher + - Ensure Maven dependencies are resolved + +2. **Code Style** (optional): + - Configure code formatter + - Set up import organization + - Configure line endings + +3. **Run Configuration**: + - Create run configuration for `Main.java` + - Set program arguments: `--path --html --verbose` + - Configure working directory + +### Building + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster iteration +mvn clean package -DskipTests + +# Verbose Maven output +mvn clean package -X + +# Build only specific module +mvn clean package -pl linter-core + +# Install to local Maven repository +mvn clean install +``` + +### Testing + +```bash +# Run all tests +mvn test + +# Run specific test class +mvn test -Dtest=BpmnLoadingTest + +# Run specific test method +mvn test -Dtest=BpmnLoadingTest#testLoadBpmn + +# Run tests with verbose output +mvn test -X + +# Skip tests during build +mvn clean package -DskipTests + +# Run tests with coverage (if configured) +mvn test jacoco:report +``` + +### Development Workflow + +```bash +# 1. Make changes to source code +vim linter-core/src/main/java/dev/dsf/linter/service/BpmnLintingService.java + +# 2. Build the project +mvn clean package -DskipTests + +# 3. Test with a sample plugin +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test-plugin.jar --html --verbose + +# 4. Check the generated report +open /tmp/dsf-linter-report-test-plugin/dsf-linter-report/index.html + +# 5. Run unit tests +mvn test + +# 6. Commit changes +git add . +git commit -m "Description of changes" +``` + +### Debugging + +#### Remote Debugging + +```bash +# Start the linter with debugger enabled +java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ + -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Attach debugger from IDE to localhost:5005 +``` + +#### Logging + +The linter uses Logback for logging. Configuration files: + +- `logback.xml`: Standard logging (INFO level) +- `logback-verbose.xml`: Verbose logging (DEBUG level, activated with `--verbose`) + +Log levels: +- **ERROR**: Fatal errors and exceptions +- **WARN**: Warnings and non-fatal issues +- **INFO**: General information and progress +- **DEBUG**: Detailed debugging information (verbose mode only) + +#### Common Debugging Scenarios + +1. **Plugin Not Found**: + - Enable verbose logging + - Check ServiceLoader registration + - Verify classpath + +2. **Resource Not Found**: + - Check JAR structure + - Verify resource paths + - Enable verbose logging + +3. **Class Loading Issues**: + - Check classloader setup + - Verify dependencies + - Check API version compatibility + +### Code Style Guidelines + +- Follow Java naming conventions +- Use meaningful variable and method names +- Add JavaDoc comments for public APIs +- Keep methods focused and small +- Use immutable objects where possible +- Handle exceptions appropriately +- Write unit tests for new features + +## Troubleshooting + +### "Input must be a JAR file" Error + +**Problem**: The linter only accepts JAR files as input. + +**Solution**: +```bash +# Wrong - Maven project directly +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project --html + +# Correct - Build first, then lint JAR +cd /path/to/project && mvn clean package +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +### JAR File Not Found + +**Problem**: The specified JAR file path cannot be found. + +**Solution**: Verify the path and use absolute paths if needed: + +```bash +# Windows +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path "C:\Users\Username\project\target\plugin.jar" --html + +# Linux/Mac +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /home/username/project/target/plugin.jar --html +``` + +### Missing Dependencies + +**Problem**: ClassNotFoundException or similar errors during linting. + +**Solution**: +```bash +# Check Maven settings +ls ~/.m2/settings.xml + +# Use verbose mode to see detailed error messages +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Check if dependencies are in the JAR +jar -tf plugin.jar | grep -i "class" +``` + +### Report Not Generated + +**Problem**: No report files are created. + +**Solution**: +```bash +# --html or --json flag must be set +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html # ← Required + +# Use absolute path for report directory +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --report-path $(pwd)/reports + +# Check write permissions +ls -ld /tmp/dsf-linter-report-* +``` + +### Remote JAR Download Error + +**Problem**: Cannot download JAR from remote URL. + +**Solution**: +```bash +# Test download separately +curl -L -o test.jar https://example.com/plugin.jar + +# Verify the download +ls -lh test.jar + +# Check network connectivity +ping example.com + +# Then use the local file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test.jar --html +``` + +### Plugin Not Found + +**Problem**: "No plugins found" message. + +**Solution**: +- Verify ServiceLoader registration exists in `META-INF/services/` +- Check that plugin class is in the JAR file +- Ensure plugin class implements the correct interface +- Use `--verbose` to see detailed discovery logs +- Check API version compatibility + +### Out of Memory Errors + +**Problem**: `OutOfMemoryError` during linting. + +**Solution**: +```bash +# Increase heap size +java -Xmx2g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html + +# For very large projects +java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +``` + +### Slow Performance + +**Problem**: Linting takes too long. + +**Solution**: +- Use `-DskipTests` during build +- Disable verbose logging in production +- Check network latency for remote JARs +- Consider increasing heap size +- Profile with JVM tools if needed + +### Class Loading Issues + +**Problem**: Classes cannot be loaded from plugin JAR. + +**Solution**: +- Verify JAR structure +- Check classpath configuration +- Ensure dependencies are included +- Use verbose mode to see classloader logs +- Check API version compatibility + +## API Reference + +### Core Classes + +#### `DsfLinter` + +Main orchestrator class for the linting process. + +**Constructor**: +```java +DsfLinter(Config config) +``` + +**Methods**: +```java +OverallLinterResult lint() throws IOException +``` + +**Usage**: +```java +DsfLinter.Config config = new DsfLinter.Config( + projectPath, + reportPath, + generateHtmlReport, + generateJsonReport, + failOnErrors, + logger +); + +DsfLinter linter = new DsfLinter(config); +DsfLinter.OverallLinterResult result = linter.lint(); +``` + +#### `DsfLinter.Config` + +Configuration record for the linter. + +**Fields**: +- `Path projectPath`: Path to the project root +- `Path reportPath`: Path for report generation +- `boolean generateHtmlReport`: Whether to generate HTML report +- `boolean generateJsonReport`: Whether to generate JSON report +- `boolean failOnErrors`: Whether to fail on errors +- `Logger logger`: Logger instance + +#### `DsfLinter.OverallLinterResult` + +Result record containing all linting results. + +**Fields**: +- `Map pluginLinter`: Results per plugin +- `LeftoverResourceDetector.AnalysisResult leftoverAnalysis`: Leftover resource analysis +- `Path masterReportPath`: Path to master report +- `long executionTimeMs`: Execution time in milliseconds +- `boolean success`: Whether linting succeeded + +**Methods**: +- `int getPluginErrors()`: Total error count from plugins +- `int getPluginWarnings()`: Total warning count from plugins +- `int getLeftoverCount()`: Count of leftover resources +- `int getTotalErrors()`: Total errors including leftovers + +#### `DsfLinter.PluginLinter` + +Linting result for a single plugin. + +**Fields**: +- `String pluginName`: Name of the plugin +- `String pluginClass`: Fully qualified class name +- `ApiVersion apiVersion`: DSF API version (V1 or V2) +- `LintingOutput output`: Detailed linting output +- `Path reportPath`: Path to generated report + +### Linting Services + +#### `BpmnLintingService` + +Service for linting BPMN files. + +**Constructor**: +```java +BpmnLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List bpmnFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `FhirLintingService` + +Service for linting FHIR resources. + +**Constructor**: +```java +FhirLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List fhirFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `PluginLintingService` + +Service for linting plugin configuration. + +**Constructor**: +```java +PluginLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lintPlugin( + Path projectPath, + PluginAdapter pluginAdapter, + ApiVersion apiVersion, + List collectedPluginItems +) throws MissingServiceRegistrationException +``` + +### Lint Items + +All lint items extend `AbstractLintItem` and implement specific interfaces. + +#### Base Classes + +- `AbstractLintItem`: Base class for all lint items +- `BpmnElementLintItem`: Base class for BPMN-specific lint items +- `FhirElementLintItem`: Base class for FHIR-specific lint items +- `PluginLintItem`: Base class for plugin-specific lint items + +#### Severity Levels + +- `ERROR`: Critical issues that must be fixed +- `WARNING`: Issues that should be addressed +- `INFO`: Informational messages +- `SUCCESS`: Validation passed successfully + +#### Common Lint Item Methods + +```java +LinterSeverity getSeverity() +String getMessage() +File getFile() +String getElement() +``` + +### Utility Classes + +#### `Logger` + +Interface for logging functionality. + +**Methods**: +```java +void error(String message) +void error(String message, Throwable throwable) +void warn(String message) +void info(String message) +void debug(String message) +``` + +#### `InputResolver` + +Resolves and processes input JAR files. + +**Methods**: +```java +Optional resolve(String inputPath) +String extractInputName(String inputPath, InputType inputType) +void cleanup(ResolutionResult resolution) +``` + +#### `ResourceDiscoveryService` + +Discovers plugins and resources. + +**Methods**: +```java +DiscoveryResult discover(ProjectContext context) +``` + +## Changelog + +### Version 1.0.0 +- Initial release +- BPMN validation +- FHIR validation +- Plugin configuration validation +- HTML report generation + diff --git a/docs/src/process-development/api-v2/tooling/validator.md b/docs/src/process-development/api-v2/tooling/validator.md deleted file mode 100644 index 8605181b4..000000000 --- a/docs/src/process-development/api-v2/tooling/validator.md +++ /dev/null @@ -1,234 +0,0 @@ ---- -title: Process Plugin Validator -icon: operate ---- -# DSF Process Plugin Validator v 1.3.0 - -## 1  Introduction - -The **DSF Validator** is a quality‑assurance tool for Digital Sample Framework (DSF) process plugins. Version **1.3.0** extends the 1.2.0 release by adding  - -* a dedicated **FHIR *Task* validator** for the base profile `dsf-task-base`, -* a **StructureDefinition validator** with slice‑aware cardinality checks,  -* enhanced terminology look‑ups via **FhirAuthorizationCache**, and -* a streamlined **CLI & Maven plugin** that share the same validation core. - -The validator now supports end‑to‑end consistency checks across BPMN models and all core FHIR artefacts used in the DSF platform. It targets **Java 21** and can be embedded in CI/CD pipelines, local project builds, or executed as a standalone JAR. - - -## 2  Project Overview - -| Component | Purpose | -| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **BPMN analysis** | Verifies Camunda‑compatible workflows (tasks, events, gateways, multi‑instance sub‑processes, field injections). | -| **FHIR analysis** | Validates XML/JSON resources against DSF profiles (ActivityDefinition, CodeSystem, Questionnaire, Task, ValueSet, *Task (base)*, StructureDefinition). | -| **Aggregator** | `FhirInstanceValidatorAggregator` discovers concrete validators and produces a single `ValidationOutput`. | -| **Authorization cache** | `FhirAuthorizationCache` holds all known DSF `CodeSystem` codes in a thread‑safe map for high‑performance terminology look‑ups. | -| **Report generator** | Writes structured JSON reports under `report/` (CLI) or `target/dsf-validation-reports/` (Maven plugin). | - -Camunda models are parsed with the **Camunda BPMN Model API** ([github.com](https://github.com/camunda/camunda-bpm-platform/blob/master/model-api/bpmn-model/README.asciidoc?utm_source=chatgpt.com)), while FHIR resources are processed via standard DOM/XPath and validated by custom DSF-specific validators augmented by DSF‑specific rule sets. - - - -## 3  Validation Scope - -### 3.1 BPMN Model Validation (module `validator‑core`) - -| Validator | BPMN elements inspected | Key DSF rules enforced | -| ----------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `BpmnTaskValidator` | `ServiceTask`, `UserTask`, `SendTask`, `ReceiveTask` | \* camunda\:class/expression must reference a Java class implementing `JavaDelegate`.
\* Field injections validated against DSF profiles (`profile`, `message-name`, `instantiatesCanonical`).
\* `UserTask → camunda:formKey` must resolve to an existing `Questionnaire` file. | -| `BpmnEventValidator` | `StartEvent`, `EndEvent`, `IntermediateCatch`, `ThrowEvent`, `BoundaryEvent` | \* Message events require a non‑blank `` and `` pointing to an `ActivityDefinition.url`.
\* Timer/signal events: ISO‑8601 expressions and registered signal definitions. | -| `BpmnGatewayAndFlowValidator` | `ExclusiveGateway`, `EventBasedGateway`, `SequenceFlow` | \* Exclusive gateways: every outgoing `SequenceFlow` needs `name + conditionExpression`.
\* Event‑based gateways: exactly one incoming flow; only allowed outgoing event types. | -| `BpmnFieldInjectionValidator` | Camunda `` | \* `profile` must reference a `StructureDefinition` in `src/main/resources/fhir/StructureDefinition`.
\* `message-name` must exist as an `input` slice in a `Task`.
\* `instantiatesCanonical` must match an existing `ActivityDefinition`. | | -------------------------------------------------------------------------------------------------------------------------- | -| `BpmnSubProcessValidator` | `SubProcess` (+ `MultiInstanceLoopCharacteristics`) | • Requires `camunda:asyncBefore="true"` for multi-instance subprocesses. • Checks loop cardinality and clean termination. | - -### 3.2 FHIR Resource Validation (module `validator‑core`) - -| DSF Profile & Class | Mandatory elements | DSF‑specific checks | Shared checks | -| ----------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | -| **ActivityDefinition 1.0.0**  `FhirActivityDefinitionValidator` | `url`, `status="unknown"`, `kind="Task"` | \* First `meta.tag` = system `…/read-access-tag`, code `ALL`.
\* `extension-process-authorization`: every requester/recipient coding must be known to the authorization cache. | Placeholder enforcement (`#{version}`, `#{date}`) | -| **CodeSystem 1.0.0**  `FhirCodeSystemValidator` | `url`, `name`, `title`, `publisher`, `content`, `caseSensitive` | \* `status="unknown"`.
\* `url` must start with `http://dsf.dev/fhir/CodeSystem/`.
\* All `concept.code` values unique; each concept needs `code + display`. | Placeholder enforcement; read‑access tag | -| **Questionnaire 1.5.0**  `FhirQuestionnaireValidator` | `meta.profile`, `url`, `version`, `date`, `status` | \* Mandatory items `business-key` & `user-task-id` (type string, `required=true`).
\* Ensures unique `linkId`; warns on non‑conformant patterns. | Placeholder enforcement; read‑access tag | -| **Task 1.0.0**  `FhirTaskValidator` | `id`, `instantiatesCanonical`, `intent`, `status` | \* Required `input` slices `message-name`, `business-key`; optional `correlation-key`.
\* Duplicate `input` slices detected via `Map` counter.
\* Output slice rules: if `status=failed` → must contain `error` slice. | Placeholder enforcement (`#{date}`, `#{organization}`); terminology look‑ups via the authorization cache | -| **ValueSet 1.0.0**  `FhirValueSetValidator` | `url`, `name`, `title`, `publisher`, `description` | \* Enforces read‑access tag.
\* `compose.include`: each `system` present; `concept.code` non‑blank and known.
\* Flags duplicate concepts within the same `include` block. | Placeholder enforcement (`#{version}`, `#{date}`) | -| **StructureDefinition 1.0.0**  `FhirStructureDefinitionValidator`
(**NEW in v1.3.0**) | `meta.profile`, `differential`, `url` | \* Must contain `meta.tag` & `meta.profile`.
\* `version` and `date` fields require `#{version}` / `#{date}` placeholders.
\* No `snapshot` allowed; all element `@id`s unique.
\* **Slice cardinality**: min/max constraints are verified for each slice using rules from FHIR §5.1.0.14 ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)). | Placeholder enforcement; read‑access tag | - -### 3.3 Cross‑resource Consistency - -*The validator resolves every `` to its canonical URL and verifies that a corresponding `ActivityDefinition.url` exists. Field injections (`profile`, `message-name`, `instantiatesCanonical`) are likewise cross-checked against the available FHIR artefacts to ensure that referenced canonicals exist. **Slice-level conformity to the referenced `StructureDefinition` is not evaluated.*** - - -## 4  Validation Approach - -1. **File discovery** – Recursively searches for either full Maven-style paths (e.g., `src/main/resources/bpe`) or flat folder names (e.g., `bpe`). Supports both Maven projects and unpacked JARs in CI. -2. **BPMN pass** – Camunda Model API parses the model; validators run sequentially. -3. **FHIR pass** – XML/JSON files stream through `FhirInstanceValidatorAggregator`, which delegates to each concrete validator. -4. **Slice cardinality checks** – For every `StructureDefinition`, the validator loads min/max values of the base and sliced elements and enforces them according to FHIR profiling rules §5.1.0.14 ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)). -5. **Terminology** – `FhirAuthorizationCache` accelerates terminology look-ups (read-access tags, concept codes). Authorization checks for requester/recipient organisations rely on these look-ups at run time but are not cached.* -6. **Output generation** – All validation items are collected, sorted, and written to JSON reports. - - - -## 5  Implementation & Components - -``` -validator-core - ├─ BpmnModelValidator - │ ├─ BpmnEventValidator - │ ├─ BpmnGatewayAndFlowValidator - │ ├─ BpmnTaskValidator - │ ├─ BpmnFieldInjectionValidator - │ └─ BpmnSubProcessValidator - ├─ AbstractFhirInstanceValidator (base class) - │ ├─ FhirActivityDefinitionValidator - │ ├─ FhirCodeSystemValidator - │ ├─ FhirQuestionnaireValidator - │ ├─ FhirTaskValidator - │ ├─ FhirValueSetValidator - │ ├─ FhirStructureDefinitionValidator ← NEW - ├─ FhirResourceValidator - ├─ FhirInstanceValidatorAggregator - ├─ FhirAuthorizationCache - ├─ ValidationOutput (print + JSON export) - ├─ ReportCleaner - ├─ ApiVersionDetector / ApiVersionHolder - ├─ MavenBuilder - └─ DsfValidatorImpl -validator-cli - └─ Main (Picocli CLI entry point) -validator-maven-plugin - └─ ValidateMojo (goal bound to *verify* phase) -``` - - - -## 6  Build System & Dependencies - -* **Apache Maven** – multi‑module build (`dsf-validator`, `validator-core`, `validator-api`, `validator-cli`). -* **Java 21** target, **Byte Buddy** for test instrumentation. -* External libraries: Camunda BPMN Model API ([github.com](https://github.com/camunda/camunda-bpm-platform/blob/master/model-api/bpmn-model/README.asciidoc?utm_source=chatgpt.com)), **Picocli**, **JGit**, **Jackson**, **JUnit 5**, **Mockito**. - - - - -## 7 Running the Validator - -The DSF Validator supports multiple execution environments: - -| **Scenario** | **Command / Configuration** | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **CLI – local folder** | `java -jar dsf-validator-1.3.0.jar --localPath /path/to/project` | -| **CLI – remote Git repo** | `java -jar dsf-validator-1.3.0.jar --remoteRepo https://gitlab.com/org/repo.git` | -| **Maven (one-shot)** | `mvn dev.dsf.utils.validator:validator-maven-plugin:verify` | -| **Maven (POM snippet)** | `xml

dev.dsf.utils.validator
validator-maven-plugin
1.2


verify
verify


` | -| **CI Pipeline (GitLab)** | See below – fully automated GitLab CI validation pipeline using containerized validator image | - ---- - -### Maven Plugin Features - -* Runs during `verify`, `compile`, or `install` phase. -* Validates BPMN models (`src/main/resources/bpe`) and FHIR resources (`src/main/resources/fhir`). -* Reports are written to: - `target/dsf-validation-reports/` - -**Example Output Structure:** - -``` -target/dsf-validation-reports/ -├── bpmnReports/ -│ ├── success/ -│ ├── other/ -│ └── bpmn_issues_aggregated.json -├── fhirReports/ -│ ├── success/ -│ ├── other/ -│ └── fhir_issues_aggregated.json -└── aggregated.json -``` -The validator automatically runs -`mvn clean package dependency:copy-dependencies` before analysis. - ---- - -### GitLab CI Pipeline Features - -The DSF validation pipeline enables automated quality checks of submitted plugins using Dockerized jobs. - -#### **Pipeline Overview** - -```yaml -# Example job in .gitlab-ci.yml -analyze-dsf-validator: - stage: analyze - image: - name: registry.it.hs-heilbronn.de/dsf/qs/hub-qa-pipeline/dsf-validator:1.2-3 - entrypoint: [""] - dependencies: [build1] - script: - - java -jar /opt/validator/validator.jar --localPath output - - mkdir -p "$CI_PROJECT_DIR/reports/dsf-validator" - - cp -r report/* "$CI_PROJECT_DIR/reports/dsf-validator/" || true -``` - -#### **Features** - -* **Input:** Validated plugin is extracted from the submitted JAR. -* **Execution flow:** - - * `build1` stage prepares the plugin. - * `analyze-dsf-validator` performs static validation of BPMN and FHIR resources. - * `collect-reports` aggregates results from all analyzers into `final-reports/`. - -#### **Outputs** - -All JSON-formatted validation results are stored as GitLab artifacts under: - -``` -final-reports/ -└── dsf-validator/ - ├── bpmnReports/ - ├── fhirReports/ - └── aggregated.json -``` - -#### **Requirements** - -* Internet access (for downloading dependencies and validator image) -* Maven-compatible environment -* Container image: - `registry.it.hs-heilbronn.de/dsf/qs/hub-qa-pipeline/dsf-validator:1.2-3` - - ---- - -## 8  Data Processing & Storage - -Validation items are materialised as `BpmnElementValidationItem` or `FhirElementValidationItem` and serialised to JSON. The **top‑level `aggregated.json`** summarises overall status (`ERROR` / `WARN` / `INFO` / `SUCCESS`). - - -## 9  Execution Workflow - -1. **RepositoryManager** clones remote sources if requested. -2. **MavenBuilder** compiles the project. -3. **BpmnModelValidator** & **FhirInstanceValidatorAggregator** perform analysis. -4. **ReportCleaner** purges previous results; writers store fresh reports. -5. **ApiVersionDetector** prints the detected DSF BPE API version (v1 or v2). - - -## 10  Expected Output - -* **Errors** – fatal; block deployment. -* **Warnings** – non‑fatal but may break runtime paths. -* **Info** – best‑practice hints (e.g. missing `display` in `CodeSystem.concept`). - -Developers review `report/aggregated.json` or per‑file reports under `success/` and `other/`. - -## 11  Conclusion - -Version **1.3.0** turns the DSF Validator into a *profile‑aware* verification tool: - -* It validates every BPMN construct and all core FHIR artefacts *plus* the DSF‑specific `dsf-task-base` profile and StructureDefinitions. -* It caches authorised `CodeSystem` codes, enforces slice cardinalities ([build.fhir.org](https://build.fhir.org/profiling.html?utm_source=chatgpt.com)), and guards core metadata placeholders. -* It can be launched via an intuitive CLI or a zero‑configuration Maven plugin, making it an early quality gate that helps DSF process authors catch structural, semantic, and interoperability issues long before deployment. - From e025c2ca8c82ae9b500f3356391832bf6f20fc1b Mon Sep 17 00:00:00 2001 From: Serap Aydin Date: Tue, 25 Nov 2025 16:10:25 +0100 Subject: [PATCH 2/5] - new pages for phases, development, validation and general documentation - new sidebar update - Api v2 linter tool redirects to Api v1 linter tool because we currently don't have any difference --- docs/src/.vuepress/theme.ts | 19 +- .../api-v1/tooling/linter-tool.md | 1744 ----------------- .../api-v1/tooling/linter-tool/development.md | 134 ++ .../api-v1/tooling/linter-tool/linter-tool.md | 703 +++++++ .../api-v1/tooling/linter-tool/phases.md | 86 + .../tooling/linter-tool/troubleshooting.md | 138 ++ .../api-v1/tooling/linter-tool/validation.md | 648 ++++++ .../api-v2/tooling/linter-tool.md | 1744 ----------------- .../api-v2/tooling/linter-tool/linter-tool.md | 5 + 9 files changed, 1728 insertions(+), 3493 deletions(-) delete mode 100644 docs/src/process-development/api-v1/tooling/linter-tool.md create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool/development.md create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool/phases.md create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md create mode 100644 docs/src/process-development/api-v1/tooling/linter-tool/validation.md delete mode 100644 docs/src/process-development/api-v2/tooling/linter-tool.md create mode 100644 docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts index 0fd9b5782..81d4f5008 100644 --- a/docs/src/.vuepress/theme.ts +++ b/docs/src/.vuepress/theme.ts @@ -223,14 +223,18 @@ export default hopeTheme({ ], }, ], - }, "create", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", { + }, "create", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", { text: "Process Plugin Dev Tools", icon: "info", - prefix: "tooling", + children: [{ + text: "DSF Linter Tool", + icon: "operate", + prefix: "tooling/linter-tool", collapsible: true, children: [ - "linter-tool",], - },] + "linter-tool", "validation","phases", "development", "troubleshooting"], + },]} + ] }, { text: "API v2", @@ -312,10 +316,15 @@ export default hopeTheme({ }, "implementation", "migration", "create", "best-practices", "testing", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", { text: "Process Plugin Dev Tools", icon: "info", - prefix: "tooling", + children: [{ + text: "DSF Linter Tool", + icon: "operate", + prefix: "tooling/linter-tool", collapsible: true, children: [ "linter-tool"], + }, + ] },] }, ], diff --git a/docs/src/process-development/api-v1/tooling/linter-tool.md b/docs/src/process-development/api-v1/tooling/linter-tool.md deleted file mode 100644 index b960c28a2..000000000 --- a/docs/src/process-development/api-v1/tooling/linter-tool.md +++ /dev/null @@ -1,1744 +0,0 @@ ---- -title: DSF Linter -icon: operate ---- -# DSF Linter - Complete Documentation - -A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. - -## Table of Contents - -1. [Overview](#overview) -2. [Quick Start](#quick-start) -3. [Installation](#installation) -4. [Usage](#usage) -5. [CLI Options](#cli-options) -6. [Validation Rules](#validation-rules) -7. [Report Generation](#report-generation) -8. [Architecture](#architecture) -9. [Development](#development) -10. [Troubleshooting](#troubleshooting) -11. [API Reference](#api-reference) - -## Overview - -The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: - -- **BPMN Process Definitions**: Validates Camunda BPMN 2.0 models, task implementations, event configurations, and FHIR resource references -- **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources -- **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure - -### Key Features - -- ✅ Validates BPMN processes against DSF conventions -- ✅ Validates FHIR resources against DSF profiles and HL7 specifications -- ✅ Detects unreferenced (leftover) resources -- ✅ Generates detailed HTML and JSON reports -- ✅ Supports local and remote JAR file input -- ✅ Multi-plugin project support -- ✅ CI/CD integration ready -- ✅ Comprehensive error reporting with severity levels -- ✅ Extensible architecture for custom validation rules - -### What is DSF? - -The Data Sharing Framework (DSF) is a framework for implementing interoperable healthcare data sharing processes. DSF process plugins contain: - -- **BPMN Processes**: Business process definitions using Camunda BPMN 2.0 -- **FHIR Resources**: Healthcare data resources conforming to HL7 FHIR specifications -- **Plugin Classes**: Java classes implementing the DSF ProcessPlugin interface - -## Quick Start - -### Build the Project - -```bash -# Full build with tests -mvn clean package - -# Skip tests for faster build -mvn clean package -DskipTests - -# Verbose output -mvn clean package -X -``` - -### Basic Usage - -```bash -# Lint a local JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path your-plugin.jar --html - -# Lint a remote JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html - -# View report at: /tmp/dsf-linter-report-/dsf-linter-report/index.html -``` - -## Installation - -### Requirements - -- **Java**: 17 or higher -- **Maven**: 3.6 or higher -- **Operating System**: Windows, Linux, or macOS - -### Building from Source - -```bash -# Clone the repository -git clone -cd dsf-linter - -# Build the project -mvn clean package - -# The executable JAR will be at: -# linter-cli/target/linter-cli-1.0-SNAPSHOT.jar -``` - -### Distribution - -The linter is distributed as a single executable JAR file that includes all dependencies. After building, the JAR can be used standalone: - -```bash -# Copy to a convenient location -cp linter-cli/target/linter-cli-1.0-SNAPSHOT.jar ~/bin/dsf-linter.jar - -# Use from anywhere -java -jar ~/bin/dsf-linter.jar --path plugin.jar --html -``` - -## Usage - -### Input Types - -The linter accepts only **JAR files** as input: - -| Input Type | Example | Description | -|------------|---------|-------------| -| Local JAR | `--path C:\path\to\plugin.jar` | JAR file in local filesystem | -| Remote JAR | `--path https://example.com/plugin.jar` | JAR file via HTTP/HTTPS URL | - -**Important:** Maven projects must first be built with `mvn clean package` before the resulting JAR file can be linted. - -### Expected JAR Structure - -The linter expects the following structure in the JAR file: - -``` -plugin.jar -├── META-INF/ -│ └── services/ -│ ├── dev.dsf.bpe.process.ProcessPlugin (v1) -│ └── dev.dsf.bpe.process.v2.ProcessPlugin (v2) -├── bpe/ -│ └── *.bpmn (BPMN process definitions) -└── fhir/ - ├── ActivityDefinition/ - │ └── *.xml or *.json - ├── Task/ - │ └── *.xml or *.json - ├── StructureDefinition/ - │ └── *.xml or *.json - ├── ValueSet/ - │ └── *.xml or *.json - ├── CodeSystem/ - │ └── *.xml or *.json - └── Questionnaire/ - └── *.xml or *.json -``` - -### Usage Examples - -#### Basic Linting - -```bash -# Local JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path C:\path\to\plugin.jar --html - -# Remote JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html -``` - -#### Advanced Configuration - -```bash -# Multiple report formats with custom path -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --json --report-path ./reports - -# Verbose output with colored console -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose --color - -# Lint Maven project (two-step process) -# Step 1: Build the project -cd /path/to/project && mvn clean package - -# Step 2: Lint the resulting JAR -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project/target/my-plugin-1.0.0.jar --html -``` - -#### CI/CD Integration - -```bash -# GitHub Actions / GitLab CI -FORCE_COLOR=1 java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --json --verbose - -# Jenkins (fail on errors) -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html -# Exit code: 0 = success, 1 = errors - -# Don't fail build (gradual adoption) -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --no-fail -``` - -## CLI Options - -| Option | Short | Description | Required | -|--------|-------|-------------|----------| -| `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | -| `--html` | | Generate HTML report | No | -| `--json` | | Generate JSON report | No | -| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | -| `--verbose` | `-v` | Enable verbose logging output | No | -| `--color` | | Enable colored console output | No | -| `--no-fail` | | Exit with code 0 even if linter errors are found | No | -| `--help` | `-h` | Display help message | No | -| `--version` | | Display version information | No | - -### Environment Variables - -| Variable | Effect | -|----------|--------| -| `NO_COLOR` | Disables colored output | -| `FORCE_COLOR` | Forces colored output (useful in CI) | -| `TERM=dumb` | Disables colored output | -| `WT_SESSION`, `ANSICON` | Windows color detection | - -### Exit Codes - -| Code | Meaning | -|------|---------| -| 0 | Success (no errors, or `--no-fail` was used) | -| 1 | Failure (errors found, or fatal error occurred) | - -## Validation Rules - -The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. - -### BPMN Validation - -The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. - -#### Task Validation - -##### Service Tasks - -- **Name Validation**: - - Task must have a non-empty name - - Error: `BpmnServiceTaskNameEmptyLintItem` - -- **Implementation Class Validation**: - - `camunda:class` or `camunda:delegateExpression` must be specified - - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` - - Implementation class must exist in the classpath - - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` - - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` - - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` - - Class must implement DSF-specific task interface (if applicable) - - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` - -##### User Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Form Key Validation**: - - `camunda:formKey` must be present and valid - - Must reference a valid Questionnaire resource - -- **Listener Validation**: - - Listener classes must exist - - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` - - Listener must have class attribute - - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` - - Listener must extend/implement required class - - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` - -##### Send Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Implementation Class Validation**: - - Implementation class must exist - - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` - - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` - - Class must implement required interface - - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` - -- **Field Injection Validation**: - - Message-related field injections must be valid - - FHIR resource references must be correct - -##### Receive Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Message Definition Validation**: - - Message definition must be valid - - FHIR message name cross-checks - -#### Event Validation - -##### Message Events (Start/Intermediate/End) - -- **Event Name Validation**: - - Event must have a non-empty name - - Error: `BpmnEventNameEmptyLintItem` - - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` - - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` - - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` - -- **Implementation Class Validation**: - - For send events, implementation class must exist - - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` - - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` - - Class must implement JavaDelegate - - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` - - Intermediate throw events should not have message definitions - - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` - - Throw events must implement required interface - - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` - -- **Field Injection Validation**: - - `profile` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionProfileEmptyLintItem` - - Must contain version placeholder `#{version}` - - Error: `BpmnFieldInjectionProfileNoVersionPlaceholderLintItem` - - Must reference existing StructureDefinition - - Error: `BpmnNoStructureDefinitionFoundForMessageLintItem` - - - `messageName` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionMessageValueEmptyLintItem` - - Must be a string literal - - Error: `BpmnFieldInjectionNotStringLiteralLintItem` - - - `instantiatesCanonical` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionInstantiatesCanonicalEmptyLintItem` - - Must end with version placeholder `|#{version}` - - Error: `BpmnFieldInjectionInstantiatesCanonicalNoVersionPlaceholderLintItem` - - Must reference existing ActivityDefinition - - Error: `BpmnNoActivityDefinitionFoundForMessageLintItem` - -##### Timer Events - -- **Time Expression Validation**: - - Time cycle/date/duration expressions must be valid - - Placeholder usage validation - -##### Error Boundary Events - -- **Error Configuration Validation**: - - Error reference must be present - - Error code must not be empty - - Error: `BpmnErrorBoundaryEventErrorCodeEmptyLintItem` - - Error name must not be empty (warning) - - Error: `BpmnErrorBoundaryEventErrorNameEmptyLintItem` - - Error: `BpmnErrorBoundaryEventNameEmptyLintItem` - - Error code variable must not be empty - - Error: `BpmnErrorBoundaryEventErrorCodeVariableEmptyLintItem` - -##### Signal Events - -- **Signal Definition Validation**: - - Signal definitions must be valid - - Signal references must be correct - -##### Conditional Events - -- **Condition Expression Validation**: - - Condition expressions must be valid - -#### Gateway and Flow Validation - -##### Exclusive Gateways - -- **Sequence Flow Validation**: - - Outgoing sequence flows must have appropriate names - - Conditional expressions required when multiple paths exist - - Default flow validation - -##### Inclusive Gateways - -- **Sequence Flow Validation**: - - Similar requirements as exclusive gateways - - Multiple path handling - -##### Event-Based Gateways - -- **Configuration Validation**: - - Proper configuration required - - Outgoing flow setup validation - -##### Sequence Flows - -- **Naming and Conditions**: - - Naming conventions - - Conditional expressions for non-default flows from splitting gateways - - Error: `BpmnFlowElementLintItem` - -#### SubProcess Validation - -##### Multi-Instance SubProcesses - -- **Asynchronous Execution**: - - `asyncBefore` must be set to `true` for proper asynchronous execution - - Required for multi-instance subprocesses - -##### Start/End Events in SubProcesses - -- **Structural Validation**: - - Start events must be part of subprocess - - Error: `BpmnStartEventNotPartOfSubProcessLintItem` - - End events must be part of subprocess - - Error: `BpmnEndEventNotPartOfSubProcessLintItem` - -#### Floating Elements - -- **Element Placement**: - - Elements must be properly connected - - Error: `BpmnFloatingElementLintItem` - -#### Unknown Field Injections - -- **Field Injection Validation**: - - Only known field injections are allowed - - Error: `BpmnUnknownFieldInjectionLintItem` - -### FHIR Resource Validation - -The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. - -#### Task Resources - -Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). - -##### Metadata and Profile Validation - -- **Profile Validation**: - - `meta.profile` must be present and point to a DSF Task profile - - Error: `FhirTaskMissingProfileLintItem` - - Profile must be loadable - - Error: `FhirTaskCouldNotLoadProfileLintItem` - -- **InstantiatesCanonical Validation**: - - `instantiatesCanonical` must be present - - Error: `FhirTaskMissingInstantiatesCanonicalLintItem` - - Must end with version placeholder `|#{version}` - - Error: `FhirTaskInstantiatesCanonicalPlaceholderLintItem` - - Must reference existing ActivityDefinition - - Error: `FhirTaskUnknownInstantiatesCanonicalLintItem` - -##### Fixed Elements - -- **Status Validation**: - - `status` must be present - - Error: `FhirTaskMissingStatusLintItem` - - Must be `"draft"` for template Task instances - - Error: `FhirTaskStatusNotDraftLintItem` - - Must be a valid TaskStatus value - - Error: `FhirTaskUnknownStatusLintItem` - -- **Intent Validation**: - - `intent` must be `"order"` - - Error: `FhirTaskValueIsNotSetAsOrderLintItem` - -- **Requester Validation**: - - Requester must be present - - Error: `FhirTaskMissingRequesterLintItem` - - `requester.identifier.system` must be `http://dsf.dev/sid/organization-identifier` - - Error: `FhirTaskInvalidRequesterLintItem` - - `requester.identifier.value` must be `#{organization}` (development) - - Error: `FhirTaskRequesterOrganizationNoPlaceholderLintItem` - - Error: `FhirTaskRequesterIdNoPlaceholderLintItem` - - Error: `FhirTaskRequesterIdNotExistLintItem` - -- **Recipient Validation**: - - Recipient must be present - - Error: `FhirTaskMissingRecipientLintItem` - - `restriction.recipient.identifier.system` must be `http://dsf.dev/sid/organization-identifier` - - Error: `FhirTaskInvalidRecipientLintItem` - - `restriction.recipient.identifier.value` must be `#{organization}` (development) - - Error: `FhirTaskRecipientOrganizationNoPlaceholderLintItem` - - Error: `FhirTaskRecipientIdNoPlaceholderLintItem` - - Error: `FhirTaskRecipientIdNotExistLintItem` - -##### Development Placeholders - -- **Date Placeholder**: - - `authoredOn` must contain `#{date}` - - Error: `FhirTaskDateNoPlaceholderLintItem` - -##### Task.input Validation - -- **Input Presence**: - - `Task.input` must not be empty - - Error: `FhirTaskMissingInputLintItem` - -- **Structural Validation**: - - Each input must have `type.coding.system` and `type.coding.code` - - Error: `FhirTaskInputRequiredCodingSystemAndCodingCodeLintItem` - - Each input must have a `value[x]` element - - Error: `FhirTaskInputMissingValueLintItem` - -- **Duplicate Detection**: - - No two inputs may share the same `system#code` combination - - Error: `FhirTaskInputDuplicateSliceLintItem` - -- **BPMN Slice Validation**: - - `message-name` slice: Required (min=1, max=1) - - Error: `FhirTaskRequiredInputWithCodeMessageNameLintItem` - - `business-key` slice: - - Required when status is "in-progress", "completed", or "failed" - - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` - - Must be absent when status is "draft" - - Error: `FhirTaskBusinessKeyExistsLintItem` - - `correlation-key` slice: - - Validated against StructureDefinition cardinality - - Error: `FhirTaskCorrelationExistsLintItem` - - Error: `FhirTaskCorrelationMissingButRequiredLintItem` - -- **Cardinality Validation**: - - Total input count validated against base cardinality - - Error: `FhirTaskInputInstanceCountBelowMinLintItem` - - Error: `FhirTaskInputInstanceCountExceedsMaxLintItem` - - Slice occurrence counts validated against slice-specific cardinality - - Error: `FhirTaskInputSliceCountBelowSliceMinLintItem` - - Error: `FhirTaskInputSliceCountExceedsSliceMaxLintItem` - -- **Terminology Validation**: - - Code/system combinations validated against DSF CodeSystems - - Error: `FhirTaskUnknownCodeLintItem` - -#### StructureDefinition Resources - -StructureDefinition resources are validated against DSF-specific constraints. - -##### Metadata Validation - -- **Read Access Tag**: - - Must contain valid read-access tag - - Error: `FhirStructureDefinitionMissingReadAccessTagLintItem` - -- **URL Validation**: - - `url` must be present and non-empty - - Error: `FhirStructureDefinitionMissingUrlLintItem` - -- **Status Validation**: - - `status` must be `"unknown"` (DSF convention) - - Error: `FhirStructureDefinitionInvalidStatusLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - `version` must contain exactly `#{version}` - - Error: `FhirStructureDefinitionVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - `date` must contain exactly `#{date}` - - Error: `FhirStructureDefinitionDateNoPlaceholderLintItem` - -##### Structure Validation - -- **Differential**: - - `differential` element must exist - - Error: `FhirStructureDefinitionMissingDifferentialLintItem` - -- **Snapshot**: - - `snapshot` element should not be present (warning) - - Error: `FhirStructureDefinitionSnapshotPresentLintItem` - -- **Element IDs**: - - Every `element` must have an `@id` attribute - - Error: `FhirStructureDefinitionElementWithoutIdLintItem` - - Element IDs must be unique - - Error: `FhirStructureDefinitionDuplicateElementIdLintItem` - -##### Slice Cardinality Validation - -According to FHIR profiling specification §5.1.0.14: - -- **SHOULD Rule**: - - Sum of all slice minimum cardinalities should be ≤ base element's minimum - - Error: `FhirStructureDefinitionSliceMinSumAboveBaseMinLintItem` - -- **MUST Rule (Min Sum)**: - - Sum of all slice minimum cardinalities must not exceed base element's maximum - - Error: `FhirStructureDefinitionSliceMinSumExceedsMaxLintItem` - -- **MUST Rule (Slice Max)**: - - No individual slice's maximum cardinality may exceed base element's maximum - - Error: `FhirStructureDefinitionSliceMaxExceedsBaseMaxLintItem` - -#### ValueSet Resources - -ValueSet resources are validated against the DSF ValueSet base profile. - -##### Metadata Validation - -- **Read Access Tags**: - - Must contain at least one read-access tag (ALL or LOCAL) - - Error: `FhirValueSetMissingReadAccessTagAllOrLocalLintItem` - - Organization role codes must be valid - - Error: `FhirValueSetOrganizationRoleMissingValidCodeValueLintItem` - -- **Required Elements**: - - `url` must be present - - Error: `FhirValueSetMissingUrlLintItem` - - `name` must be present - - Error: `FhirValueSetMissingNameLintItem` - - `title` must be present - - Error: `FhirValueSetMissingTitleLintItem` - - `publisher` must be present - - Error: `FhirValueSetMissingPublisherLintItem` - - `description` must be present - - Error: `FhirValueSetMissingDescriptionLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - `version` must be `#{version}` - - Error: `FhirValueSetVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - `date` must be `#{date}` - - Error: `FhirValueSetDateNoPlaceholderLintItem` - -- **Include Version Placeholder**: - - `compose.include.version` must be `#{version}` - - Error: `FhirValueSetIncludeVersionPlaceholderLintItem` - -##### Compose Structure Validation - -- **Include Elements**: - - At least one `compose.include` required - - Error: `FhirValueSetMissingComposeIncludeLintItem` - - Each include must have a `system` attribute - - Error: `FhirValueSetIncludeMissingSystemLintItem` - -- **Concept Validation**: - - Concept codes must be non-blank - - Error: `FhirValueSetConceptMissingCodeLintItem` - - Duplicate codes detected - - Error: `FhirValueSetDuplicateConceptCodeLintItem` - -##### Terminology Compliance - -- **CodeSystem Validation**: - - CodeSystem URLs validated against DSF terminology cache - - Error: `FhirValueSetUnknownCodeLintItem` - - Code exists but in different CodeSystem - - Error: `FhirValueSetFalseUrlReferencedLintItem` - -#### ActivityDefinition Resources - -##### Profile Validation - -- **Profile**: - - Must have valid profile - - Error: `FhirActivityDefinitionMissingProfileLintItem` - - Profile must not have version number - - Error: `FhirActivityDefinitionProfileHasVersionNumberLintItem` - -##### URL Validation - -- **URL Format**: - - URL must be valid - - Error: `FhirActivityDefinitionInvalidFhirUrlLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirActivityDefinitionInvalidFhirStatusLintItem` - -##### Authorization Validation - -- **Requester**: - - Requester entry must be present - - Error: `FhirActivityDefinitionEntryMissingRequesterLintItem` - - Requester entry must be valid - - Error: `FhirActivityDefinitionEntryInvalidRequesterLintItem` - -- **Recipient**: - - Recipient entry must be present - - Error: `FhirActivityDefinitionEntryMissingRecipientLintItem` - - Recipient entry must be valid - - Error: `FhirActivityDefinitionEntryInvalidRecipientLintItem` - -#### CodeSystem Resources - -##### Metadata Validation - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirCodeSystemMissingReadAccessTagLintItem` - -- **Required Elements**: - - Required elements must be present - - Error: `FhirCodeSystemMissingElementLintItem` - -##### URL Validation - -- **URL Format**: - - URL must be valid - - Error: `FhirCodeSystemInvalidUrlLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirCodeSystemInvalidStatusLintItem` - -##### Concept Validation - -- **Concepts**: - - Must have at least one concept - - Error: `FhirCodeSystemMissingConceptLintItem` - - Concepts must have code - - Error: `FhirCodeSystemConceptMissingCodeLintItem` - - Concepts must have display - - Error: `FhirCodeSystemConceptMissingDisplayLintItem` - - Duplicate codes detected - - Error: `FhirCodeSystemDuplicateCodeLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - Version must be `#{version}` - - Error: `FhirCodeSystemVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - Date must be `#{date}` - - Error: `FhirCodeSystemDateNoPlaceholderLintItem` - -#### Questionnaire Resources - -##### Metadata Validation - -- **Meta Profile**: - - Must have meta profile - - Error: `FhirQuestionnaireMissingMetaProfileLintItem` - - Meta profile must be valid - - Error: `FhirQuestionnaireInvalidMetaProfileLintItem` - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirQuestionnaireMissingReadAccessTagLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirQuestionnaireInvalidStatusLintItem` - -##### Item Validation - -- **Items**: - - Must have at least one item - - Error: `FhirQuestionnaireMissingItemLintItem` - - Items must have linkId - - Error: `FhirQuestionnaireItemMissingAttributesLinkIdLintItem` - - Items must have text - - Error: `FhirQuestionnaireItemMissingAttributesTextLintItem` - - Items must have type - - Error: `FhirQuestionnaireItemMissingAttributesTypeLintItem` - - Link IDs must be unique - - Error: `FhirQuestionnaireDuplicateLinkIdLintItem` - - Unusual link IDs detected - - Error: `FhirQuestionnaireUnusualLinkIdLintItem` - -##### Mandatory Item Validation - -- **Required Items**: - - Mandatory items must be required - - Error: `FhirQuestionnaireMandatoryItemNotRequiredLintItem` - - Mandatory items must have valid type - - Error: `FhirQuestionnaireMandatoryItemInvalidTypeLintItem` - -##### Definition Validation - -- **Definition**: - - Definition must be valid - - Error: `FhirQuestionnaireDefinitionLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - Version must be `#{version}` - - Error: `FhirQuestionnaireVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - Date must be `#{date}` - - Error: `FhirQuestionnaireDateNoPlaceholderLintItem` - -#### Common FHIR Validations - -##### Access Tag Validation - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirMissingFhirAccessTagLintItem` - - Access tag must be valid - - Error: `FhirInvalidFhirAccessTagLintItem` - -##### Kind Validation - -- **Kind**: - - Kind must be present - - Error: `FhirKindIsMissingOrEmptyLintItem` - - Kind must be "Task" for Task resources - - Error: `FhirKindNotSetAsTaskLintItem` - -##### Status Validation - -- **Status**: - - Status must be "unknown" (DSF convention) - - Error: `FhirStatusIsNotSetAsUnknownLintItem` - -##### Extension Validation - -- **Process Authorization Extension**: - - Must have process authorization extension - - Error: `FhirNoExtensionProcessAuthorizationFoundLintItem` - -### Plugin Configuration Validation - -#### ServiceLoader Registration - -- **Registration File**: - - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) - - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` - - Plugin class must be loadable - - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` - -#### Resource References - -- **BPMN File References**: - - BPMN files referenced in plugin must exist - - Error: `PluginDefinitionBpmnFileReferencedButNotFoundLintItem` - - BPMN files must be in expected root - - Error: `PluginDefinitionBpmnFileReferencedFoundOutsideExpectedRootLintItem` - - BPMN files must be parsable - - Error: `PluginDefinitionUnparsableBpmnResourceLintItem` - -- **FHIR File References**: - - FHIR resources referenced in BPMN must exist - - Error: `PluginDefinitionFhirFileReferencedButNotFoundLintItem` - - FHIR resources must be in expected root - - Error: `PluginDefinitionFhirFileReferencedFoundOutsideExpectedRootLintItem` - - FHIR resources must be parsable - - Error: `PluginDefinitionUnparsableFhirResourceLintItem` - -#### Resource Presence - -- **BPMN Processes**: - - At least one BPMN process must be defined - - Error: `PluginDefinitionNoProcessModelDefinedLintItem` - -- **FHIR Resources**: - - At least one FHIR resource must be defined - - Error: `PluginDefinitionNoFhirResourcesDefinedLintItem` - -#### Leftover Resource Detection - -The linter performs project-level analysis to identify unreferenced resources: - -- **Unreferenced BPMN Files**: - - BPMN files that are not referenced by any plugin - - Reported as warnings - -- **Unreferenced FHIR Resources**: - - FHIR resources that are not referenced by any BPMN process - - Reported as warnings - -This analysis works uniformly for single-plugin and multi-plugin projects. - -## Report Generation - -### Report Structure - -Reports are generated in the following structure: - -``` -/ -├── index.html # Summary report (all plugins) -├── plugin-name.html # Detailed report for each plugin -└── plugin-name.json # JSON report (if --json specified) -``` - -### HTML Report - -The HTML report provides a comprehensive, human-readable view of all linting results. - -#### Summary Page (`index.html`) - -The summary page includes: - -- **Header**: - - DSF Linter version - - Execution timestamp - - Project path - -- **Overall Statistics**: - - Total number of plugins - - Total errors - - Total warnings - - Execution time - -- **Plugin Summary Table**: - - Plugin name - - API version - - Error count - - Warning count - - Link to detailed report - -- **Leftover Resource Summary**: - - Unreferenced BPMN files - - Unreferenced FHIR resources - -#### Plugin Report (`plugin-name.html`) - -Each plugin has a detailed report page containing: - -- **Plugin Metadata**: - - Plugin name - - Plugin class name - - API version (v1 or v2) - -- **BPMN Validation Results**: - - List of all BPMN files - - Errors and warnings per file - - Detailed error messages with file and line references - -- **FHIR Validation Results**: - - List of all FHIR resources by type - - Errors and warnings per resource - - Detailed error messages with element paths - -- **Plugin Configuration Results**: - - ServiceLoader registration status - - Resource reference validation results - -- **Leftover Resource Analysis**: - - Unreferenced BPMN files - - Unreferenced FHIR resources - -- **Severity Indicators**: - - Color-coded severity levels (ERROR, WARNING, INFO, SUCCESS) - - Expandable/collapsible sections - -### JSON Report - -The JSON report provides machine-readable output for CI/CD integration and automated processing. - -#### Structure - -```json -{ - "version": "1.0.0", - "timestamp": "2024-01-15T10:30:00Z", - "projectPath": "/path/to/plugin.jar", - "executionTimeMs": 2300, - "success": true, - "summary": { - "totalPlugins": 1, - "totalErrors": 0, - "totalWarnings": 1, - "totalLeftoverBpmn": 0, - "totalLeftoverFhir": 0 - }, - "plugins": { - "plugin-name": { - "name": "plugin-name", - "class": "dev.dsf.bpe.plugin.ExamplePlugin", - "apiVersion": "V1", - "errors": 0, - "warnings": 1, - "bpmnFiles": [ - { - "path": "bpe/process.bpmn", - "errors": 0, - "warnings": 1, - "items": [...] - } - ], - "fhirResources": { - "ActivityDefinition": [...], - "Task": [...], - "StructureDefinition": [...] - }, - "pluginConfig": { - "serviceLoaderRegistered": true, - "items": [...] - } - } - }, - "leftoverAnalysis": { - "unreferencedBpmn": [], - "unreferencedFhir": [] - } -} -``` - -#### Lint Item Structure - -Each lint item in the JSON report has the following structure: - -```json -{ - "severity": "ERROR", - "type": "BpmnServiceTaskNameEmptyLintItem", - "message": "Service task must have a non-empty name", - "file": "bpe/process.bpmn", - "element": "ServiceTask_1", - "line": 42, - "column": 10 -} -``` - -### Example Console Output - -``` -DSF Linter v1.0.0 -================================================================= -Project: /path/to/plugin.jar -Report: /tmp/dsf-linter-report-plugin/dsf-linter-report -================================================================= - -Phase 1: Project Setup -✓ JAR file validated -✓ Resources extracted - -Phase 2: Resource Discovery -✓ Found 1 plugin(s) -✓ Plugin: my-process-plugin - - BPMN: 2 files - - FHIR: 15 resources - -Phase 3: Linting -✓ BPMN validation: 0 errors, 1 warning -✓ FHIR validation: 0 errors, 0 warnings -✓ Plugin validation: 0 errors - -Phase 4: Report Generation -✓ HTML report generated - -Summary -================================================================= -✓ SUCCESS - No errors found - Plugins: 1 - Errors: 0 - Warnings: 1 - Execution time: 2.3s -================================================================= -``` - -## Architecture - -### Project Structure - -``` -dsf-linter/ -├── linter-core/ # Core linting logic -│ ├── src/main/java/dev/dsf/linter/ -│ │ ├── analysis/ # Resource analysis -│ │ │ └── LeftoverResourceDetector.java -│ │ ├── bpmn/ # BPMN parsing & validation -│ │ │ ├── BpmnLinter.java -│ │ │ ├── BpmnModelLinter.java -│ │ │ ├── BpmnTaskLinter.java -│ │ │ ├── BpmnEventLinter.java -│ │ │ ├── BpmnGatewayAndFlowLinter.java -│ │ │ └── BpmnSubProcessLinter.java -│ │ ├── fhir/ # FHIR parsing & validation -│ │ │ ├── FhirResourceLinter.java -│ │ │ ├── FhirTaskLinter.java -│ │ │ ├── FhirStructureDefinitionLinter.java -│ │ │ ├── FhirValueSetLinter.java -│ │ │ ├── FhirActivityDefinitionLinter.java -│ │ │ ├── FhirCodeSystemLinter.java -│ │ │ └── FhirQuestionnaireLinter.java -│ │ ├── service/ # Linting services -│ │ │ ├── BpmnLintingService.java -│ │ │ ├── FhirLintingService.java -│ │ │ ├── PluginLintingService.java -│ │ │ └── PluginLintingOrchestrator.java -│ │ ├── output/ # Lint item definitions -│ │ │ └── item/ # Specific lint items (200+ classes) -│ │ ├── report/ # Report generation -│ │ │ └── LintingReportGenerator.java -│ │ ├── input/ # Input handling & JAR processing -│ │ │ └── InputResolver.java -│ │ ├── setup/ # Project setup & building -│ │ │ └── ProjectSetupHandler.java -│ │ ├── plugin/ # Plugin definition discovery -│ │ │ └── PluginDefinitionDiscovery.java -│ │ ├── classloading/ # Dynamic class loading -│ │ │ ├── ProjectClassLoaderFactory.java -│ │ │ └── ClassInspector.java -│ │ ├── logger/ # Logging infrastructure -│ │ │ ├── Logger.java -│ │ │ ├── ConsoleLogger.java -│ │ │ └── Console.java -│ │ ├── constants/ # Constants & configuration -│ │ │ └── DsfApiConstants.java -│ │ ├── exception/ # Custom exceptions -│ │ │ ├── ResourceLinterException.java -│ │ │ └── MissingServiceRegistrationException.java -│ │ └── util/ # Utilities -│ │ ├── api/ # API version detection -│ │ ├── cache/ # Caching utilities -│ │ ├── converter/ # Format converters -│ │ ├── linting/ # Linting utilities -│ │ ├── loader/ # Class/service loading -│ │ ├── maven/ # Maven utilities -│ │ └── resource/ # Resource management -│ ├── src/main/resources/ -│ │ ├── logback.xml # Logging configuration -│ │ ├── logback-verbose.xml # Verbose logging configuration -│ │ └── templates/ # HTML report templates -│ │ ├── logo.svg -│ │ ├── single_plugin_report.html -│ │ └── summary_report.html -│ └── src/test/ # Unit tests -│ ├── java/ -│ └── resources/ # Test fixtures -└── linter-cli/ # CLI interface - └── src/main/java/dev/dsf/linter/ - ├── Main.java # CLI entry point - ├── LinterExecutor.java # Execution wrapper - └── ResultPrinter.java # Result formatting -``` - -### Key Components - -| Component | Purpose | -|-----------|---------| -| `DsfLinter` | Main orchestrator coordinating all linting phases | -| `ProjectSetupHandler` | Handles JAR extraction and classloader setup | -| `ResourceDiscoveryService` | Discovers plugins, BPMN files, and FHIR resources | -| `BpmnLintingService` | Orchestrates BPMN validation | -| `FhirLintingService` | Orchestrates FHIR resource validation | -| `PluginLintingService` | Validates plugin configuration and ServiceLoader registration | -| `PluginLintingOrchestrator` | Coordinates per-plugin linting workflow | -| `LeftoverResourceDetector` | Identifies unreferenced resources | -| `LintingReportGenerator` | Generates HTML and JSON reports | -| `InputResolver` | Resolves and downloads remote JAR files | -| `BpmnModelLinter` | Validates BPMN model structure and elements | -| `FhirResourceLinter` | Validates FHIR resources using pluggable linters | - -### Linting Phases - -The linter executes in five phases: - -#### Phase 1: Project Setup - -1. **Input Validation**: - - Validates that input is a JAR file - - Checks file existence or URL accessibility - -2. **JAR Extraction**: - - Downloads remote JAR files if needed - - Extracts JAR contents to temporary directory - - Preserves directory structure - -3. **Classloader Setup**: - - Creates project-specific classloader - - Loads plugin classes and dependencies - - Sets up context classloader for resource access - -#### Phase 2: Resource Discovery - -1. **Plugin Discovery**: - - Scans `META-INF/services/` for plugin registrations - - Loads plugin classes - - Detects API version (v1 or v2) - -2. **BPMN Discovery**: - - Scans `bpe/` directory for BPMN files - - Parses BPMN files to extract process definitions - - Maps BPMN files to plugins - -3. **FHIR Discovery**: - - Scans `fhir/` directory for FHIR resources - - Organizes resources by type - - Maps FHIR resources to plugins - -4. **Reference Mapping**: - - Extracts BPMN references to FHIR resources - - Maps FHIR resource references - - Identifies cross-references - -#### Phase 3: Linting - -1. **Per-Plugin Linting**: - - For each discovered plugin: - - Validates BPMN processes - - Validates FHIR resources - - Validates plugin configuration - - Collects lint items - -2. **Project-Level Analysis**: - - Performs leftover resource analysis - - Aggregates referenced resources across all plugins - - Identifies unreferenced resources - -3. **Result Aggregation**: - - Combines results from all plugins - - Calculates totals (errors, warnings) - - Determines overall success status - -#### Phase 4: Report Generation - -1. **HTML Report Generation**: - - Generates summary page - - Generates detailed plugin pages - - Applies templates and styling - -2. **JSON Report Generation** (if requested): - - Serializes all results to JSON - - Includes metadata and statistics - - Provides machine-readable format - -#### Phase 5: Summary - -1. **Console Output**: - - Displays execution summary - - Shows error and warning counts - - Reports execution time - -2. **Exit Code Determination**: - - Sets exit code based on results - - Respects `--no-fail` flag - - Returns appropriate status code - -### Design Patterns - -The linter uses several design patterns: - -- **Template Method Pattern**: Abstract base classes define linting algorithm structure -- **Strategy Pattern**: Pluggable linters for different resource types -- **Factory Pattern**: Classloader and service creation -- **Service Locator Pattern**: Plugin discovery via ServiceLoader -- **Builder Pattern**: Configuration and result objects - -### Thread Safety - -- Most components are stateless and thread-safe -- Classloader isolation ensures no cross-plugin interference -- Temporary context classloader used for resource access -- Result objects are immutable - -## Development - -### Requirements - -- **Java**: 17 or higher -- **Maven**: 3.6 or higher -- **IDE**: IntelliJ IDEA, Eclipse, or VS Code (optional) - -### IDE Setup - -1. **Import Project**: - - Import as Maven project - - Set JDK to 17 or higher - - Ensure Maven dependencies are resolved - -2. **Code Style** (optional): - - Configure code formatter - - Set up import organization - - Configure line endings - -3. **Run Configuration**: - - Create run configuration for `Main.java` - - Set program arguments: `--path --html --verbose` - - Configure working directory - -### Building - -```bash -# Full build with tests -mvn clean package - -# Skip tests for faster iteration -mvn clean package -DskipTests - -# Verbose Maven output -mvn clean package -X - -# Build only specific module -mvn clean package -pl linter-core - -# Install to local Maven repository -mvn clean install -``` - -### Testing - -```bash -# Run all tests -mvn test - -# Run specific test class -mvn test -Dtest=BpmnLoadingTest - -# Run specific test method -mvn test -Dtest=BpmnLoadingTest#testLoadBpmn - -# Run tests with verbose output -mvn test -X - -# Skip tests during build -mvn clean package -DskipTests - -# Run tests with coverage (if configured) -mvn test jacoco:report -``` - -### Development Workflow - -```bash -# 1. Make changes to source code -vim linter-core/src/main/java/dev/dsf/linter/service/BpmnLintingService.java - -# 2. Build the project -mvn clean package -DskipTests - -# 3. Test with a sample plugin -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path test-plugin.jar --html --verbose - -# 4. Check the generated report -open /tmp/dsf-linter-report-test-plugin/dsf-linter-report/index.html - -# 5. Run unit tests -mvn test - -# 6. Commit changes -git add . -git commit -m "Description of changes" -``` - -### Debugging - -#### Remote Debugging - -```bash -# Start the linter with debugger enabled -java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ - -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose - -# Attach debugger from IDE to localhost:5005 -``` - -#### Logging - -The linter uses Logback for logging. Configuration files: - -- `logback.xml`: Standard logging (INFO level) -- `logback-verbose.xml`: Verbose logging (DEBUG level, activated with `--verbose`) - -Log levels: -- **ERROR**: Fatal errors and exceptions -- **WARN**: Warnings and non-fatal issues -- **INFO**: General information and progress -- **DEBUG**: Detailed debugging information (verbose mode only) - -#### Common Debugging Scenarios - -1. **Plugin Not Found**: - - Enable verbose logging - - Check ServiceLoader registration - - Verify classpath - -2. **Resource Not Found**: - - Check JAR structure - - Verify resource paths - - Enable verbose logging - -3. **Class Loading Issues**: - - Check classloader setup - - Verify dependencies - - Check API version compatibility - -### Code Style Guidelines - -- Follow Java naming conventions -- Use meaningful variable and method names -- Add JavaDoc comments for public APIs -- Keep methods focused and small -- Use immutable objects where possible -- Handle exceptions appropriately -- Write unit tests for new features - -## Troubleshooting - -### "Input must be a JAR file" Error - -**Problem**: The linter only accepts JAR files as input. - -**Solution**: -```bash -# Wrong - Maven project directly -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project --html - -# Correct - Build first, then lint JAR -cd /path/to/project && mvn clean package -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project/target/my-plugin-1.0.0.jar --html -``` - -### JAR File Not Found - -**Problem**: The specified JAR file path cannot be found. - -**Solution**: Verify the path and use absolute paths if needed: - -```bash -# Windows -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path "C:\Users\Username\project\target\plugin.jar" --html - -# Linux/Mac -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /home/username/project/target/plugin.jar --html -``` - -### Missing Dependencies - -**Problem**: ClassNotFoundException or similar errors during linting. - -**Solution**: -```bash -# Check Maven settings -ls ~/.m2/settings.xml - -# Use verbose mode to see detailed error messages -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose - -# Check if dependencies are in the JAR -jar -tf plugin.jar | grep -i "class" -``` - -### Report Not Generated - -**Problem**: No report files are created. - -**Solution**: -```bash -# --html or --json flag must be set -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html # ← Required - -# Use absolute path for report directory -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --report-path $(pwd)/reports - -# Check write permissions -ls -ld /tmp/dsf-linter-report-* -``` - -### Remote JAR Download Error - -**Problem**: Cannot download JAR from remote URL. - -**Solution**: -```bash -# Test download separately -curl -L -o test.jar https://example.com/plugin.jar - -# Verify the download -ls -lh test.jar - -# Check network connectivity -ping example.com - -# Then use the local file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path test.jar --html -``` - -### Plugin Not Found - -**Problem**: "No plugins found" message. - -**Solution**: -- Verify ServiceLoader registration exists in `META-INF/services/` -- Check that plugin class is in the JAR file -- Ensure plugin class implements the correct interface -- Use `--verbose` to see detailed discovery logs -- Check API version compatibility - -### Out of Memory Errors - -**Problem**: `OutOfMemoryError` during linting. - -**Solution**: -```bash -# Increase heap size -java -Xmx2g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html - -# For very large projects -java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html -``` - -### Slow Performance - -**Problem**: Linting takes too long. - -**Solution**: -- Use `-DskipTests` during build -- Disable verbose logging in production -- Check network latency for remote JARs -- Consider increasing heap size -- Profile with JVM tools if needed - -### Class Loading Issues - -**Problem**: Classes cannot be loaded from plugin JAR. - -**Solution**: -- Verify JAR structure -- Check classpath configuration -- Ensure dependencies are included -- Use verbose mode to see classloader logs -- Check API version compatibility - -## API Reference - -### Core Classes - -#### `DsfLinter` - -Main orchestrator class for the linting process. - -**Constructor**: -```java -DsfLinter(Config config) -``` - -**Methods**: -```java -OverallLinterResult lint() throws IOException -``` - -**Usage**: -```java -DsfLinter.Config config = new DsfLinter.Config( - projectPath, - reportPath, - generateHtmlReport, - generateJsonReport, - failOnErrors, - logger -); - -DsfLinter linter = new DsfLinter(config); -DsfLinter.OverallLinterResult result = linter.lint(); -``` - -#### `DsfLinter.Config` - -Configuration record for the linter. - -**Fields**: -- `Path projectPath`: Path to the project root -- `Path reportPath`: Path for report generation -- `boolean generateHtmlReport`: Whether to generate HTML report -- `boolean generateJsonReport`: Whether to generate JSON report -- `boolean failOnErrors`: Whether to fail on errors -- `Logger logger`: Logger instance - -#### `DsfLinter.OverallLinterResult` - -Result record containing all linting results. - -**Fields**: -- `Map pluginLinter`: Results per plugin -- `LeftoverResourceDetector.AnalysisResult leftoverAnalysis`: Leftover resource analysis -- `Path masterReportPath`: Path to master report -- `long executionTimeMs`: Execution time in milliseconds -- `boolean success`: Whether linting succeeded - -**Methods**: -- `int getPluginErrors()`: Total error count from plugins -- `int getPluginWarnings()`: Total warning count from plugins -- `int getLeftoverCount()`: Count of leftover resources -- `int getTotalErrors()`: Total errors including leftovers - -#### `DsfLinter.PluginLinter` - -Linting result for a single plugin. - -**Fields**: -- `String pluginName`: Name of the plugin -- `String pluginClass`: Fully qualified class name -- `ApiVersion apiVersion`: DSF API version (V1 or V2) -- `LintingOutput output`: Detailed linting output -- `Path reportPath`: Path to generated report - -### Linting Services - -#### `BpmnLintingService` - -Service for linting BPMN files. - -**Constructor**: -```java -BpmnLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lint( - String pluginName, - List bpmnFiles, - List missingRefs, - Map outsideRoot, - Map fromDependencies, - File pluginResourceRoot -) -``` - -#### `FhirLintingService` - -Service for linting FHIR resources. - -**Constructor**: -```java -FhirLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lint( - String pluginName, - List fhirFiles, - List missingRefs, - Map outsideRoot, - Map fromDependencies, - File pluginResourceRoot -) -``` - -#### `PluginLintingService` - -Service for linting plugin configuration. - -**Constructor**: -```java -PluginLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lintPlugin( - Path projectPath, - PluginAdapter pluginAdapter, - ApiVersion apiVersion, - List collectedPluginItems -) throws MissingServiceRegistrationException -``` - -### Lint Items - -All lint items extend `AbstractLintItem` and implement specific interfaces. - -#### Base Classes - -- `AbstractLintItem`: Base class for all lint items -- `BpmnElementLintItem`: Base class for BPMN-specific lint items -- `FhirElementLintItem`: Base class for FHIR-specific lint items -- `PluginLintItem`: Base class for plugin-specific lint items - -#### Severity Levels - -- `ERROR`: Critical issues that must be fixed -- `WARNING`: Issues that should be addressed -- `INFO`: Informational messages -- `SUCCESS`: Validation passed successfully - -#### Common Lint Item Methods - -```java -LinterSeverity getSeverity() -String getMessage() -File getFile() -String getElement() -``` - -### Utility Classes - -#### `Logger` - -Interface for logging functionality. - -**Methods**: -```java -void error(String message) -void error(String message, Throwable throwable) -void warn(String message) -void info(String message) -void debug(String message) -``` - -#### `InputResolver` - -Resolves and processes input JAR files. - -**Methods**: -```java -Optional resolve(String inputPath) -String extractInputName(String inputPath, InputType inputType) -void cleanup(ResolutionResult resolution) -``` - -#### `ResourceDiscoveryService` - -Discovers plugins and resources. - -**Methods**: -```java -DiscoveryResult discover(ProjectContext context) -``` - -## Changelog - -### Version 1.0.0 -- Initial release -- BPMN validation -- FHIR validation -- Plugin configuration validation -- HTML report generation - diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/development.md b/docs/src/process-development/api-v1/tooling/linter-tool/development.md new file mode 100644 index 000000000..b339ba566 --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool/development.md @@ -0,0 +1,134 @@ +--- +title: Development +--- + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **IDE**: IntelliJ IDEA, Eclipse, or VS Code (optional) + +### IDE Setup + +1. **Import Project**: + - Import as Maven project + - Set JDK to 17 or higher + - Ensure Maven dependencies are resolved + +2. **Code Style** (optional): + - Configure code formatter + - Set up import organization + - Configure line endings + +3. **Run Configuration**: + - Create run configuration for `Main.java` + - Set program arguments: `--path --html --verbose` + - Configure working directory + +### Building + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster iteration +mvn clean package -DskipTests + +# Verbose Maven output +mvn clean package -X + +# Build only specific module +mvn clean package -pl linter-core + +# Install to local Maven repository +mvn clean install +``` + +### Testing + +```bash +# Run all tests +mvn test + +# Run specific test class +mvn test -Dtest=BpmnLoadingTest + +# Run specific test method +mvn test -Dtest=BpmnLoadingTest#testLoadBpmn + +# Run tests with verbose output +mvn test -X + +# Skip tests during build +mvn clean package -DskipTests + +# Run tests with coverage (if configured) +mvn test jacoco:report +``` + +### Development Workflow + +```bash +# 1. Make changes to source code +vim linter-core/src/main/java/dev/dsf/linter/service/BpmnLintingService.java + +# 2. Build the project +mvn clean package -DskipTests + +# 3. Test with a sample plugin +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test-plugin.jar --html --verbose + +# 4. Check the generated report +open /tmp/dsf-linter-report-test-plugin/dsf-linter-report/index.html + +# 5. Run unit tests +mvn test + +# 6. Commit changes +git add . +git commit -m "Description of changes" +``` + +### Debugging + +#### Remote Debugging + +```bash +# Start the linter with debugger enabled +java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ + -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Attach debugger from IDE to localhost:5005 +``` + +#### Logging + +The linter uses Logback for logging. Configuration files: + +- `logback.xml`: Standard logging (INFO level) +- `logback-verbose.xml`: Verbose logging (DEBUG level, activated with `--verbose`) + +Log levels: +- **ERROR**: Fatal errors and exceptions +- **WARN**: Warnings and non-fatal issues +- **INFO**: General information and progress +- **DEBUG**: Detailed debugging information (verbose mode only) + +#### Common Debugging Scenarios + +1. **Plugin Not Found**: + - Enable verbose logging + - Check ServiceLoader registration + - Verify classpath + +2. **Resource Not Found**: + - Check JAR structure + - Verify resource paths + - Enable verbose logging + +3. **Class Loading Issues**: + - Check classloader setup + - Verify dependencies + - Check API version compatibility \ No newline at end of file diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md b/docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md new file mode 100644 index 000000000..a29853f2c --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md @@ -0,0 +1,703 @@ +--- +title: Linter Tool +--- + +A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. + +## Table of Contents + +1. [Overview](#overview) +2. [Quick Start](#quick-start) +3. [Installation](#installation) +4. [Usage](#usage) +5. [CLI Options](#cli-options) +7. [Report Generation](#report-generation) +8. [Architecture](#architecture) +11. [API Reference](#api-reference) + +## Overview + +The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: + +- **BPMN Process Definitions**: Validates Camunda/Operaton BPMN 2.0 models, task implementations, event configurations, and FHIR resource references +- **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources +- **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure + +### Key Features + +- ✅ Validates BPMN processes against DSF conventions +- ✅ Validates FHIR resources against DSF profiles and HL7 specifications +- ✅ Detects unreferenced (leftover) resources +- ✅ Generates detailed HTML and JSON reports +- ✅ Supports local and remote JAR file input +- ✅ Multi-plugin project support +- ✅ CI/CD integration ready +- ✅ Comprehensive error reporting with severity levels +- ✅ Extensible architecture for custom validation rules + +## Quick Start + +### Build the Project + +```bash +# Full build with tests +mvn clean package + +# Skip tests for faster build +mvn clean package -DskipTests + +# Verbose output +mvn clean package -X +``` + +### Basic Usage + +```bash +# Lint a local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path your-plugin.jar --html + +# Lint a remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html + +# View report at: /tmp/dsf-linter-report-/dsf-linter-report/index.html +``` + +## Installation + +### Requirements + +- **Java**: 17 or higher +- **Maven**: 3.6 or higher +- **Operating System**: Windows, Linux, or macOS + +### Building from Source + +```bash +# Clone the repository +git clone +cd dsf-linter + +# Build the project +mvn clean package + +# The executable JAR will be at: +# linter-cli/target/linter-cli-1.0-SNAPSHOT.jar +``` + +### Distribution + +The linter is distributed as a single executable JAR file that includes all dependencies. After building, the JAR can be used standalone: + +```bash +# Copy to a convenient location +cp linter-cli/target/linter-cli-1.0-SNAPSHOT.jar ~/bin/dsf-linter.jar + +# Use from anywhere +java -jar ~/bin/dsf-linter.jar --path plugin.jar --html +``` + +## Usage + +### Input Types + +The linter accepts only **JAR files** as input: + +| Input Type | Example | Description | +|------------|---------|-------------| +| Local JAR | `--path C:\path\to\plugin.jar` | JAR file in local filesystem | +| Remote JAR | `--path https://example.com/plugin.jar` | JAR file via HTTP/HTTPS URL | + +**Important:** Maven projects must first be built with `mvn clean package` before the resulting JAR file can be linted. + +### Expected JAR Structure + +The linter expects the following structure in the JAR file: + +``` +plugin.jar +├── META-INF/ +│ └── services/ +│ ├── dev.dsf.bpe.process.ProcessPlugin (v1) +│ └── dev.dsf.bpe.process.v2.ProcessPlugin (v2) +├── bpe/ +│ └── *.bpmn (BPMN process definitions) +└── fhir/ + ├── ActivityDefinition/ + │ └── *.xml or *.json + ├── Task/ + │ └── *.xml or *.json + ├── StructureDefinition/ + │ └── *.xml or *.json + ├── ValueSet/ + │ └── *.xml or *.json + ├── CodeSystem/ + │ └── *.xml or *.json + └── Questionnaire/ + └── *.xml or *.json +``` + +### Usage Examples + +#### Basic Linting + +```bash +# Local JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path C:\path\to\plugin.jar --html + +# Remote JAR file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html +``` + +#### Advanced Configuration + +```bash +# Multiple report formats with custom path +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --report-path ./reports + +# Verbose output with colored console +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose --color + +# Lint Maven project (two-step process) +# Step 1: Build the project +cd /path/to/project && mvn clean package + +# Step 2: Lint the resulting JAR +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +#### CI/CD Integration + +```bash +# GitHub Actions / GitLab CI +FORCE_COLOR=1 java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --json --verbose + +# Jenkins (fail on errors) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +# Exit code: 0 = success, 1 = errors + +# Don't fail build (gradual adoption) +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --no-fail +``` + +## CLI Options + +| Option | Short | Description | Required | +|--------|-------|-------------|----------| +| `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | +| `--html` | | Generate HTML report | No | +| `--json` | | Generate JSON report | No | +| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | +| `--verbose` | `-v` | Enable verbose logging output | No | +| `--color` | | Enable colored console output | No | +| `--no-fail` | | Exit with code 0 even if linter errors are found | No | +| `--help` | `-h` | Display help message | No | +| `--version` | | Display version information | No | + +### Environment Variables + +| Variable | Effect | +|----------|--------| +| `NO_COLOR` | Disables colored output | +| `FORCE_COLOR` | Forces colored output (useful in CI) | +| `TERM=dumb` | Disables colored output | +| `WT_SESSION`, `ANSICON` | Windows color detection | + +### Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success (no errors, or `--no-fail` was used) | +| 1 | Failure (errors found, or fatal error occurred) | + + +## Report Generation + +### Report Structure + +Reports are generated in the following structure: + +``` +/ +├── index.html # Summary report (all plugins) +├── plugin-name.html # Detailed report for each plugin +└── plugin-name.json # JSON report (if --json specified) +``` + +### HTML Report + +The HTML report provides a comprehensive, human-readable view of all linting results. + +#### Summary Page (`index.html`) + +The summary page includes: + +- **Header**: + - DSF Linter version + - Execution timestamp + - Project path + +- **Overall Statistics**: + - Total number of plugins + - Total errors + - Total warnings + - Execution time + +- **Plugin Summary Table**: + - Plugin name + - API version + - Error count + - Warning count + - Link to detailed report + +- **Leftover Resource Summary**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +#### Plugin Report (`plugin-name.html`) + +Each plugin has a detailed report page containing: + +- **Plugin Metadata**: + - Plugin name + - Plugin class name + - API version (v1 or v2) + +- **BPMN Validation Results**: + - List of all BPMN files + - Errors and warnings per file + - Detailed error messages with file and line references + +- **FHIR Validation Results**: + - List of all FHIR resources by type + - Errors and warnings per resource + - Detailed error messages with element paths + +- **Plugin Configuration Results**: + - ServiceLoader registration status + - Resource reference validation results + +- **Leftover Resource Analysis**: + - Unreferenced BPMN files + - Unreferenced FHIR resources + +- **Severity Indicators**: + - Color-coded severity levels (ERROR, WARNING, INFO, SUCCESS) + - Expandable/collapsible sections + +### JSON Report + +The JSON report provides machine-readable output for CI/CD integration and automated processing. + +#### Structure + +```json +{ + "version": "1.0.0", + "timestamp": "2024-01-15T10:30:00Z", + "projectPath": "/path/to/plugin.jar", + "executionTimeMs": 2300, + "success": true, + "summary": { + "totalPlugins": 1, + "totalErrors": 0, + "totalWarnings": 1, + "totalLeftoverBpmn": 0, + "totalLeftoverFhir": 0 + }, + "plugins": { + "plugin-name": { + "name": "plugin-name", + "class": "dev.dsf.bpe.plugin.ExamplePlugin", + "apiVersion": "V1", + "errors": 0, + "warnings": 1, + "bpmnFiles": [ + { + "path": "bpe/process.bpmn", + "errors": 0, + "warnings": 1, + "items": [...] + } + ], + "fhirResources": { + "ActivityDefinition": [...], + "Task": [...], + "StructureDefinition": [...] + }, + "pluginConfig": { + "serviceLoaderRegistered": true, + "items": [...] + } + } + }, + "leftoverAnalysis": { + "unreferencedBpmn": [], + "unreferencedFhir": [] + } +} +``` + +#### Lint Item Structure + +Each lint item in the JSON report has the following structure: + +```json +{ + "severity": "ERROR", + "type": "BpmnServiceTaskNameEmptyLintItem", + "message": "Service task must have a non-empty name", + "file": "bpe/process.bpmn", + "element": "ServiceTask_1", + "line": 42, + "column": 10 +} +``` + +### Example Console Output + +``` +DSF Linter v1.0.0 +================================================================= +Project: /path/to/plugin.jar +Report: /tmp/dsf-linter-report-plugin/dsf-linter-report +================================================================= + +Phase 1: Project Setup +✓ JAR file validated +✓ Resources extracted + +Phase 2: Resource Discovery +✓ Found 1 plugin(s) +✓ Plugin: my-process-plugin + - BPMN: 2 files + - FHIR: 15 resources + +Phase 3: Linting +✓ BPMN validation: 0 errors, 1 warning +✓ FHIR validation: 0 errors, 0 warnings +✓ Plugin validation: 0 errors + +Phase 4: Report Generation +✓ HTML report generated + +Summary +================================================================= +✓ SUCCESS - No errors found + Plugins: 1 + Errors: 0 + Warnings: 1 + Execution time: 2.3s +================================================================= +``` + +## Architecture + +### Project Structure + +``` +dsf-linter/ +├── linter-core/ # Core linting logic +│ ├── src/main/java/dev/dsf/linter/ +│ │ ├── analysis/ # Resource analysis +│ │ │ └── LeftoverResourceDetector.java +│ │ ├── bpmn/ # BPMN parsing & validation +│ │ │ ├── BpmnLinter.java +│ │ │ ├── BpmnModelLinter.java +│ │ │ ├── BpmnTaskLinter.java +│ │ │ ├── BpmnEventLinter.java +│ │ │ ├── BpmnGatewayAndFlowLinter.java +│ │ │ └── BpmnSubProcessLinter.java +│ │ ├── fhir/ # FHIR parsing & validation +│ │ │ ├── FhirResourceLinter.java +│ │ │ ├── FhirTaskLinter.java +│ │ │ ├── FhirStructureDefinitionLinter.java +│ │ │ ├── FhirValueSetLinter.java +│ │ │ ├── FhirActivityDefinitionLinter.java +│ │ │ ├── FhirCodeSystemLinter.java +│ │ │ └── FhirQuestionnaireLinter.java +│ │ ├── service/ # Linting services +│ │ │ ├── BpmnLintingService.java +│ │ │ ├── FhirLintingService.java +│ │ │ ├── PluginLintingService.java +│ │ │ └── PluginLintingOrchestrator.java +│ │ ├── output/ # Lint item definitions +│ │ │ └── item/ # Specific lint items (200+ classes) +│ │ ├── report/ # Report generation +│ │ │ └── LintingReportGenerator.java +│ │ ├── input/ # Input handling & JAR processing +│ │ │ └── InputResolver.java +│ │ ├── setup/ # Project setup & building +│ │ │ └── ProjectSetupHandler.java +│ │ ├── plugin/ # Plugin definition discovery +│ │ │ └── PluginDefinitionDiscovery.java +│ │ ├── classloading/ # Dynamic class loading +│ │ │ ├── ProjectClassLoaderFactory.java +│ │ │ └── ClassInspector.java +│ │ ├── logger/ # Logging infrastructure +│ │ │ ├── Logger.java +│ │ │ ├── ConsoleLogger.java +│ │ │ └── Console.java +│ │ ├── constants/ # Constants & configuration +│ │ │ └── DsfApiConstants.java +│ │ ├── exception/ # Custom exceptions +│ │ │ ├── ResourceLinterException.java +│ │ │ └── MissingServiceRegistrationException.java +│ │ └── util/ # Utilities +│ │ ├── api/ # API version detection +│ │ ├── cache/ # Caching utilities +│ │ ├── converter/ # Format converters +│ │ ├── linting/ # Linting utilities +│ │ ├── loader/ # Class/service loading +│ │ ├── maven/ # Maven utilities +│ │ └── resource/ # Resource management +│ ├── src/main/resources/ +│ │ ├── logback.xml # Logging configuration +│ │ ├── logback-verbose.xml # Verbose logging configuration +│ │ └── templates/ # HTML report templates +│ │ ├── logo.svg +│ │ ├── single_plugin_report.html +│ │ └── summary_report.html +│ └── src/test/ # Unit tests +│ ├── java/ +│ └── resources/ # Test fixtures +└── linter-cli/ # CLI interface + └── src/main/java/dev/dsf/linter/ + ├── Main.java # CLI entry point + ├── LinterExecutor.java # Execution wrapper + └── ResultPrinter.java # Result formatting +``` + +### Key Components + +| Component | Purpose | +|-----------|---------| +| `DsfLinter` | Main orchestrator coordinating all linting phases | +| `ProjectSetupHandler` | Handles JAR extraction and classloader setup | +| `ResourceDiscoveryService` | Discovers plugins, BPMN files, and FHIR resources | +| `BpmnLintingService` | Orchestrates BPMN validation | +| `FhirLintingService` | Orchestrates FHIR resource validation | +| `PluginLintingService` | Validates plugin configuration and ServiceLoader registration | +| `PluginLintingOrchestrator` | Coordinates per-plugin linting workflow | +| `LeftoverResourceDetector` | Identifies unreferenced resources | +| `LintingReportGenerator` | Generates HTML and JSON reports | +| `InputResolver` | Resolves and downloads remote JAR files | +| `BpmnModelLinter` | Validates BPMN model structure and elements | +| `FhirResourceLinter` | Validates FHIR resources using pluggable linters | + +## API Reference + +### Core Classes + +#### `DsfLinter` + +Main orchestrator class for the linting process. + +**Constructor**: +```java +DsfLinter(Config config) +``` + +**Methods**: +```java +OverallLinterResult lint() throws IOException +``` + +**Usage**: +```java +DsfLinter.Config config = new DsfLinter.Config( + projectPath, + reportPath, + generateHtmlReport, + generateJsonReport, + failOnErrors, + logger +); + +DsfLinter linter = new DsfLinter(config); +DsfLinter.OverallLinterResult result = linter.lint(); +``` + +#### `DsfLinter.Config` + +Configuration record for the linter. + +**Fields**: +- `Path projectPath`: Path to the project root +- `Path reportPath`: Path for report generation +- `boolean generateHtmlReport`: Whether to generate HTML report +- `boolean generateJsonReport`: Whether to generate JSON report +- `boolean failOnErrors`: Whether to fail on errors +- `Logger logger`: Logger instance + +#### `DsfLinter.OverallLinterResult` + +Result record containing all linting results. + +**Fields**: +- `Map pluginLinter`: Results per plugin +- `LeftoverResourceDetector.AnalysisResult leftoverAnalysis`: Leftover resource analysis +- `Path masterReportPath`: Path to master report +- `long executionTimeMs`: Execution time in milliseconds +- `boolean success`: Whether linting succeeded + +**Methods**: +- `int getPluginErrors()`: Total error count from plugins +- `int getPluginWarnings()`: Total warning count from plugins +- `int getLeftoverCount()`: Count of leftover resources +- `int getTotalErrors()`: Total errors including leftovers + +#### `DsfLinter.PluginLinter` + +Linting result for a single plugin. + +**Fields**: +- `String pluginName`: Name of the plugin +- `String pluginClass`: Fully qualified class name +- `ApiVersion apiVersion`: DSF API version (V1 or V2) +- `LintingOutput output`: Detailed linting output +- `Path reportPath`: Path to generated report + +### Linting Services + +#### `BpmnLintingService` + +Service for linting BPMN files. + +**Constructor**: +```java +BpmnLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List bpmnFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `FhirLintingService` + +Service for linting FHIR resources. + +**Constructor**: +```java +FhirLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lint( + String pluginName, + List fhirFiles, + List missingRefs, + Map outsideRoot, + Map fromDependencies, + File pluginResourceRoot +) +``` + +#### `PluginLintingService` + +Service for linting plugin configuration. + +**Constructor**: +```java +PluginLintingService(Logger logger) +``` + +**Methods**: +```java +LintingResult lintPlugin( + Path projectPath, + PluginAdapter pluginAdapter, + ApiVersion apiVersion, + List collectedPluginItems +) throws MissingServiceRegistrationException +``` + +### Lint Items + +All lint items extend `AbstractLintItem` and implement specific interfaces. + +#### Base Classes + +- `AbstractLintItem`: Base class for all lint items +- `BpmnElementLintItem`: Base class for BPMN-specific lint items +- `FhirElementLintItem`: Base class for FHIR-specific lint items +- `PluginLintItem`: Base class for plugin-specific lint items + +#### Severity Levels + +- `ERROR`: Critical issues that must be fixed +- `WARNING`: Issues that should be addressed +- `INFO`: Informational messages +- `SUCCESS`: Validation passed successfully + +#### Common Lint Item Methods + +```java +LinterSeverity getSeverity() +String getMessage() +File getFile() +String getElement() +``` + +### Utility Classes + +#### `Logger` + +Interface for logging functionality. + +**Methods**: +```java +void error(String message) +void error(String message, Throwable throwable) +void warn(String message) +void info(String message) +void debug(String message) +``` + +#### `InputResolver` + +Resolves and processes input JAR files. + +**Methods**: +```java +Optional resolve(String inputPath) +String extractInputName(String inputPath, InputType inputType) +void cleanup(ResolutionResult resolution) +``` + +#### `ResourceDiscoveryService` + +Discovers plugins and resources. + +**Methods**: +```java +DiscoveryResult discover(ProjectContext context) +``` + +## Changelog + +### Version 1.0.0 +- Initial release +- BPMN validation +- FHIR validation +- Plugin configuration validation +- HTML report generation + diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/phases.md b/docs/src/process-development/api-v1/tooling/linter-tool/phases.md new file mode 100644 index 000000000..5111a1938 --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool/phases.md @@ -0,0 +1,86 @@ +--- +title: Linting Phases +--- + +The linter executes in five phases: + +#### Phase 1: Project Setup + +1. **Input Validation**: + - Validates that input is a JAR file + - Checks file existence or URL accessibility + +2. **JAR Extraction**: + - Downloads remote JAR files if needed + - Extracts JAR contents to temporary directory + - Preserves directory structure + +3. **Classloader Setup**: + - Creates project-specific classloader + - Loads plugin classes and dependencies + - Sets up context classloader for resource access + +#### Phase 2: Resource Discovery + +1. **Plugin Discovery**: + - Scans `META-INF/services/` for plugin registrations + - Loads plugin classes + - Detects API version (v1 or v2) + +2. **BPMN Discovery**: + - Scans `bpe/` directory for BPMN files + - Parses BPMN files to extract process definitions + - Maps BPMN files to plugins + +3. **FHIR Discovery**: + - Scans `fhir/` directory for FHIR resources + - Organizes resources by type + - Maps FHIR resources to plugins + +4. **Reference Mapping**: + - Extracts BPMN references to FHIR resources + - Maps FHIR resource references + - Identifies cross-references + +#### Phase 3: Linting + +1. **Per-Plugin Linting**: + - For each discovered plugin: + - Validates BPMN processes + - Validates FHIR resources + - Validates plugin configuration + - Collects lint items + +2. **Project-Level Analysis**: + - Performs leftover resource analysis + - Aggregates referenced resources across all plugins + - Identifies unreferenced resources + +3. **Result Aggregation**: + - Combines results from all plugins + - Calculates totals (errors, warnings) + - Determines overall success status + +#### Phase 4: Report Generation + +1. **HTML Report Generation**: + - Generates summary page + - Generates detailed plugin pages + - Applies templates and styling + +2. **JSON Report Generation** (if requested): + - Serializes all results to JSON + - Includes metadata and statistics + - Provides machine-readable format + +#### Phase 5: Summary + +1. **Console Output**: + - Displays execution summary + - Shows error and warning counts + - Reports execution time + +2. **Exit Code Determination**: + - Sets exit code based on results + - Respects `--no-fail` flag + - Returns appropriate status code \ No newline at end of file diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md b/docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md new file mode 100644 index 000000000..b5f42642d --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md @@ -0,0 +1,138 @@ +--- +title: Troubleshooting +--- + +### "Input must be a JAR file" Error + +**Problem**: The linter only accepts JAR files as input. + +**Solution**: +```bash +# Wrong - Maven project directly +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project --html + +# Correct - Build first, then lint JAR +cd /path/to/project && mvn clean package +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /path/to/project/target/my-plugin-1.0.0.jar --html +``` + +### JAR File Not Found + +**Problem**: The specified JAR file path cannot be found. + +**Solution**: Verify the path and use absolute paths if needed: + +```bash +# Windows +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path "C:\Users\Username\project\target\plugin.jar" --html + +# Linux/Mac +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path /home/username/project/target/plugin.jar --html +``` + +### Missing Dependencies + +**Problem**: ClassNotFoundException or similar errors during linting. + +**Solution**: +```bash +# Check Maven settings +ls ~/.m2/settings.xml + +# Use verbose mode to see detailed error messages +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --verbose + +# Check if dependencies are in the JAR +jar -tf plugin.jar | grep -i "class" +``` + +### Report Not Generated + +**Problem**: No report files are created. + +**Solution**: +```bash +# --html or --json flag must be set +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html # ← Required + +# Use absolute path for report directory +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html --report-path $(pwd)/reports + +# Check write permissions +ls -ld /tmp/dsf-linter-report-* +``` + +### Remote JAR Download Error + +**Problem**: Cannot download JAR from remote URL. + +**Solution**: +```bash +# Test download separately +curl -L -o test.jar https://example.com/plugin.jar + +# Verify the download +ls -lh test.jar + +# Check network connectivity +ping example.com + +# Then use the local file +java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path test.jar --html +``` + +### Plugin Not Found + +**Problem**: "No plugins found" message. + +**Solution**: +- Verify ServiceLoader registration exists in `META-INF/services/` +- Check that plugin class is in the JAR file +- Ensure plugin class implements the correct interface +- Use `--verbose` to see detailed discovery logs +- Check API version compatibility + +### Out of Memory Errors + +**Problem**: `OutOfMemoryError` during linting. + +**Solution**: +```bash +# Increase heap size +java -Xmx2g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html + +# For very large projects +java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ + --path plugin.jar --html +``` + +### Slow Performance + +**Problem**: Linting takes too long. + +**Solution**: +- Use `-DskipTests` during build +- Disable verbose logging in production +- Check network latency for remote JARs +- Consider increasing heap size +- Profile with JVM tools if needed + +### Class Loading Issues + +**Problem**: Classes cannot be loaded from plugin JAR. + +**Solution**: +- Verify JAR structure +- Check classpath configuration +- Ensure dependencies are included +- Use verbose mode to see classloader logs +- Check API version compatibility diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/validation.md b/docs/src/process-development/api-v1/tooling/linter-tool/validation.md new file mode 100644 index 000000000..7d691aac4 --- /dev/null +++ b/docs/src/process-development/api-v1/tooling/linter-tool/validation.md @@ -0,0 +1,648 @@ +--- +title: Validation Rules +--- + +The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. + +### BPMN Validation + +The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. + +#### Task Validation + +##### Service Tasks + +- **Name Validation**: + - Task must have a non-empty name + - Error: `BpmnServiceTaskNameEmptyLintItem` + +- **Implementation Class Validation**: + - `camunda:class` or `camunda:delegateExpression` must be specified + - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` + - Implementation class must exist in the classpath + - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` + - Class must implement DSF-specific task interface (if applicable) + - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` + +##### User Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Form Key Validation**: + - `camunda:formKey` must be present and valid + - Must reference a valid Questionnaire resource + +- **Listener Validation**: + - Listener classes must exist + - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` + - Listener must have class attribute + - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` + - Listener must extend/implement required class + - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + +##### Send Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Implementation Class Validation**: + - Implementation class must exist + - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` + - Class must implement required interface + - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` + +- **Field Injection Validation**: + - Message-related field injections must be valid + - FHIR resource references must be correct + +##### Receive Tasks + +- **Name Validation**: + - Task must have a non-empty name + +- **Message Definition Validation**: + - Message definition must be valid + - FHIR message name cross-checks + +#### Event Validation + +##### Message Events (Start/Intermediate/End) + +- **Event Name Validation**: + - Event must have a non-empty name + - Error: `BpmnEventNameEmptyLintItem` + - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` + - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` + - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` + +- **Implementation Class Validation**: + - For send events, implementation class must exist + - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` + - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` + - Class must implement JavaDelegate + - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` + - Intermediate throw events should not have message definitions + - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` + - Throw events must implement required interface + - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` + +- **Field Injection Validation**: + - `profile` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionProfileEmptyLintItem` + - Must contain version placeholder `#{version}` + - Error: `BpmnFieldInjectionProfileNoVersionPlaceholderLintItem` + - Must reference existing StructureDefinition + - Error: `BpmnNoStructureDefinitionFoundForMessageLintItem` + + - `messageName` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionMessageValueEmptyLintItem` + - Must be a string literal + - Error: `BpmnFieldInjectionNotStringLiteralLintItem` + + - `instantiatesCanonical` field injection: + - Must be non-empty + - Error: `BpmnFieldInjectionInstantiatesCanonicalEmptyLintItem` + - Must end with version placeholder `|#{version}` + - Error: `BpmnFieldInjectionInstantiatesCanonicalNoVersionPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `BpmnNoActivityDefinitionFoundForMessageLintItem` + +##### Timer Events + +- **Time Expression Validation**: + - Time cycle/date/duration expressions must be valid + - Placeholder usage validation + +##### Error Boundary Events + +- **Error Configuration Validation**: + - Error reference must be present + - Error code must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeEmptyLintItem` + - Error name must not be empty (warning) + - Error: `BpmnErrorBoundaryEventErrorNameEmptyLintItem` + - Error: `BpmnErrorBoundaryEventNameEmptyLintItem` + - Error code variable must not be empty + - Error: `BpmnErrorBoundaryEventErrorCodeVariableEmptyLintItem` + +##### Signal Events + +- **Signal Definition Validation**: + - Signal definitions must be valid + - Signal references must be correct + +##### Conditional Events + +- **Condition Expression Validation**: + - Condition expressions must be valid + +#### Gateway and Flow Validation + +##### Exclusive Gateways + +- **Sequence Flow Validation**: + - Outgoing sequence flows must have appropriate names + - Conditional expressions required when multiple paths exist + - Default flow validation + +##### Inclusive Gateways + +- **Sequence Flow Validation**: + - Similar requirements as exclusive gateways + - Multiple path handling + +##### Event-Based Gateways + +- **Configuration Validation**: + - Proper configuration required + - Outgoing flow setup validation + +##### Sequence Flows + +- **Naming and Conditions**: + - Naming conventions + - Conditional expressions for non-default flows from splitting gateways + - Error: `BpmnFlowElementLintItem` + +#### SubProcess Validation + +##### Multi-Instance SubProcesses + +- **Asynchronous Execution**: + - `asyncBefore` must be set to `true` for proper asynchronous execution + - Required for multi-instance subprocesses + +##### Start/End Events in SubProcesses + +- **Structural Validation**: + - Start events must be part of subprocess + - Error: `BpmnStartEventNotPartOfSubProcessLintItem` + - End events must be part of subprocess + - Error: `BpmnEndEventNotPartOfSubProcessLintItem` + +#### Floating Elements + +- **Element Placement**: + - Elements must be properly connected + - Error: `BpmnFloatingElementLintItem` + +#### Unknown Field Injections + +- **Field Injection Validation**: + - Only known field injections are allowed + - Error: `BpmnUnknownFieldInjectionLintItem` + +### FHIR Resource Validation + +The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. + +#### Task Resources + +Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). + +##### Metadata and Profile Validation + +- **Profile Validation**: + - `meta.profile` must be present and point to a DSF Task profile + - Error: `FhirTaskMissingProfileLintItem` + - Profile must be loadable + - Error: `FhirTaskCouldNotLoadProfileLintItem` + +- **InstantiatesCanonical Validation**: + - `instantiatesCanonical` must be present + - Error: `FhirTaskMissingInstantiatesCanonicalLintItem` + - Must end with version placeholder `|#{version}` + - Error: `FhirTaskInstantiatesCanonicalPlaceholderLintItem` + - Must reference existing ActivityDefinition + - Error: `FhirTaskUnknownInstantiatesCanonicalLintItem` + +##### Fixed Elements + +- **Status Validation**: + - `status` must be present + - Error: `FhirTaskMissingStatusLintItem` + - Must be `"draft"` for template Task instances + - Error: `FhirTaskStatusNotDraftLintItem` + - Must be a valid TaskStatus value + - Error: `FhirTaskUnknownStatusLintItem` + +- **Intent Validation**: + - `intent` must be `"order"` + - Error: `FhirTaskValueIsNotSetAsOrderLintItem` + +- **Requester Validation**: + - Requester must be present + - Error: `FhirTaskMissingRequesterLintItem` + - `requester.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRequesterLintItem` + - `requester.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRequesterOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNoPlaceholderLintItem` + - Error: `FhirTaskRequesterIdNotExistLintItem` + +- **Recipient Validation**: + - Recipient must be present + - Error: `FhirTaskMissingRecipientLintItem` + - `restriction.recipient.identifier.system` must be `http://dsf.dev/sid/organization-identifier` + - Error: `FhirTaskInvalidRecipientLintItem` + - `restriction.recipient.identifier.value` must be `#{organization}` (development) + - Error: `FhirTaskRecipientOrganizationNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNoPlaceholderLintItem` + - Error: `FhirTaskRecipientIdNotExistLintItem` + +##### Development Placeholders + +- **Date Placeholder**: + - `authoredOn` must contain `#{date}` + - Error: `FhirTaskDateNoPlaceholderLintItem` + +##### Task.input Validation + +- **Input Presence**: + - `Task.input` must not be empty + - Error: `FhirTaskMissingInputLintItem` + +- **Structural Validation**: + - Each input must have `type.coding.system` and `type.coding.code` + - Error: `FhirTaskInputRequiredCodingSystemAndCodingCodeLintItem` + - Each input must have a `value[x]` element + - Error: `FhirTaskInputMissingValueLintItem` + +- **Duplicate Detection**: + - No two inputs may share the same `system#code` combination + - Error: `FhirTaskInputDuplicateSliceLintItem` + +- **BPMN Slice Validation**: + - `message-name` slice: Required (min=1, max=1) + - Error: `FhirTaskRequiredInputWithCodeMessageNameLintItem` + - `business-key` slice: + - Required when status is "in-progress", "completed", or "failed" + - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` + - Must be absent when status is "draft" + - Error: `FhirTaskBusinessKeyExistsLintItem` + - `correlation-key` slice: + - Validated against StructureDefinition cardinality + - Error: `FhirTaskCorrelationExistsLintItem` + - Error: `FhirTaskCorrelationMissingButRequiredLintItem` + +- **Cardinality Validation**: + - Total input count validated against base cardinality + - Error: `FhirTaskInputInstanceCountBelowMinLintItem` + - Error: `FhirTaskInputInstanceCountExceedsMaxLintItem` + - Slice occurrence counts validated against slice-specific cardinality + - Error: `FhirTaskInputSliceCountBelowSliceMinLintItem` + - Error: `FhirTaskInputSliceCountExceedsSliceMaxLintItem` + +- **Terminology Validation**: + - Code/system combinations validated against DSF CodeSystems + - Error: `FhirTaskUnknownCodeLintItem` + +#### StructureDefinition Resources + +StructureDefinition resources are validated against DSF-specific constraints. + +##### Metadata Validation + +- **Read Access Tag**: + - Must contain valid read-access tag + - Error: `FhirStructureDefinitionMissingReadAccessTagLintItem` + +- **URL Validation**: + - `url` must be present and non-empty + - Error: `FhirStructureDefinitionMissingUrlLintItem` + +- **Status Validation**: + - `status` must be `"unknown"` (DSF convention) + - Error: `FhirStructureDefinitionInvalidStatusLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must contain exactly `#{version}` + - Error: `FhirStructureDefinitionVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must contain exactly `#{date}` + - Error: `FhirStructureDefinitionDateNoPlaceholderLintItem` + +##### Structure Validation + +- **Differential**: + - `differential` element must exist + - Error: `FhirStructureDefinitionMissingDifferentialLintItem` + +- **Snapshot**: + - `snapshot` element should not be present (warning) + - Error: `FhirStructureDefinitionSnapshotPresentLintItem` + +- **Element IDs**: + - Every `element` must have an `@id` attribute + - Error: `FhirStructureDefinitionElementWithoutIdLintItem` + - Element IDs must be unique + - Error: `FhirStructureDefinitionDuplicateElementIdLintItem` + +##### Slice Cardinality Validation + +According to FHIR profiling specification §5.1.0.14: + +- **SHOULD Rule**: + - Sum of all slice minimum cardinalities should be ≤ base element's minimum + - Error: `FhirStructureDefinitionSliceMinSumAboveBaseMinLintItem` + +- **MUST Rule (Min Sum)**: + - Sum of all slice minimum cardinalities must not exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMinSumExceedsMaxLintItem` + +- **MUST Rule (Slice Max)**: + - No individual slice's maximum cardinality may exceed base element's maximum + - Error: `FhirStructureDefinitionSliceMaxExceedsBaseMaxLintItem` + +#### ValueSet Resources + +ValueSet resources are validated against the DSF ValueSet base profile. + +##### Metadata Validation + +- **Read Access Tags**: + - Must contain at least one read-access tag (ALL or LOCAL) + - Error: `FhirValueSetMissingReadAccessTagAllOrLocalLintItem` + - Organization role codes must be valid + - Error: `FhirValueSetOrganizationRoleMissingValidCodeValueLintItem` + +- **Required Elements**: + - `url` must be present + - Error: `FhirValueSetMissingUrlLintItem` + - `name` must be present + - Error: `FhirValueSetMissingNameLintItem` + - `title` must be present + - Error: `FhirValueSetMissingTitleLintItem` + - `publisher` must be present + - Error: `FhirValueSetMissingPublisherLintItem` + - `description` must be present + - Error: `FhirValueSetMissingDescriptionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - `version` must be `#{version}` + - Error: `FhirValueSetVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - `date` must be `#{date}` + - Error: `FhirValueSetDateNoPlaceholderLintItem` + +- **Include Version Placeholder**: + - `compose.include.version` must be `#{version}` + - Error: `FhirValueSetIncludeVersionPlaceholderLintItem` + +##### Compose Structure Validation + +- **Include Elements**: + - At least one `compose.include` required + - Error: `FhirValueSetMissingComposeIncludeLintItem` + - Each include must have a `system` attribute + - Error: `FhirValueSetIncludeMissingSystemLintItem` + +- **Concept Validation**: + - Concept codes must be non-blank + - Error: `FhirValueSetConceptMissingCodeLintItem` + - Duplicate codes detected + - Error: `FhirValueSetDuplicateConceptCodeLintItem` + +##### Terminology Compliance + +- **CodeSystem Validation**: + - CodeSystem URLs validated against DSF terminology cache + - Error: `FhirValueSetUnknownCodeLintItem` + - Code exists but in different CodeSystem + - Error: `FhirValueSetFalseUrlReferencedLintItem` + +#### ActivityDefinition Resources + +##### Profile Validation + +- **Profile**: + - Must have valid profile + - Error: `FhirActivityDefinitionMissingProfileLintItem` + - Profile must not have version number + - Error: `FhirActivityDefinitionProfileHasVersionNumberLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirActivityDefinitionInvalidFhirUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirActivityDefinitionInvalidFhirStatusLintItem` + +##### Authorization Validation + +- **Requester**: + - Requester entry must be present + - Error: `FhirActivityDefinitionEntryMissingRequesterLintItem` + - Requester entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRequesterLintItem` + +- **Recipient**: + - Recipient entry must be present + - Error: `FhirActivityDefinitionEntryMissingRecipientLintItem` + - Recipient entry must be valid + - Error: `FhirActivityDefinitionEntryInvalidRecipientLintItem` + +#### CodeSystem Resources + +##### Metadata Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirCodeSystemMissingReadAccessTagLintItem` + +- **Required Elements**: + - Required elements must be present + - Error: `FhirCodeSystemMissingElementLintItem` + +##### URL Validation + +- **URL Format**: + - URL must be valid + - Error: `FhirCodeSystemInvalidUrlLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirCodeSystemInvalidStatusLintItem` + +##### Concept Validation + +- **Concepts**: + - Must have at least one concept + - Error: `FhirCodeSystemMissingConceptLintItem` + - Concepts must have code + - Error: `FhirCodeSystemConceptMissingCodeLintItem` + - Concepts must have display + - Error: `FhirCodeSystemConceptMissingDisplayLintItem` + - Duplicate codes detected + - Error: `FhirCodeSystemDuplicateCodeLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirCodeSystemVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirCodeSystemDateNoPlaceholderLintItem` + +#### Questionnaire Resources + +##### Metadata Validation + +- **Meta Profile**: + - Must have meta profile + - Error: `FhirQuestionnaireMissingMetaProfileLintItem` + - Meta profile must be valid + - Error: `FhirQuestionnaireInvalidMetaProfileLintItem` + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirQuestionnaireMissingReadAccessTagLintItem` + +##### Status Validation + +- **Status**: + - Status must be valid + - Error: `FhirQuestionnaireInvalidStatusLintItem` + +##### Item Validation + +- **Items**: + - Must have at least one item + - Error: `FhirQuestionnaireMissingItemLintItem` + - Items must have linkId + - Error: `FhirQuestionnaireItemMissingAttributesLinkIdLintItem` + - Items must have text + - Error: `FhirQuestionnaireItemMissingAttributesTextLintItem` + - Items must have type + - Error: `FhirQuestionnaireItemMissingAttributesTypeLintItem` + - Link IDs must be unique + - Error: `FhirQuestionnaireDuplicateLinkIdLintItem` + - Unusual link IDs detected + - Error: `FhirQuestionnaireUnusualLinkIdLintItem` + +##### Mandatory Item Validation + +- **Required Items**: + - Mandatory items must be required + - Error: `FhirQuestionnaireMandatoryItemNotRequiredLintItem` + - Mandatory items must have valid type + - Error: `FhirQuestionnaireMandatoryItemInvalidTypeLintItem` + +##### Definition Validation + +- **Definition**: + - Definition must be valid + - Error: `FhirQuestionnaireDefinitionLintItem` + +##### Placeholder Validation + +- **Version Placeholder**: + - Version must be `#{version}` + - Error: `FhirQuestionnaireVersionNoPlaceholderLintItem` + +- **Date Placeholder**: + - Date must be `#{date}` + - Error: `FhirQuestionnaireDateNoPlaceholderLintItem` + +#### Common FHIR Validations + +##### Access Tag Validation + +- **Read Access Tag**: + - Must have read access tag + - Error: `FhirMissingFhirAccessTagLintItem` + - Access tag must be valid + - Error: `FhirInvalidFhirAccessTagLintItem` + +##### Kind Validation + +- **Kind**: + - Kind must be present + - Error: `FhirKindIsMissingOrEmptyLintItem` + - Kind must be "Task" for Task resources + - Error: `FhirKindNotSetAsTaskLintItem` + +##### Status Validation + +- **Status**: + - Status must be "unknown" (DSF convention) + - Error: `FhirStatusIsNotSetAsUnknownLintItem` + +##### Extension Validation + +- **Process Authorization Extension**: + - Must have process authorization extension + - Error: `FhirNoExtensionProcessAuthorizationFoundLintItem` + +### Plugin Configuration Validation + +#### ServiceLoader Registration + +- **Registration File**: + - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) + - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` + - Plugin class must be loadable + - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` + +#### Resource References + +- **BPMN File References**: + - BPMN files referenced in plugin must exist + - Error: `PluginDefinitionBpmnFileReferencedButNotFoundLintItem` + - BPMN files must be in expected root + - Error: `PluginDefinitionBpmnFileReferencedFoundOutsideExpectedRootLintItem` + - BPMN files must be parsable + - Error: `PluginDefinitionUnparsableBpmnResourceLintItem` + +- **FHIR File References**: + - FHIR resources referenced in BPMN must exist + - Error: `PluginDefinitionFhirFileReferencedButNotFoundLintItem` + - FHIR resources must be in expected root + - Error: `PluginDefinitionFhirFileReferencedFoundOutsideExpectedRootLintItem` + - FHIR resources must be parsable + - Error: `PluginDefinitionUnparsableFhirResourceLintItem` + +#### Resource Presence + +- **BPMN Processes**: + - At least one BPMN process must be defined + - Error: `PluginDefinitionNoProcessModelDefinedLintItem` + +- **FHIR Resources**: + - At least one FHIR resource must be defined + - Error: `PluginDefinitionNoFhirResourcesDefinedLintItem` + +#### Leftover Resource Detection + +The linter performs project-level analysis to identify unreferenced resources: + +- **Unreferenced BPMN Files**: + - BPMN files that are not referenced by any plugin + - Reported as warnings + +- **Unreferenced FHIR Resources**: + - FHIR resources that are not referenced by any BPMN process + - Reported as warnings + +This analysis works uniformly for single-plugin and multi-plugin projects. diff --git a/docs/src/process-development/api-v2/tooling/linter-tool.md b/docs/src/process-development/api-v2/tooling/linter-tool.md deleted file mode 100644 index b960c28a2..000000000 --- a/docs/src/process-development/api-v2/tooling/linter-tool.md +++ /dev/null @@ -1,1744 +0,0 @@ ---- -title: DSF Linter -icon: operate ---- -# DSF Linter - Complete Documentation - -A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. - -## Table of Contents - -1. [Overview](#overview) -2. [Quick Start](#quick-start) -3. [Installation](#installation) -4. [Usage](#usage) -5. [CLI Options](#cli-options) -6. [Validation Rules](#validation-rules) -7. [Report Generation](#report-generation) -8. [Architecture](#architecture) -9. [Development](#development) -10. [Troubleshooting](#troubleshooting) -11. [API Reference](#api-reference) - -## Overview - -The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: - -- **BPMN Process Definitions**: Validates Camunda BPMN 2.0 models, task implementations, event configurations, and FHIR resource references -- **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources -- **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure - -### Key Features - -- ✅ Validates BPMN processes against DSF conventions -- ✅ Validates FHIR resources against DSF profiles and HL7 specifications -- ✅ Detects unreferenced (leftover) resources -- ✅ Generates detailed HTML and JSON reports -- ✅ Supports local and remote JAR file input -- ✅ Multi-plugin project support -- ✅ CI/CD integration ready -- ✅ Comprehensive error reporting with severity levels -- ✅ Extensible architecture for custom validation rules - -### What is DSF? - -The Data Sharing Framework (DSF) is a framework for implementing interoperable healthcare data sharing processes. DSF process plugins contain: - -- **BPMN Processes**: Business process definitions using Camunda BPMN 2.0 -- **FHIR Resources**: Healthcare data resources conforming to HL7 FHIR specifications -- **Plugin Classes**: Java classes implementing the DSF ProcessPlugin interface - -## Quick Start - -### Build the Project - -```bash -# Full build with tests -mvn clean package - -# Skip tests for faster build -mvn clean package -DskipTests - -# Verbose output -mvn clean package -X -``` - -### Basic Usage - -```bash -# Lint a local JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path your-plugin.jar --html - -# Lint a remote JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html - -# View report at: /tmp/dsf-linter-report-/dsf-linter-report/index.html -``` - -## Installation - -### Requirements - -- **Java**: 17 or higher -- **Maven**: 3.6 or higher -- **Operating System**: Windows, Linux, or macOS - -### Building from Source - -```bash -# Clone the repository -git clone -cd dsf-linter - -# Build the project -mvn clean package - -# The executable JAR will be at: -# linter-cli/target/linter-cli-1.0-SNAPSHOT.jar -``` - -### Distribution - -The linter is distributed as a single executable JAR file that includes all dependencies. After building, the JAR can be used standalone: - -```bash -# Copy to a convenient location -cp linter-cli/target/linter-cli-1.0-SNAPSHOT.jar ~/bin/dsf-linter.jar - -# Use from anywhere -java -jar ~/bin/dsf-linter.jar --path plugin.jar --html -``` - -## Usage - -### Input Types - -The linter accepts only **JAR files** as input: - -| Input Type | Example | Description | -|------------|---------|-------------| -| Local JAR | `--path C:\path\to\plugin.jar` | JAR file in local filesystem | -| Remote JAR | `--path https://example.com/plugin.jar` | JAR file via HTTP/HTTPS URL | - -**Important:** Maven projects must first be built with `mvn clean package` before the resulting JAR file can be linted. - -### Expected JAR Structure - -The linter expects the following structure in the JAR file: - -``` -plugin.jar -├── META-INF/ -│ └── services/ -│ ├── dev.dsf.bpe.process.ProcessPlugin (v1) -│ └── dev.dsf.bpe.process.v2.ProcessPlugin (v2) -├── bpe/ -│ └── *.bpmn (BPMN process definitions) -└── fhir/ - ├── ActivityDefinition/ - │ └── *.xml or *.json - ├── Task/ - │ └── *.xml or *.json - ├── StructureDefinition/ - │ └── *.xml or *.json - ├── ValueSet/ - │ └── *.xml or *.json - ├── CodeSystem/ - │ └── *.xml or *.json - └── Questionnaire/ - └── *.xml or *.json -``` - -### Usage Examples - -#### Basic Linting - -```bash -# Local JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path C:\path\to\plugin.jar --html - -# Remote JAR file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path https://github.com/datasharingframework/dsf-process-ping-pong/releases/download/v2.0.0.1/dsf-process-ping-pong-2.0.0.1.jar --html -``` - -#### Advanced Configuration - -```bash -# Multiple report formats with custom path -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --json --report-path ./reports - -# Verbose output with colored console -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose --color - -# Lint Maven project (two-step process) -# Step 1: Build the project -cd /path/to/project && mvn clean package - -# Step 2: Lint the resulting JAR -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project/target/my-plugin-1.0.0.jar --html -``` - -#### CI/CD Integration - -```bash -# GitHub Actions / GitLab CI -FORCE_COLOR=1 java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --json --verbose - -# Jenkins (fail on errors) -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html -# Exit code: 0 = success, 1 = errors - -# Don't fail build (gradual adoption) -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --no-fail -``` - -## CLI Options - -| Option | Short | Description | Required | -|--------|-------|-------------|----------| -| `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | -| `--html` | | Generate HTML report | No | -| `--json` | | Generate JSON report | No | -| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | -| `--verbose` | `-v` | Enable verbose logging output | No | -| `--color` | | Enable colored console output | No | -| `--no-fail` | | Exit with code 0 even if linter errors are found | No | -| `--help` | `-h` | Display help message | No | -| `--version` | | Display version information | No | - -### Environment Variables - -| Variable | Effect | -|----------|--------| -| `NO_COLOR` | Disables colored output | -| `FORCE_COLOR` | Forces colored output (useful in CI) | -| `TERM=dumb` | Disables colored output | -| `WT_SESSION`, `ANSICON` | Windows color detection | - -### Exit Codes - -| Code | Meaning | -|------|---------| -| 0 | Success (no errors, or `--no-fail` was used) | -| 1 | Failure (errors found, or fatal error occurred) | - -## Validation Rules - -The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. - -### BPMN Validation - -The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. - -#### Task Validation - -##### Service Tasks - -- **Name Validation**: - - Task must have a non-empty name - - Error: `BpmnServiceTaskNameEmptyLintItem` - -- **Implementation Class Validation**: - - `camunda:class` or `camunda:delegateExpression` must be specified - - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` - - Implementation class must exist in the classpath - - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` - - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` - - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` - - Class must implement DSF-specific task interface (if applicable) - - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` - -##### User Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Form Key Validation**: - - `camunda:formKey` must be present and valid - - Must reference a valid Questionnaire resource - -- **Listener Validation**: - - Listener classes must exist - - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` - - Listener must have class attribute - - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` - - Listener must extend/implement required class - - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` - -##### Send Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Implementation Class Validation**: - - Implementation class must exist - - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` - - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` - - Class must implement required interface - - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` - -- **Field Injection Validation**: - - Message-related field injections must be valid - - FHIR resource references must be correct - -##### Receive Tasks - -- **Name Validation**: - - Task must have a non-empty name - -- **Message Definition Validation**: - - Message definition must be valid - - FHIR message name cross-checks - -#### Event Validation - -##### Message Events (Start/Intermediate/End) - -- **Event Name Validation**: - - Event must have a non-empty name - - Error: `BpmnEventNameEmptyLintItem` - - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` - - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` - - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` - -- **Implementation Class Validation**: - - For send events, implementation class must exist - - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` - - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` - - Class must implement JavaDelegate - - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` - - Intermediate throw events should not have message definitions - - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` - - Throw events must implement required interface - - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` - -- **Field Injection Validation**: - - `profile` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionProfileEmptyLintItem` - - Must contain version placeholder `#{version}` - - Error: `BpmnFieldInjectionProfileNoVersionPlaceholderLintItem` - - Must reference existing StructureDefinition - - Error: `BpmnNoStructureDefinitionFoundForMessageLintItem` - - - `messageName` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionMessageValueEmptyLintItem` - - Must be a string literal - - Error: `BpmnFieldInjectionNotStringLiteralLintItem` - - - `instantiatesCanonical` field injection: - - Must be non-empty - - Error: `BpmnFieldInjectionInstantiatesCanonicalEmptyLintItem` - - Must end with version placeholder `|#{version}` - - Error: `BpmnFieldInjectionInstantiatesCanonicalNoVersionPlaceholderLintItem` - - Must reference existing ActivityDefinition - - Error: `BpmnNoActivityDefinitionFoundForMessageLintItem` - -##### Timer Events - -- **Time Expression Validation**: - - Time cycle/date/duration expressions must be valid - - Placeholder usage validation - -##### Error Boundary Events - -- **Error Configuration Validation**: - - Error reference must be present - - Error code must not be empty - - Error: `BpmnErrorBoundaryEventErrorCodeEmptyLintItem` - - Error name must not be empty (warning) - - Error: `BpmnErrorBoundaryEventErrorNameEmptyLintItem` - - Error: `BpmnErrorBoundaryEventNameEmptyLintItem` - - Error code variable must not be empty - - Error: `BpmnErrorBoundaryEventErrorCodeVariableEmptyLintItem` - -##### Signal Events - -- **Signal Definition Validation**: - - Signal definitions must be valid - - Signal references must be correct - -##### Conditional Events - -- **Condition Expression Validation**: - - Condition expressions must be valid - -#### Gateway and Flow Validation - -##### Exclusive Gateways - -- **Sequence Flow Validation**: - - Outgoing sequence flows must have appropriate names - - Conditional expressions required when multiple paths exist - - Default flow validation - -##### Inclusive Gateways - -- **Sequence Flow Validation**: - - Similar requirements as exclusive gateways - - Multiple path handling - -##### Event-Based Gateways - -- **Configuration Validation**: - - Proper configuration required - - Outgoing flow setup validation - -##### Sequence Flows - -- **Naming and Conditions**: - - Naming conventions - - Conditional expressions for non-default flows from splitting gateways - - Error: `BpmnFlowElementLintItem` - -#### SubProcess Validation - -##### Multi-Instance SubProcesses - -- **Asynchronous Execution**: - - `asyncBefore` must be set to `true` for proper asynchronous execution - - Required for multi-instance subprocesses - -##### Start/End Events in SubProcesses - -- **Structural Validation**: - - Start events must be part of subprocess - - Error: `BpmnStartEventNotPartOfSubProcessLintItem` - - End events must be part of subprocess - - Error: `BpmnEndEventNotPartOfSubProcessLintItem` - -#### Floating Elements - -- **Element Placement**: - - Elements must be properly connected - - Error: `BpmnFloatingElementLintItem` - -#### Unknown Field Injections - -- **Field Injection Validation**: - - Only known field injections are allowed - - Error: `BpmnUnknownFieldInjectionLintItem` - -### FHIR Resource Validation - -The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. - -#### Task Resources - -Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). - -##### Metadata and Profile Validation - -- **Profile Validation**: - - `meta.profile` must be present and point to a DSF Task profile - - Error: `FhirTaskMissingProfileLintItem` - - Profile must be loadable - - Error: `FhirTaskCouldNotLoadProfileLintItem` - -- **InstantiatesCanonical Validation**: - - `instantiatesCanonical` must be present - - Error: `FhirTaskMissingInstantiatesCanonicalLintItem` - - Must end with version placeholder `|#{version}` - - Error: `FhirTaskInstantiatesCanonicalPlaceholderLintItem` - - Must reference existing ActivityDefinition - - Error: `FhirTaskUnknownInstantiatesCanonicalLintItem` - -##### Fixed Elements - -- **Status Validation**: - - `status` must be present - - Error: `FhirTaskMissingStatusLintItem` - - Must be `"draft"` for template Task instances - - Error: `FhirTaskStatusNotDraftLintItem` - - Must be a valid TaskStatus value - - Error: `FhirTaskUnknownStatusLintItem` - -- **Intent Validation**: - - `intent` must be `"order"` - - Error: `FhirTaskValueIsNotSetAsOrderLintItem` - -- **Requester Validation**: - - Requester must be present - - Error: `FhirTaskMissingRequesterLintItem` - - `requester.identifier.system` must be `http://dsf.dev/sid/organization-identifier` - - Error: `FhirTaskInvalidRequesterLintItem` - - `requester.identifier.value` must be `#{organization}` (development) - - Error: `FhirTaskRequesterOrganizationNoPlaceholderLintItem` - - Error: `FhirTaskRequesterIdNoPlaceholderLintItem` - - Error: `FhirTaskRequesterIdNotExistLintItem` - -- **Recipient Validation**: - - Recipient must be present - - Error: `FhirTaskMissingRecipientLintItem` - - `restriction.recipient.identifier.system` must be `http://dsf.dev/sid/organization-identifier` - - Error: `FhirTaskInvalidRecipientLintItem` - - `restriction.recipient.identifier.value` must be `#{organization}` (development) - - Error: `FhirTaskRecipientOrganizationNoPlaceholderLintItem` - - Error: `FhirTaskRecipientIdNoPlaceholderLintItem` - - Error: `FhirTaskRecipientIdNotExistLintItem` - -##### Development Placeholders - -- **Date Placeholder**: - - `authoredOn` must contain `#{date}` - - Error: `FhirTaskDateNoPlaceholderLintItem` - -##### Task.input Validation - -- **Input Presence**: - - `Task.input` must not be empty - - Error: `FhirTaskMissingInputLintItem` - -- **Structural Validation**: - - Each input must have `type.coding.system` and `type.coding.code` - - Error: `FhirTaskInputRequiredCodingSystemAndCodingCodeLintItem` - - Each input must have a `value[x]` element - - Error: `FhirTaskInputMissingValueLintItem` - -- **Duplicate Detection**: - - No two inputs may share the same `system#code` combination - - Error: `FhirTaskInputDuplicateSliceLintItem` - -- **BPMN Slice Validation**: - - `message-name` slice: Required (min=1, max=1) - - Error: `FhirTaskRequiredInputWithCodeMessageNameLintItem` - - `business-key` slice: - - Required when status is "in-progress", "completed", or "failed" - - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` - - Must be absent when status is "draft" - - Error: `FhirTaskBusinessKeyExistsLintItem` - - `correlation-key` slice: - - Validated against StructureDefinition cardinality - - Error: `FhirTaskCorrelationExistsLintItem` - - Error: `FhirTaskCorrelationMissingButRequiredLintItem` - -- **Cardinality Validation**: - - Total input count validated against base cardinality - - Error: `FhirTaskInputInstanceCountBelowMinLintItem` - - Error: `FhirTaskInputInstanceCountExceedsMaxLintItem` - - Slice occurrence counts validated against slice-specific cardinality - - Error: `FhirTaskInputSliceCountBelowSliceMinLintItem` - - Error: `FhirTaskInputSliceCountExceedsSliceMaxLintItem` - -- **Terminology Validation**: - - Code/system combinations validated against DSF CodeSystems - - Error: `FhirTaskUnknownCodeLintItem` - -#### StructureDefinition Resources - -StructureDefinition resources are validated against DSF-specific constraints. - -##### Metadata Validation - -- **Read Access Tag**: - - Must contain valid read-access tag - - Error: `FhirStructureDefinitionMissingReadAccessTagLintItem` - -- **URL Validation**: - - `url` must be present and non-empty - - Error: `FhirStructureDefinitionMissingUrlLintItem` - -- **Status Validation**: - - `status` must be `"unknown"` (DSF convention) - - Error: `FhirStructureDefinitionInvalidStatusLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - `version` must contain exactly `#{version}` - - Error: `FhirStructureDefinitionVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - `date` must contain exactly `#{date}` - - Error: `FhirStructureDefinitionDateNoPlaceholderLintItem` - -##### Structure Validation - -- **Differential**: - - `differential` element must exist - - Error: `FhirStructureDefinitionMissingDifferentialLintItem` - -- **Snapshot**: - - `snapshot` element should not be present (warning) - - Error: `FhirStructureDefinitionSnapshotPresentLintItem` - -- **Element IDs**: - - Every `element` must have an `@id` attribute - - Error: `FhirStructureDefinitionElementWithoutIdLintItem` - - Element IDs must be unique - - Error: `FhirStructureDefinitionDuplicateElementIdLintItem` - -##### Slice Cardinality Validation - -According to FHIR profiling specification §5.1.0.14: - -- **SHOULD Rule**: - - Sum of all slice minimum cardinalities should be ≤ base element's minimum - - Error: `FhirStructureDefinitionSliceMinSumAboveBaseMinLintItem` - -- **MUST Rule (Min Sum)**: - - Sum of all slice minimum cardinalities must not exceed base element's maximum - - Error: `FhirStructureDefinitionSliceMinSumExceedsMaxLintItem` - -- **MUST Rule (Slice Max)**: - - No individual slice's maximum cardinality may exceed base element's maximum - - Error: `FhirStructureDefinitionSliceMaxExceedsBaseMaxLintItem` - -#### ValueSet Resources - -ValueSet resources are validated against the DSF ValueSet base profile. - -##### Metadata Validation - -- **Read Access Tags**: - - Must contain at least one read-access tag (ALL or LOCAL) - - Error: `FhirValueSetMissingReadAccessTagAllOrLocalLintItem` - - Organization role codes must be valid - - Error: `FhirValueSetOrganizationRoleMissingValidCodeValueLintItem` - -- **Required Elements**: - - `url` must be present - - Error: `FhirValueSetMissingUrlLintItem` - - `name` must be present - - Error: `FhirValueSetMissingNameLintItem` - - `title` must be present - - Error: `FhirValueSetMissingTitleLintItem` - - `publisher` must be present - - Error: `FhirValueSetMissingPublisherLintItem` - - `description` must be present - - Error: `FhirValueSetMissingDescriptionLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - `version` must be `#{version}` - - Error: `FhirValueSetVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - `date` must be `#{date}` - - Error: `FhirValueSetDateNoPlaceholderLintItem` - -- **Include Version Placeholder**: - - `compose.include.version` must be `#{version}` - - Error: `FhirValueSetIncludeVersionPlaceholderLintItem` - -##### Compose Structure Validation - -- **Include Elements**: - - At least one `compose.include` required - - Error: `FhirValueSetMissingComposeIncludeLintItem` - - Each include must have a `system` attribute - - Error: `FhirValueSetIncludeMissingSystemLintItem` - -- **Concept Validation**: - - Concept codes must be non-blank - - Error: `FhirValueSetConceptMissingCodeLintItem` - - Duplicate codes detected - - Error: `FhirValueSetDuplicateConceptCodeLintItem` - -##### Terminology Compliance - -- **CodeSystem Validation**: - - CodeSystem URLs validated against DSF terminology cache - - Error: `FhirValueSetUnknownCodeLintItem` - - Code exists but in different CodeSystem - - Error: `FhirValueSetFalseUrlReferencedLintItem` - -#### ActivityDefinition Resources - -##### Profile Validation - -- **Profile**: - - Must have valid profile - - Error: `FhirActivityDefinitionMissingProfileLintItem` - - Profile must not have version number - - Error: `FhirActivityDefinitionProfileHasVersionNumberLintItem` - -##### URL Validation - -- **URL Format**: - - URL must be valid - - Error: `FhirActivityDefinitionInvalidFhirUrlLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirActivityDefinitionInvalidFhirStatusLintItem` - -##### Authorization Validation - -- **Requester**: - - Requester entry must be present - - Error: `FhirActivityDefinitionEntryMissingRequesterLintItem` - - Requester entry must be valid - - Error: `FhirActivityDefinitionEntryInvalidRequesterLintItem` - -- **Recipient**: - - Recipient entry must be present - - Error: `FhirActivityDefinitionEntryMissingRecipientLintItem` - - Recipient entry must be valid - - Error: `FhirActivityDefinitionEntryInvalidRecipientLintItem` - -#### CodeSystem Resources - -##### Metadata Validation - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirCodeSystemMissingReadAccessTagLintItem` - -- **Required Elements**: - - Required elements must be present - - Error: `FhirCodeSystemMissingElementLintItem` - -##### URL Validation - -- **URL Format**: - - URL must be valid - - Error: `FhirCodeSystemInvalidUrlLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirCodeSystemInvalidStatusLintItem` - -##### Concept Validation - -- **Concepts**: - - Must have at least one concept - - Error: `FhirCodeSystemMissingConceptLintItem` - - Concepts must have code - - Error: `FhirCodeSystemConceptMissingCodeLintItem` - - Concepts must have display - - Error: `FhirCodeSystemConceptMissingDisplayLintItem` - - Duplicate codes detected - - Error: `FhirCodeSystemDuplicateCodeLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - Version must be `#{version}` - - Error: `FhirCodeSystemVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - Date must be `#{date}` - - Error: `FhirCodeSystemDateNoPlaceholderLintItem` - -#### Questionnaire Resources - -##### Metadata Validation - -- **Meta Profile**: - - Must have meta profile - - Error: `FhirQuestionnaireMissingMetaProfileLintItem` - - Meta profile must be valid - - Error: `FhirQuestionnaireInvalidMetaProfileLintItem` - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirQuestionnaireMissingReadAccessTagLintItem` - -##### Status Validation - -- **Status**: - - Status must be valid - - Error: `FhirQuestionnaireInvalidStatusLintItem` - -##### Item Validation - -- **Items**: - - Must have at least one item - - Error: `FhirQuestionnaireMissingItemLintItem` - - Items must have linkId - - Error: `FhirQuestionnaireItemMissingAttributesLinkIdLintItem` - - Items must have text - - Error: `FhirQuestionnaireItemMissingAttributesTextLintItem` - - Items must have type - - Error: `FhirQuestionnaireItemMissingAttributesTypeLintItem` - - Link IDs must be unique - - Error: `FhirQuestionnaireDuplicateLinkIdLintItem` - - Unusual link IDs detected - - Error: `FhirQuestionnaireUnusualLinkIdLintItem` - -##### Mandatory Item Validation - -- **Required Items**: - - Mandatory items must be required - - Error: `FhirQuestionnaireMandatoryItemNotRequiredLintItem` - - Mandatory items must have valid type - - Error: `FhirQuestionnaireMandatoryItemInvalidTypeLintItem` - -##### Definition Validation - -- **Definition**: - - Definition must be valid - - Error: `FhirQuestionnaireDefinitionLintItem` - -##### Placeholder Validation - -- **Version Placeholder**: - - Version must be `#{version}` - - Error: `FhirQuestionnaireVersionNoPlaceholderLintItem` - -- **Date Placeholder**: - - Date must be `#{date}` - - Error: `FhirQuestionnaireDateNoPlaceholderLintItem` - -#### Common FHIR Validations - -##### Access Tag Validation - -- **Read Access Tag**: - - Must have read access tag - - Error: `FhirMissingFhirAccessTagLintItem` - - Access tag must be valid - - Error: `FhirInvalidFhirAccessTagLintItem` - -##### Kind Validation - -- **Kind**: - - Kind must be present - - Error: `FhirKindIsMissingOrEmptyLintItem` - - Kind must be "Task" for Task resources - - Error: `FhirKindNotSetAsTaskLintItem` - -##### Status Validation - -- **Status**: - - Status must be "unknown" (DSF convention) - - Error: `FhirStatusIsNotSetAsUnknownLintItem` - -##### Extension Validation - -- **Process Authorization Extension**: - - Must have process authorization extension - - Error: `FhirNoExtensionProcessAuthorizationFoundLintItem` - -### Plugin Configuration Validation - -#### ServiceLoader Registration - -- **Registration File**: - - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) - - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` - - Plugin class must be loadable - - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` - -#### Resource References - -- **BPMN File References**: - - BPMN files referenced in plugin must exist - - Error: `PluginDefinitionBpmnFileReferencedButNotFoundLintItem` - - BPMN files must be in expected root - - Error: `PluginDefinitionBpmnFileReferencedFoundOutsideExpectedRootLintItem` - - BPMN files must be parsable - - Error: `PluginDefinitionUnparsableBpmnResourceLintItem` - -- **FHIR File References**: - - FHIR resources referenced in BPMN must exist - - Error: `PluginDefinitionFhirFileReferencedButNotFoundLintItem` - - FHIR resources must be in expected root - - Error: `PluginDefinitionFhirFileReferencedFoundOutsideExpectedRootLintItem` - - FHIR resources must be parsable - - Error: `PluginDefinitionUnparsableFhirResourceLintItem` - -#### Resource Presence - -- **BPMN Processes**: - - At least one BPMN process must be defined - - Error: `PluginDefinitionNoProcessModelDefinedLintItem` - -- **FHIR Resources**: - - At least one FHIR resource must be defined - - Error: `PluginDefinitionNoFhirResourcesDefinedLintItem` - -#### Leftover Resource Detection - -The linter performs project-level analysis to identify unreferenced resources: - -- **Unreferenced BPMN Files**: - - BPMN files that are not referenced by any plugin - - Reported as warnings - -- **Unreferenced FHIR Resources**: - - FHIR resources that are not referenced by any BPMN process - - Reported as warnings - -This analysis works uniformly for single-plugin and multi-plugin projects. - -## Report Generation - -### Report Structure - -Reports are generated in the following structure: - -``` -/ -├── index.html # Summary report (all plugins) -├── plugin-name.html # Detailed report for each plugin -└── plugin-name.json # JSON report (if --json specified) -``` - -### HTML Report - -The HTML report provides a comprehensive, human-readable view of all linting results. - -#### Summary Page (`index.html`) - -The summary page includes: - -- **Header**: - - DSF Linter version - - Execution timestamp - - Project path - -- **Overall Statistics**: - - Total number of plugins - - Total errors - - Total warnings - - Execution time - -- **Plugin Summary Table**: - - Plugin name - - API version - - Error count - - Warning count - - Link to detailed report - -- **Leftover Resource Summary**: - - Unreferenced BPMN files - - Unreferenced FHIR resources - -#### Plugin Report (`plugin-name.html`) - -Each plugin has a detailed report page containing: - -- **Plugin Metadata**: - - Plugin name - - Plugin class name - - API version (v1 or v2) - -- **BPMN Validation Results**: - - List of all BPMN files - - Errors and warnings per file - - Detailed error messages with file and line references - -- **FHIR Validation Results**: - - List of all FHIR resources by type - - Errors and warnings per resource - - Detailed error messages with element paths - -- **Plugin Configuration Results**: - - ServiceLoader registration status - - Resource reference validation results - -- **Leftover Resource Analysis**: - - Unreferenced BPMN files - - Unreferenced FHIR resources - -- **Severity Indicators**: - - Color-coded severity levels (ERROR, WARNING, INFO, SUCCESS) - - Expandable/collapsible sections - -### JSON Report - -The JSON report provides machine-readable output for CI/CD integration and automated processing. - -#### Structure - -```json -{ - "version": "1.0.0", - "timestamp": "2024-01-15T10:30:00Z", - "projectPath": "/path/to/plugin.jar", - "executionTimeMs": 2300, - "success": true, - "summary": { - "totalPlugins": 1, - "totalErrors": 0, - "totalWarnings": 1, - "totalLeftoverBpmn": 0, - "totalLeftoverFhir": 0 - }, - "plugins": { - "plugin-name": { - "name": "plugin-name", - "class": "dev.dsf.bpe.plugin.ExamplePlugin", - "apiVersion": "V1", - "errors": 0, - "warnings": 1, - "bpmnFiles": [ - { - "path": "bpe/process.bpmn", - "errors": 0, - "warnings": 1, - "items": [...] - } - ], - "fhirResources": { - "ActivityDefinition": [...], - "Task": [...], - "StructureDefinition": [...] - }, - "pluginConfig": { - "serviceLoaderRegistered": true, - "items": [...] - } - } - }, - "leftoverAnalysis": { - "unreferencedBpmn": [], - "unreferencedFhir": [] - } -} -``` - -#### Lint Item Structure - -Each lint item in the JSON report has the following structure: - -```json -{ - "severity": "ERROR", - "type": "BpmnServiceTaskNameEmptyLintItem", - "message": "Service task must have a non-empty name", - "file": "bpe/process.bpmn", - "element": "ServiceTask_1", - "line": 42, - "column": 10 -} -``` - -### Example Console Output - -``` -DSF Linter v1.0.0 -================================================================= -Project: /path/to/plugin.jar -Report: /tmp/dsf-linter-report-plugin/dsf-linter-report -================================================================= - -Phase 1: Project Setup -✓ JAR file validated -✓ Resources extracted - -Phase 2: Resource Discovery -✓ Found 1 plugin(s) -✓ Plugin: my-process-plugin - - BPMN: 2 files - - FHIR: 15 resources - -Phase 3: Linting -✓ BPMN validation: 0 errors, 1 warning -✓ FHIR validation: 0 errors, 0 warnings -✓ Plugin validation: 0 errors - -Phase 4: Report Generation -✓ HTML report generated - -Summary -================================================================= -✓ SUCCESS - No errors found - Plugins: 1 - Errors: 0 - Warnings: 1 - Execution time: 2.3s -================================================================= -``` - -## Architecture - -### Project Structure - -``` -dsf-linter/ -├── linter-core/ # Core linting logic -│ ├── src/main/java/dev/dsf/linter/ -│ │ ├── analysis/ # Resource analysis -│ │ │ └── LeftoverResourceDetector.java -│ │ ├── bpmn/ # BPMN parsing & validation -│ │ │ ├── BpmnLinter.java -│ │ │ ├── BpmnModelLinter.java -│ │ │ ├── BpmnTaskLinter.java -│ │ │ ├── BpmnEventLinter.java -│ │ │ ├── BpmnGatewayAndFlowLinter.java -│ │ │ └── BpmnSubProcessLinter.java -│ │ ├── fhir/ # FHIR parsing & validation -│ │ │ ├── FhirResourceLinter.java -│ │ │ ├── FhirTaskLinter.java -│ │ │ ├── FhirStructureDefinitionLinter.java -│ │ │ ├── FhirValueSetLinter.java -│ │ │ ├── FhirActivityDefinitionLinter.java -│ │ │ ├── FhirCodeSystemLinter.java -│ │ │ └── FhirQuestionnaireLinter.java -│ │ ├── service/ # Linting services -│ │ │ ├── BpmnLintingService.java -│ │ │ ├── FhirLintingService.java -│ │ │ ├── PluginLintingService.java -│ │ │ └── PluginLintingOrchestrator.java -│ │ ├── output/ # Lint item definitions -│ │ │ └── item/ # Specific lint items (200+ classes) -│ │ ├── report/ # Report generation -│ │ │ └── LintingReportGenerator.java -│ │ ├── input/ # Input handling & JAR processing -│ │ │ └── InputResolver.java -│ │ ├── setup/ # Project setup & building -│ │ │ └── ProjectSetupHandler.java -│ │ ├── plugin/ # Plugin definition discovery -│ │ │ └── PluginDefinitionDiscovery.java -│ │ ├── classloading/ # Dynamic class loading -│ │ │ ├── ProjectClassLoaderFactory.java -│ │ │ └── ClassInspector.java -│ │ ├── logger/ # Logging infrastructure -│ │ │ ├── Logger.java -│ │ │ ├── ConsoleLogger.java -│ │ │ └── Console.java -│ │ ├── constants/ # Constants & configuration -│ │ │ └── DsfApiConstants.java -│ │ ├── exception/ # Custom exceptions -│ │ │ ├── ResourceLinterException.java -│ │ │ └── MissingServiceRegistrationException.java -│ │ └── util/ # Utilities -│ │ ├── api/ # API version detection -│ │ ├── cache/ # Caching utilities -│ │ ├── converter/ # Format converters -│ │ ├── linting/ # Linting utilities -│ │ ├── loader/ # Class/service loading -│ │ ├── maven/ # Maven utilities -│ │ └── resource/ # Resource management -│ ├── src/main/resources/ -│ │ ├── logback.xml # Logging configuration -│ │ ├── logback-verbose.xml # Verbose logging configuration -│ │ └── templates/ # HTML report templates -│ │ ├── logo.svg -│ │ ├── single_plugin_report.html -│ │ └── summary_report.html -│ └── src/test/ # Unit tests -│ ├── java/ -│ └── resources/ # Test fixtures -└── linter-cli/ # CLI interface - └── src/main/java/dev/dsf/linter/ - ├── Main.java # CLI entry point - ├── LinterExecutor.java # Execution wrapper - └── ResultPrinter.java # Result formatting -``` - -### Key Components - -| Component | Purpose | -|-----------|---------| -| `DsfLinter` | Main orchestrator coordinating all linting phases | -| `ProjectSetupHandler` | Handles JAR extraction and classloader setup | -| `ResourceDiscoveryService` | Discovers plugins, BPMN files, and FHIR resources | -| `BpmnLintingService` | Orchestrates BPMN validation | -| `FhirLintingService` | Orchestrates FHIR resource validation | -| `PluginLintingService` | Validates plugin configuration and ServiceLoader registration | -| `PluginLintingOrchestrator` | Coordinates per-plugin linting workflow | -| `LeftoverResourceDetector` | Identifies unreferenced resources | -| `LintingReportGenerator` | Generates HTML and JSON reports | -| `InputResolver` | Resolves and downloads remote JAR files | -| `BpmnModelLinter` | Validates BPMN model structure and elements | -| `FhirResourceLinter` | Validates FHIR resources using pluggable linters | - -### Linting Phases - -The linter executes in five phases: - -#### Phase 1: Project Setup - -1. **Input Validation**: - - Validates that input is a JAR file - - Checks file existence or URL accessibility - -2. **JAR Extraction**: - - Downloads remote JAR files if needed - - Extracts JAR contents to temporary directory - - Preserves directory structure - -3. **Classloader Setup**: - - Creates project-specific classloader - - Loads plugin classes and dependencies - - Sets up context classloader for resource access - -#### Phase 2: Resource Discovery - -1. **Plugin Discovery**: - - Scans `META-INF/services/` for plugin registrations - - Loads plugin classes - - Detects API version (v1 or v2) - -2. **BPMN Discovery**: - - Scans `bpe/` directory for BPMN files - - Parses BPMN files to extract process definitions - - Maps BPMN files to plugins - -3. **FHIR Discovery**: - - Scans `fhir/` directory for FHIR resources - - Organizes resources by type - - Maps FHIR resources to plugins - -4. **Reference Mapping**: - - Extracts BPMN references to FHIR resources - - Maps FHIR resource references - - Identifies cross-references - -#### Phase 3: Linting - -1. **Per-Plugin Linting**: - - For each discovered plugin: - - Validates BPMN processes - - Validates FHIR resources - - Validates plugin configuration - - Collects lint items - -2. **Project-Level Analysis**: - - Performs leftover resource analysis - - Aggregates referenced resources across all plugins - - Identifies unreferenced resources - -3. **Result Aggregation**: - - Combines results from all plugins - - Calculates totals (errors, warnings) - - Determines overall success status - -#### Phase 4: Report Generation - -1. **HTML Report Generation**: - - Generates summary page - - Generates detailed plugin pages - - Applies templates and styling - -2. **JSON Report Generation** (if requested): - - Serializes all results to JSON - - Includes metadata and statistics - - Provides machine-readable format - -#### Phase 5: Summary - -1. **Console Output**: - - Displays execution summary - - Shows error and warning counts - - Reports execution time - -2. **Exit Code Determination**: - - Sets exit code based on results - - Respects `--no-fail` flag - - Returns appropriate status code - -### Design Patterns - -The linter uses several design patterns: - -- **Template Method Pattern**: Abstract base classes define linting algorithm structure -- **Strategy Pattern**: Pluggable linters for different resource types -- **Factory Pattern**: Classloader and service creation -- **Service Locator Pattern**: Plugin discovery via ServiceLoader -- **Builder Pattern**: Configuration and result objects - -### Thread Safety - -- Most components are stateless and thread-safe -- Classloader isolation ensures no cross-plugin interference -- Temporary context classloader used for resource access -- Result objects are immutable - -## Development - -### Requirements - -- **Java**: 17 or higher -- **Maven**: 3.6 or higher -- **IDE**: IntelliJ IDEA, Eclipse, or VS Code (optional) - -### IDE Setup - -1. **Import Project**: - - Import as Maven project - - Set JDK to 17 or higher - - Ensure Maven dependencies are resolved - -2. **Code Style** (optional): - - Configure code formatter - - Set up import organization - - Configure line endings - -3. **Run Configuration**: - - Create run configuration for `Main.java` - - Set program arguments: `--path --html --verbose` - - Configure working directory - -### Building - -```bash -# Full build with tests -mvn clean package - -# Skip tests for faster iteration -mvn clean package -DskipTests - -# Verbose Maven output -mvn clean package -X - -# Build only specific module -mvn clean package -pl linter-core - -# Install to local Maven repository -mvn clean install -``` - -### Testing - -```bash -# Run all tests -mvn test - -# Run specific test class -mvn test -Dtest=BpmnLoadingTest - -# Run specific test method -mvn test -Dtest=BpmnLoadingTest#testLoadBpmn - -# Run tests with verbose output -mvn test -X - -# Skip tests during build -mvn clean package -DskipTests - -# Run tests with coverage (if configured) -mvn test jacoco:report -``` - -### Development Workflow - -```bash -# 1. Make changes to source code -vim linter-core/src/main/java/dev/dsf/linter/service/BpmnLintingService.java - -# 2. Build the project -mvn clean package -DskipTests - -# 3. Test with a sample plugin -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path test-plugin.jar --html --verbose - -# 4. Check the generated report -open /tmp/dsf-linter-report-test-plugin/dsf-linter-report/index.html - -# 5. Run unit tests -mvn test - -# 6. Commit changes -git add . -git commit -m "Description of changes" -``` - -### Debugging - -#### Remote Debugging - -```bash -# Start the linter with debugger enabled -java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ - -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose - -# Attach debugger from IDE to localhost:5005 -``` - -#### Logging - -The linter uses Logback for logging. Configuration files: - -- `logback.xml`: Standard logging (INFO level) -- `logback-verbose.xml`: Verbose logging (DEBUG level, activated with `--verbose`) - -Log levels: -- **ERROR**: Fatal errors and exceptions -- **WARN**: Warnings and non-fatal issues -- **INFO**: General information and progress -- **DEBUG**: Detailed debugging information (verbose mode only) - -#### Common Debugging Scenarios - -1. **Plugin Not Found**: - - Enable verbose logging - - Check ServiceLoader registration - - Verify classpath - -2. **Resource Not Found**: - - Check JAR structure - - Verify resource paths - - Enable verbose logging - -3. **Class Loading Issues**: - - Check classloader setup - - Verify dependencies - - Check API version compatibility - -### Code Style Guidelines - -- Follow Java naming conventions -- Use meaningful variable and method names -- Add JavaDoc comments for public APIs -- Keep methods focused and small -- Use immutable objects where possible -- Handle exceptions appropriately -- Write unit tests for new features - -## Troubleshooting - -### "Input must be a JAR file" Error - -**Problem**: The linter only accepts JAR files as input. - -**Solution**: -```bash -# Wrong - Maven project directly -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project --html - -# Correct - Build first, then lint JAR -cd /path/to/project && mvn clean package -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /path/to/project/target/my-plugin-1.0.0.jar --html -``` - -### JAR File Not Found - -**Problem**: The specified JAR file path cannot be found. - -**Solution**: Verify the path and use absolute paths if needed: - -```bash -# Windows -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path "C:\Users\Username\project\target\plugin.jar" --html - -# Linux/Mac -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path /home/username/project/target/plugin.jar --html -``` - -### Missing Dependencies - -**Problem**: ClassNotFoundException or similar errors during linting. - -**Solution**: -```bash -# Check Maven settings -ls ~/.m2/settings.xml - -# Use verbose mode to see detailed error messages -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose - -# Check if dependencies are in the JAR -jar -tf plugin.jar | grep -i "class" -``` - -### Report Not Generated - -**Problem**: No report files are created. - -**Solution**: -```bash -# --html or --json flag must be set -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html # ← Required - -# Use absolute path for report directory -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --report-path $(pwd)/reports - -# Check write permissions -ls -ld /tmp/dsf-linter-report-* -``` - -### Remote JAR Download Error - -**Problem**: Cannot download JAR from remote URL. - -**Solution**: -```bash -# Test download separately -curl -L -o test.jar https://example.com/plugin.jar - -# Verify the download -ls -lh test.jar - -# Check network connectivity -ping example.com - -# Then use the local file -java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path test.jar --html -``` - -### Plugin Not Found - -**Problem**: "No plugins found" message. - -**Solution**: -- Verify ServiceLoader registration exists in `META-INF/services/` -- Check that plugin class is in the JAR file -- Ensure plugin class implements the correct interface -- Use `--verbose` to see detailed discovery logs -- Check API version compatibility - -### Out of Memory Errors - -**Problem**: `OutOfMemoryError` during linting. - -**Solution**: -```bash -# Increase heap size -java -Xmx2g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html - -# For very large projects -java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html -``` - -### Slow Performance - -**Problem**: Linting takes too long. - -**Solution**: -- Use `-DskipTests` during build -- Disable verbose logging in production -- Check network latency for remote JARs -- Consider increasing heap size -- Profile with JVM tools if needed - -### Class Loading Issues - -**Problem**: Classes cannot be loaded from plugin JAR. - -**Solution**: -- Verify JAR structure -- Check classpath configuration -- Ensure dependencies are included -- Use verbose mode to see classloader logs -- Check API version compatibility - -## API Reference - -### Core Classes - -#### `DsfLinter` - -Main orchestrator class for the linting process. - -**Constructor**: -```java -DsfLinter(Config config) -``` - -**Methods**: -```java -OverallLinterResult lint() throws IOException -``` - -**Usage**: -```java -DsfLinter.Config config = new DsfLinter.Config( - projectPath, - reportPath, - generateHtmlReport, - generateJsonReport, - failOnErrors, - logger -); - -DsfLinter linter = new DsfLinter(config); -DsfLinter.OverallLinterResult result = linter.lint(); -``` - -#### `DsfLinter.Config` - -Configuration record for the linter. - -**Fields**: -- `Path projectPath`: Path to the project root -- `Path reportPath`: Path for report generation -- `boolean generateHtmlReport`: Whether to generate HTML report -- `boolean generateJsonReport`: Whether to generate JSON report -- `boolean failOnErrors`: Whether to fail on errors -- `Logger logger`: Logger instance - -#### `DsfLinter.OverallLinterResult` - -Result record containing all linting results. - -**Fields**: -- `Map pluginLinter`: Results per plugin -- `LeftoverResourceDetector.AnalysisResult leftoverAnalysis`: Leftover resource analysis -- `Path masterReportPath`: Path to master report -- `long executionTimeMs`: Execution time in milliseconds -- `boolean success`: Whether linting succeeded - -**Methods**: -- `int getPluginErrors()`: Total error count from plugins -- `int getPluginWarnings()`: Total warning count from plugins -- `int getLeftoverCount()`: Count of leftover resources -- `int getTotalErrors()`: Total errors including leftovers - -#### `DsfLinter.PluginLinter` - -Linting result for a single plugin. - -**Fields**: -- `String pluginName`: Name of the plugin -- `String pluginClass`: Fully qualified class name -- `ApiVersion apiVersion`: DSF API version (V1 or V2) -- `LintingOutput output`: Detailed linting output -- `Path reportPath`: Path to generated report - -### Linting Services - -#### `BpmnLintingService` - -Service for linting BPMN files. - -**Constructor**: -```java -BpmnLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lint( - String pluginName, - List bpmnFiles, - List missingRefs, - Map outsideRoot, - Map fromDependencies, - File pluginResourceRoot -) -``` - -#### `FhirLintingService` - -Service for linting FHIR resources. - -**Constructor**: -```java -FhirLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lint( - String pluginName, - List fhirFiles, - List missingRefs, - Map outsideRoot, - Map fromDependencies, - File pluginResourceRoot -) -``` - -#### `PluginLintingService` - -Service for linting plugin configuration. - -**Constructor**: -```java -PluginLintingService(Logger logger) -``` - -**Methods**: -```java -LintingResult lintPlugin( - Path projectPath, - PluginAdapter pluginAdapter, - ApiVersion apiVersion, - List collectedPluginItems -) throws MissingServiceRegistrationException -``` - -### Lint Items - -All lint items extend `AbstractLintItem` and implement specific interfaces. - -#### Base Classes - -- `AbstractLintItem`: Base class for all lint items -- `BpmnElementLintItem`: Base class for BPMN-specific lint items -- `FhirElementLintItem`: Base class for FHIR-specific lint items -- `PluginLintItem`: Base class for plugin-specific lint items - -#### Severity Levels - -- `ERROR`: Critical issues that must be fixed -- `WARNING`: Issues that should be addressed -- `INFO`: Informational messages -- `SUCCESS`: Validation passed successfully - -#### Common Lint Item Methods - -```java -LinterSeverity getSeverity() -String getMessage() -File getFile() -String getElement() -``` - -### Utility Classes - -#### `Logger` - -Interface for logging functionality. - -**Methods**: -```java -void error(String message) -void error(String message, Throwable throwable) -void warn(String message) -void info(String message) -void debug(String message) -``` - -#### `InputResolver` - -Resolves and processes input JAR files. - -**Methods**: -```java -Optional resolve(String inputPath) -String extractInputName(String inputPath, InputType inputType) -void cleanup(ResolutionResult resolution) -``` - -#### `ResourceDiscoveryService` - -Discovers plugins and resources. - -**Methods**: -```java -DiscoveryResult discover(ProjectContext context) -``` - -## Changelog - -### Version 1.0.0 -- Initial release -- BPMN validation -- FHIR validation -- Plugin configuration validation -- HTML report generation - diff --git a/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md b/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md new file mode 100644 index 000000000..03f49fd2d --- /dev/null +++ b/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md @@ -0,0 +1,5 @@ +--- +title: Linter Tool +--- + + \ No newline at end of file From df2a2b38ab2261f3ebdff3a6cdc1448e65ba476a Mon Sep 17 00:00:00 2001 From: Serap Aydin Date: Fri, 12 Dec 2025 11:59:13 +0100 Subject: [PATCH 3/5] fix broken link --- docs/src/process-development/api-v2/tooling/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/process-development/api-v2/tooling/README.md b/docs/src/process-development/api-v2/tooling/README.md index e2a4de1c6..0e3bc5d79 100644 --- a/docs/src/process-development/api-v2/tooling/README.md +++ b/docs/src/process-development/api-v2/tooling/README.md @@ -4,4 +4,4 @@ icon: operate --- ## Process Plugin Dev Tools -- [ DSF Linter](linter-tool.md) \ No newline at end of file +- [ DSF Linter](/linter-tool/linter-tool) \ No newline at end of file From e4a241f7bd50af8ef9d6e1632527f00bc6b3f0f3 Mon Sep 17 00:00:00 2001 From: Serap Aydin Date: Fri, 12 Dec 2025 16:46:00 +0100 Subject: [PATCH 4/5] separated dsf linter from api 1&2 --- docs/src/.vuepress/theme.ts | 38 +++++++------------ .../api-v1/tooling/README.md | 1 - .../api-v2/tooling/README.md | 1 - .../api-v2/tooling/linter-tool/linter-tool.md | 5 --- .../tooling => }/linter-tool/development.md | 0 .../tooling => }/linter-tool/linter-tool.md | 0 .../tooling => }/linter-tool/phases.md | 0 .../linter-tool/troubleshooting.md | 0 .../tooling => }/linter-tool/validation.md | 0 9 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md rename docs/src/process-development/{api-v1/tooling => }/linter-tool/development.md (100%) rename docs/src/process-development/{api-v1/tooling => }/linter-tool/linter-tool.md (100%) rename docs/src/process-development/{api-v1/tooling => }/linter-tool/phases.md (100%) rename docs/src/process-development/{api-v1/tooling => }/linter-tool/troubleshooting.md (100%) rename docs/src/process-development/{api-v1/tooling => }/linter-tool/validation.md (100%) diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts index 81d4f5008..b22be78f3 100644 --- a/docs/src/.vuepress/theme.ts +++ b/docs/src/.vuepress/theme.ts @@ -154,7 +154,6 @@ export default hopeTheme({ children: ["get-started", { text: "Concepts", icon: "info", - link: "concept", collapsible: true, children: [ { @@ -223,18 +222,7 @@ export default hopeTheme({ ], }, ], - }, "create", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", { - text: "Process Plugin Dev Tools", - icon: "info", - children: [{ - text: "DSF Linter Tool", - icon: "operate", - prefix: "tooling/linter-tool", - collapsible: true, - children: [ - "linter-tool", "validation","phases", "development", "troubleshooting"], - },]} - ] + }, "create", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", ] }, { text: "API v2", @@ -244,7 +232,6 @@ export default hopeTheme({ children: ["get-started", { text: "Concepts", icon: "info", - link: "concept", collapsible: true, children: [ { @@ -313,19 +300,20 @@ export default hopeTheme({ ], }, ], - }, "implementation", "migration", "create", "best-practices", "testing", "publishing/publish-on-dsfhub", "tutorials/", "javadoc", { - text: "Process Plugin Dev Tools", - icon: "info", - children: [{ - text: "DSF Linter Tool", + }, "implementation", "migration", "create", "best-practices", "testing", "publishing/publish-on-dsfhub", "tutorials/", "javadoc",] + }, + { + text: "Process Plugin Dev Tools", + icon: "info", + children: [ + { + text:"DSF Linter Tool", icon: "operate", - prefix: "tooling/linter-tool", - collapsible: true, + prefix: "linter-tool/", children: [ - "linter-tool"], - }, - ] - },] + "linter-tool", "validation","phases", "development", "troubleshooting"], + } + ] }, ], "/dsf-development": [ diff --git a/docs/src/process-development/api-v1/tooling/README.md b/docs/src/process-development/api-v1/tooling/README.md index e2a4de1c6..5c765896b 100644 --- a/docs/src/process-development/api-v1/tooling/README.md +++ b/docs/src/process-development/api-v1/tooling/README.md @@ -4,4 +4,3 @@ icon: operate --- ## Process Plugin Dev Tools -- [ DSF Linter](linter-tool.md) \ No newline at end of file diff --git a/docs/src/process-development/api-v2/tooling/README.md b/docs/src/process-development/api-v2/tooling/README.md index 0e3bc5d79..5c765896b 100644 --- a/docs/src/process-development/api-v2/tooling/README.md +++ b/docs/src/process-development/api-v2/tooling/README.md @@ -4,4 +4,3 @@ icon: operate --- ## Process Plugin Dev Tools -- [ DSF Linter](/linter-tool/linter-tool) \ No newline at end of file diff --git a/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md b/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md deleted file mode 100644 index 03f49fd2d..000000000 --- a/docs/src/process-development/api-v2/tooling/linter-tool/linter-tool.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Linter Tool ---- - - \ No newline at end of file diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/development.md b/docs/src/process-development/linter-tool/development.md similarity index 100% rename from docs/src/process-development/api-v1/tooling/linter-tool/development.md rename to docs/src/process-development/linter-tool/development.md diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md b/docs/src/process-development/linter-tool/linter-tool.md similarity index 100% rename from docs/src/process-development/api-v1/tooling/linter-tool/linter-tool.md rename to docs/src/process-development/linter-tool/linter-tool.md diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/phases.md b/docs/src/process-development/linter-tool/phases.md similarity index 100% rename from docs/src/process-development/api-v1/tooling/linter-tool/phases.md rename to docs/src/process-development/linter-tool/phases.md diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md b/docs/src/process-development/linter-tool/troubleshooting.md similarity index 100% rename from docs/src/process-development/api-v1/tooling/linter-tool/troubleshooting.md rename to docs/src/process-development/linter-tool/troubleshooting.md diff --git a/docs/src/process-development/api-v1/tooling/linter-tool/validation.md b/docs/src/process-development/linter-tool/validation.md similarity index 100% rename from docs/src/process-development/api-v1/tooling/linter-tool/validation.md rename to docs/src/process-development/linter-tool/validation.md From 51f74221f78e5add9e6261faad8c595d344c42a6 Mon Sep 17 00:00:00 2001 From: Serap Aydin Date: Fri, 12 Dec 2025 17:41:24 +0100 Subject: [PATCH 5/5] latest Documentation update --- docs/src/.vuepress/theme.ts | 11 +- .../linter-tool/development.md | 14 +- .../linter-tool/linter-tool.md | 42 ++--- .../process-development/linter-tool/phases.md | 2 +- .../linter-tool/troubleshooting.md | 4 +- .../linter-tool/validation.md | 174 ++++++++++++++++-- 6 files changed, 198 insertions(+), 49 deletions(-) diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts index b22be78f3..d9e026d3a 100644 --- a/docs/src/.vuepress/theme.ts +++ b/docs/src/.vuepress/theme.ts @@ -305,16 +305,11 @@ export default hopeTheme({ { text: "Process Plugin Dev Tools", icon: "info", + prefix: "linter-tool/", children: [ - { - text:"DSF Linter Tool", - icon: "operate", - prefix: "linter-tool/", - children: [ - "linter-tool", "validation","phases", "development", "troubleshooting"], + "linter-tool", + "validation","phases", "development", "troubleshooting"], } - ] - }, ], "/dsf-development": [ { diff --git a/docs/src/process-development/linter-tool/development.md b/docs/src/process-development/linter-tool/development.md index b339ba566..8a383984b 100644 --- a/docs/src/process-development/linter-tool/development.md +++ b/docs/src/process-development/linter-tool/development.md @@ -1,6 +1,8 @@ --- title: Development +icon: code --- +## Development ### Requirements @@ -131,4 +133,14 @@ Log levels: 3. **Class Loading Issues**: - Check classloader setup - Verify dependencies - - Check API version compatibility \ No newline at end of file + - Check API version compatibility + +### Code Style Guidelines + +- Follow Java naming conventions +- Use meaningful variable and method names +- Add JavaDoc comments for public APIs +- Keep methods focused and small +- Use immutable objects where possible +- Handle exceptions appropriately +- Write unit tests for new features \ No newline at end of file diff --git a/docs/src/process-development/linter-tool/linter-tool.md b/docs/src/process-development/linter-tool/linter-tool.md index a29853f2c..3a0e6cbfc 100644 --- a/docs/src/process-development/linter-tool/linter-tool.md +++ b/docs/src/process-development/linter-tool/linter-tool.md @@ -1,6 +1,8 @@ --- -title: Linter Tool +title: DSF Linter Tool +icon: customize --- +# DSF Linter - Complete Documentation A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. Validates BPMN processes, FHIR resources, and plugin configurations from JAR files. @@ -11,15 +13,15 @@ A comprehensive linting tool for DSF (Data Sharing Framework) process plugins. V 3. [Installation](#installation) 4. [Usage](#usage) 5. [CLI Options](#cli-options) -7. [Report Generation](#report-generation) -8. [Architecture](#architecture) -11. [API Reference](#api-reference) +6. [Report Generation](#report-generation) +7. [Architecture](#architecture) +8. [API Reference](#api-reference) ## Overview The DSF Linter is a static analysis tool designed to validate DSF process plugins before deployment. It performs comprehensive checks on: -- **BPMN Process Definitions**: Validates Camunda/Operaton BPMN 2.0 models, task implementations, event configurations, and FHIR resource references +- **BPMN Process Definitions**: Validates Camunda BPMN 2.0 models, task implementations, event configurations, and FHIR resource references - **FHIR Resources**: Validates ActivityDefinition, Task, StructureDefinition, ValueSet, CodeSystem, and Questionnaire resources - **Plugin Configuration**: Verifies ServiceLoader registrations, resource references, and plugin structure @@ -35,6 +37,14 @@ The DSF Linter is a static analysis tool designed to validate DSF process plugin - ✅ Comprehensive error reporting with severity levels - ✅ Extensible architecture for custom validation rules +### What is DSF? + +The Data Sharing Framework (DSF) is a framework for implementing interoperable healthcare data sharing processes. DSF process plugins contain: + +- **BPMN Processes**: Business process definitions using Camunda BPMN 2.0 +- **FHIR Resources**: Healthcare data resources conforming to HL7 FHIR specifications +- **Plugin Classes**: Java classes implementing the DSF ProcessPlugin interface + ## Quick Start ### Build the Project @@ -159,9 +169,9 @@ java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ --path plugin.jar --html --json --report-path ./reports -# Verbose output with colored console +# Verbose output (colors enabled by default, use --no-color to disable) java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - --path plugin.jar --html --verbose --color + --path plugin.jar --html --verbose # Lint Maven project (two-step process) # Step 1: Build the project @@ -196,9 +206,9 @@ java -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ | `--path ` | `-p` | Path to JAR file (local or remote URL) | Yes | | `--html` | | Generate HTML report | No | | `--json` | | Generate JSON report | No | -| `--report-path ` | `-r` | Custom report directory (default: temp directory) | No | +| `--report-path ` | `-r` | Custom report directory (default: `/dsf-linter-report-/dsf-linter-report`) | No | | `--verbose` | `-v` | Enable verbose logging output | No | -| `--color` | | Enable colored console output | No | +| `--no-color` | | Disable colored console output (default: enabled) | No | | `--no-fail` | | Exit with code 0 even if linter errors are found | No | | `--help` | `-h` | Display help message | No | | `--version` | | Display version information | No | @@ -302,7 +312,7 @@ The JSON report provides machine-readable output for CI/CD integration and autom ```json { - "version": "1.0.0", + "version": "2.0.0", "timestamp": "2024-01-15T10:30:00Z", "projectPath": "/path/to/plugin.jar", "executionTimeMs": 2300, @@ -366,7 +376,7 @@ Each lint item in the JSON report has the following structure: ### Example Console Output ``` -DSF Linter v1.0.0 +DSF Linter v2.0.0 ================================================================= Project: /path/to/plugin.jar Report: /tmp/dsf-linter-report-plugin/dsf-linter-report @@ -691,13 +701,3 @@ Discovers plugins and resources. ```java DiscoveryResult discover(ProjectContext context) ``` - -## Changelog - -### Version 1.0.0 -- Initial release -- BPMN validation -- FHIR validation -- Plugin configuration validation -- HTML report generation - diff --git a/docs/src/process-development/linter-tool/phases.md b/docs/src/process-development/linter-tool/phases.md index 5111a1938..ea188f464 100644 --- a/docs/src/process-development/linter-tool/phases.md +++ b/docs/src/process-development/linter-tool/phases.md @@ -1,7 +1,7 @@ --- title: Linting Phases +icon: config --- - The linter executes in five phases: #### Phase 1: Project Setup diff --git a/docs/src/process-development/linter-tool/troubleshooting.md b/docs/src/process-development/linter-tool/troubleshooting.md index b5f42642d..505924539 100644 --- a/docs/src/process-development/linter-tool/troubleshooting.md +++ b/docs/src/process-development/linter-tool/troubleshooting.md @@ -1,7 +1,7 @@ --- title: Troubleshooting +icon: config --- - ### "Input must be a JAR file" Error **Problem**: The linter only accepts JAR files as input. @@ -135,4 +135,4 @@ java -Xmx4g -Xms1g -jar linter-cli/target/linter-cli-1.0-SNAPSHOT.jar \ - Check classpath configuration - Ensure dependencies are included - Use verbose mode to see classloader logs -- Check API version compatibility +- Check API version compatibility \ No newline at end of file diff --git a/docs/src/process-development/linter-tool/validation.md b/docs/src/process-development/linter-tool/validation.md index 7d691aac4..250ec6ade 100644 --- a/docs/src/process-development/linter-tool/validation.md +++ b/docs/src/process-development/linter-tool/validation.md @@ -1,6 +1,8 @@ --- title: Validation Rules +icon: note --- +## Validation Rules The linter performs comprehensive validation across multiple dimensions. This section details all validation rules organized by resource type. @@ -8,6 +10,12 @@ The linter performs comprehensive validation across multiple dimensions. This se The linter performs comprehensive validation on BPMN 2.0 process definitions using the Camunda BPMN model API. +**Important:** The linter automatically detects the DSF API version (V1 or V2) from the plugin configuration and applies version-specific validation rules. Many validation rules differ between V1 and V2 API, particularly for: +- Service Task and Send Task implementation classes +- Execution Listeners +- Task Listeners (User Tasks) +- Message Events (Intermediate Throw and End Events) + #### Task Validation ##### Service Tasks @@ -18,21 +26,34 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - **Implementation Class Validation**: - `camunda:class` or `camunda:delegateExpression` must be specified + - Error: `BpmnServiceTaskImplementationNotExistLintItem` - Error: `BpmnServiceTaskImplementationClassEmptyLintItem` - Implementation class must exist in the classpath - Error: `BpmnServiceTaskImplementationClassNotFoundLintItem` - - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` - - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` - - Class must implement DSF-specific task interface (if applicable) - - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` + +- **API Version-Specific Requirements**: + - **V1 API**: + - Both checks are performed separately: + - Class must extend `dev.dsf.bpe.v1.activity.AbstractServiceDelegate` + - Error: `BpmnServiceTaskNotExtendingAbstractServiceDelegateLintItem` (if not extending) + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnServiceTaskImplementationClassNotImplementingJavaDelegateLintItem` (if not implementing) + - Note: Both conditions are checked independently. A class should ideally satisfy both, but the linter reports separate errors for each missing requirement. + - **V2 API**: + - Class must implement `dev.dsf.bpe.v2.activity.ServiceTask` + - Error: `BpmnServiceTaskNoInterfaceClassImplementingLintItem` ##### User Tasks - **Name Validation**: - Task must have a non-empty name + - Error: `BpmnUserTaskNameEmptyLintItem` - **Form Key Validation**: - - `camunda:formKey` must be present and valid + - `camunda:formKey` must be present and non-empty + - Error: `BpmnUserTaskFormKeyEmptyLintItem` + - Must reference an external form (starting with "external:", "http://", or "https://") + - Error: `BpmnUserTaskFormKeyIsNotAnExternalFormLintItem` - Must reference a valid Questionnaire resource - **Listener Validation**: @@ -40,8 +61,73 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - Error: `BpmnUserTaskListenerJavaClassNotFoundLintItem` - Listener must have class attribute - Error: `BpmnUserTaskListenerMissingClassAttributeLintItem` - - Listener must extend/implement required class - - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + +- **API Version-Specific Requirements**: + - **V1 API**: + - Listener must extend `dev.dsf.bpe.v1.activity.DefaultUserTaskListener` OR implement `org.camunda.bpm.engine.delegate.TaskListener` + - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + - **V2 API**: + - Listener must extend `dev.dsf.bpe.v2.activity.DefaultUserTaskListener` OR implement `dev.dsf.bpe.v2.activity.UserTaskListener` + - Error: `BpmnUserTaskListenerNotExtendingOrImplementingRequiredClassLintItem` + +- **Task Listener Input Parameter Validation (V2 API only)**: + - Validates input parameters (`camunda:inputParameter`) within task listeners for API v2 + - Applies to all task listeners in API v2, with severity based on whether the listener extends `DefaultUserTaskListener` + + - **`practitionerRole` Parameter**: + - If a `practitionerRole` input parameter is defined in the task listener's `extensionElements`, its value must not be null or empty + - **Severity**: + - **ERROR**: When the task listener extends `dev.dsf.bpe.v2.activity.DefaultUserTaskListener` + - **WARN**: When the task listener does not extend `DefaultUserTaskListener` + - Error/Warning: `BpmnPractitionerRolehasNoValueOrNullLintItem` + - Success: `BpmnElementLintItemSuccess` (when value is present and non-empty) + + - **`practitioners` Parameter**: + - If a `practitioners` input parameter is defined in the task listener's `extensionElements`, its value must not be null or empty + - **Severity**: + - **ERROR**: When the task listener extends `dev.dsf.bpe.v2.activity.DefaultUserTaskListener` + - **WARN**: When the task listener does not extend `DefaultUserTaskListener` + - Error/Warning: `BpmnPractitionershasNoValueOrNullLintItem` + - Success: `BpmnElementLintItemSuccess` (when value is present and non-empty) + + - **Validation Behavior**: + - Only validates input parameters if they are explicitly defined in the BPMN file + - Supports various value formats: direct text content, ``, or `` with `` elements + - Validation is skipped if the input parameter is not present (no lint items generated) + - Validation only applies to API v2 task listeners + +- **Task Listener TaskOutput Field Injections Validation (V2 API only)**: + - Validates the taskOutput field injections (`taskOutputSystem`, `taskOutputCode`, `taskOutputVersion`) used to configure output parameters for UserTask listeners + - Applies to all task listeners in API v2 + + - **Completeness Check**: + - If any of the three fields (`taskOutputSystem`, `taskOutputCode`, `taskOutputVersion`) is set, all three must be set + - Error: `BpmnUserTaskListenerIncompleteTaskOutputFieldsLintItem` + - Message: "If taskOutputSystem, taskOutputCode, or taskOutputVersion is set, all three must be set" + - Validation is skipped if none of the fields are set + + - **FHIR Resource Validation**: + - **`taskOutputSystem`**: Should reference a valid CodeSystem URL + - Uses `FhirAuthorizationCache.containsSystem()` to check if the CodeSystem exists + - Error: `BpmnUserTaskListenerTaskOutputSystemInvalidFhirResourceLintItem` if CodeSystem is unknown + - Success: `BpmnElementLintItemSuccess` when CodeSystem is valid + + - **`taskOutputCode`**: Should be a valid code in the referenced CodeSystem + - Uses `FhirAuthorizationCache.isUnknown()` to check if the code exists in the CodeSystem + - Error: `BpmnUserTaskListenerTaskOutputCodeInvalidFhirResourceLintItem` if code is unknown + - Success: `BpmnElementLintItemSuccess` when code is valid + + - **`taskOutputVersion`**: Must contain a placeholder (e.g., `#{version}`) + - Uses `LintingUtils.containsPlaceholder()` to check for placeholders + - Warning: `BpmnUserTaskListenerTaskOutputVersionNoPlaceholderLintItem` if no placeholder found + - Success: `BpmnElementLintItemSuccess` when placeholder is present + + - **Validation Behavior**: + - Only validates field injections if they are explicitly defined in the task listener's `extensionElements` + - Field values are read from `camunda:field` elements with `camunda:stringValue` or nested `` elements + - Validation is skipped if none of the fields are set (no lint items generated) + - Validation only applies to API v2 task listeners + - FHIR resource validation is only performed if all three fields are set (completeness check passes) ##### Send Tasks @@ -52,8 +138,18 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - Implementation class must exist - Error: `BpmnMessageSendTaskImplementationClassEmptyLintItem` - Error: `BpmnMessageSendTaskImplementationClassNotFoundLintItem` - - Class must implement required interface - - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` + +- **API Version-Specific Requirements**: + - **V1 API**: + - Both checks are performed separately: + - Class must extend `dev.dsf.bpe.v1.activity.AbstractTaskMessageSend` + - Error: `BpmnSendTaskNotExtendingAbstractTaskMessageSendLintItem` (if not extending) + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` (if not implementing) + - Note: Both conditions are checked independently. A class should ideally satisfy both, but the linter reports separate errors for each missing requirement. + - **V2 API**: + - Class must implement `dev.dsf.bpe.v2.activity.MessageSendTask` + - Error: `BpmnSendTaskNoInterfaceClassImplementingLintItem` - **Field Injection Validation**: - Message-related field injections must be valid @@ -77,18 +173,26 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - Error: `BpmnEventNameEmptyLintItem` - Error: `BpmnMessageStartEventMessageNameEmptyLintItem` - Error: `BpmnMessageIntermediateCatchEventNameEmptyLintItem` + - Error: `BpmnMessageIntermediateCatchEventMessageNameEmptyLintItem` - Error: `BpmnMessageBoundaryEventNameEmptyLintItem` - **Implementation Class Validation**: - For send events, implementation class must exist - Error: `BpmnMessageSendEventImplementationClassEmptyLintItem` - Error: `BpmnMessageSendEventImplementationClassNotFoundLintItem` - - Class must implement JavaDelegate - - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` - Intermediate throw events should not have message definitions - Error: `BpmnMessageIntermediateThrowEventHasMessageLintItem` - - Throw events must implement required interface - - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` + +- **API Version-Specific Requirements**: + - **V1 API**: + - Class must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnMessageSendEventImplementationClassNotImplementingJavaDelegateLintItem` + - Throw events must implement `org.camunda.bpm.engine.delegate.JavaDelegate` + - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` + - **V2 API**: + - Message Intermediate Throw Events must implement `dev.dsf.bpe.v2.activity.MessageIntermediateThrowEvent` + - Message End Events must implement `dev.dsf.bpe.v2.activity.MessageEndEvent` + - Error: `BpmnEndOrIntermediateThrowEventMissingInterfaceLintItem` - **Field Injection Validation**: - `profile` field injection: @@ -134,6 +238,14 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi ##### Signal Events - **Signal Definition Validation**: + - Signal end events must have a non-empty name + - Error: `BpmnSignalEndEventNameEmptyLintItem` + - Signal end events must have a signal definition + - Error: `BpmnSignalEndEventSignalEmptyLintItem` + - Signal intermediate throw events must have a non-empty name + - Error: `BpmnSignalIntermediateThrowEventNameEmptyLintItem` + - Signal intermediate throw events must have a signal definition + - Error: `BpmnSignalIntermediateThrowEventSignalEmptyLintItem` - Signal definitions must be valid - Signal references must be correct @@ -148,6 +260,8 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - **Sequence Flow Validation**: - Outgoing sequence flows must have appropriate names + - When multiple outgoing flows exist, gateway must have a name + - Error: `BpmnExclusiveGatewayHasMultipleOutgoingFlowsButNameIsEmptyLintItem` - Conditional expressions required when multiple paths exist - Default flow validation @@ -155,6 +269,8 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - **Sequence Flow Validation**: - Similar requirements as exclusive gateways + - When multiple outgoing flows exist, gateway must have a name + - Error: `BpmnInclusiveGatewayHasMultipleOutgoingFlowsButNameIsEmptyLintItem` - Multiple path handling ##### Event-Based Gateways @@ -177,6 +293,7 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - **Asynchronous Execution**: - `asyncBefore` must be set to `true` for proper asynchronous execution - Required for multi-instance subprocesses + - Error: `BpmnSubProcessHasMultiInstanceButIsNotAsyncBeforeTrueLintItem` ##### Start/End Events in SubProcesses @@ -185,6 +302,8 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - Error: `BpmnStartEventNotPartOfSubProcessLintItem` - End events must be part of subprocess - Error: `BpmnEndEventNotPartOfSubProcessLintItem` + - End events inside subprocesses should have `asyncAfter` set to `true` + - Error: `BpmnEndEventInsideSubProcessShouldHaveAsyncAfterTrueLintItem` #### Floating Elements @@ -192,6 +311,20 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi - Elements must be properly connected - Error: `BpmnFloatingElementLintItem` +#### Execution Listeners + +- **Execution Listener Validation**: + - Execution listener classes must exist in the classpath + - Error: `BpmnExecutionListenerClassNotFoundLintItem` + +- **API Version-Specific Requirements**: + - **V1 API**: + - Execution listener classes must implement `org.camunda.bpm.engine.delegate.ExecutionListener` + - Error: `BpmnExecutionListenerNotImplementingRequiredInterfaceLintItem` + - **V2 API**: + - Execution listener classes must implement `dev.dsf.bpe.v2.activity.ExecutionListener` + - Error: `BpmnExecutionListenerNotImplementingRequiredInterfaceLintItem` + #### Unknown Field Injections - **Field Injection Validation**: @@ -202,6 +335,12 @@ The linter performs comprehensive validation on BPMN 2.0 process definitions usi The linter validates FHIR resources against DSF-specific profiles and HL7 FHIR specifications. +#### Unparsable FHIR Resources + +- **Resource Parsing**: + - FHIR resources must be valid XML or JSON + - Error: `UnparsableFhirResourceLintItem` + #### Task Resources Task resources are validated against the DSF Task base profile (`http://dsf.dev/fhir/StructureDefinition/dsf-task-base`). @@ -286,6 +425,8 @@ Task resources are validated against the DSF Task base profile (`http://dsf.dev/ - Error: `FhirTaskStatusRequiredInputBusinessKeyLintItem` - Must be absent when status is "draft" - Error: `FhirTaskBusinessKeyExistsLintItem` + - Business key validation may be skipped in certain conditions + - Warning: `FhirTaskBusinessKeyCheckIsSkippedLintItem` - `correlation-key` slice: - Validated against StructureDefinition cardinality - Error: `FhirTaskCorrelationExistsLintItem` @@ -419,7 +560,7 @@ ValueSet resources are validated against the DSF ValueSet base profile. - **CodeSystem Validation**: - CodeSystem URLs validated against DSF terminology cache - - Error: `FhirValueSetUnknownCodeLintItem` + - Warn: `FhirValueSetUnknownCodeLintItem` - Code exists but in different CodeSystem - Error: `FhirValueSetFalseUrlReferencedLintItem` @@ -600,7 +741,8 @@ ValueSet resources are validated against the DSF ValueSet base profile. #### ServiceLoader Registration - **Registration File**: - - Must be registered in `META-INF/services/dev.dsf.bpe.process.ProcessPlugin` (v1) or equivalent (v2) + - **V1 API**: Must be registered in `META-INF/services/dev.dsf.bpe.v1.ProcessPluginDefinition` + - **V2 API**: Must be registered in `META-INF/services/dev.dsf.bpe.v2.ProcessPluginDefinition` - Error: `PluginDefinitionMissingServiceLoaderRegistrationLintItem` - Plugin class must be loadable - Error: `PluginDefinitionProcessPluginRessourceNotLoadedLintItem` @@ -645,4 +787,4 @@ The linter performs project-level analysis to identify unreferenced resources: - FHIR resources that are not referenced by any BPMN process - Reported as warnings -This analysis works uniformly for single-plugin and multi-plugin projects. +This analysis works uniformly for single-plugin and multi-plugin projects. \ No newline at end of file