Skip to content

Commit bd334fd

Browse files
committed
TRUNK-6469: Add support for automatic initialization of Envers audit tables
1 parent c3e9f39 commit bd334fd

File tree

16 files changed

+701
-1
lines changed

16 files changed

+701
-1
lines changed

CLAUDE.md

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
OpenMRS is a patient-based medical record system focusing on providing a free, customizable electronic medical record system (EMR). This is the core platform repository written in Java, using Spring Framework, Hibernate ORM, and a modular architecture that allows extending functionality through modules.
8+
9+
**Version**: 3.0.0-SNAPSHOT
10+
**License**: Mozilla Public License 2.0 with Healthcare Disclaimer
11+
**Java Version**: 21 (JDK 21 minimum)
12+
**Maven Version**: 3.8.0+ required
13+
14+
## Common Development Commands
15+
16+
### Building the Project
17+
```bash
18+
# Full build with all tests
19+
mvn clean package
20+
21+
# Build without tests (faster for quick compilation)
22+
mvn clean install -DskipTests
23+
24+
# Build with specific Maven profile
25+
mvn clean install -Pskip-all-checks
26+
```
27+
28+
### Running Tests
29+
```bash
30+
# Run all unit tests
31+
mvn test
32+
33+
# Run integration tests
34+
mvn test -Pskip-default-test -Pintegration-test
35+
36+
# Run specific test class
37+
mvn test -Dtest=PatientServiceTest
38+
39+
# Run specific test method
40+
mvn test -Dtest=PatientServiceTest#shouldGetPatientByUuid
41+
```
42+
43+
### Running the Application Locally
44+
```bash
45+
# Using Jetty (from webapp directory)
46+
cd webapp
47+
mvn jetty:run
48+
49+
# Using Jetty on custom port
50+
mvn -Djetty.http.port=8081 jetty:run
51+
52+
# Using Cargo
53+
cd webapp
54+
mvn cargo:run
55+
56+
# Using Cargo on custom port
57+
mvn -Dcargo.servlet.port=8081 cargo:run
58+
```
59+
60+
After starting, access the application at `http://localhost:8080/openmrs`
61+
62+
### Docker Development
63+
```bash
64+
# Build development image
65+
docker compose build
66+
67+
# Build with custom Maven arguments
68+
docker compose build --build-arg MVN_ARGS='install -DskipTests'
69+
70+
# Run development version
71+
docker compose up
72+
73+
# Build and run production version
74+
docker compose -f docker-compose.yml build
75+
docker compose -f docker-compose.yml up
76+
77+
# Run with ElasticSearch backend
78+
docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.es.yml up
79+
```
80+
81+
### Code Quality and Formatting
82+
```bash
83+
# Run checkstyle
84+
mvn checkstyle:check
85+
86+
# Format code (uses Eclipse formatter)
87+
mvn java-formatter:format
88+
89+
# Check license headers
90+
mvn license:check
91+
92+
# Format license headers
93+
mvn license:format
94+
```
95+
96+
## Architecture
97+
98+
### Multi-Module Structure
99+
100+
The repository is organized as a Maven multi-module project:
101+
102+
- **api/** - Core Java API containing domain models, service interfaces, and business logic
103+
- Domain models: `org.openmrs.*` (Patient, Encounter, Obs, Concept, etc.)
104+
- Service interfaces: `org.openmrs.api.*` (PatientService, ConceptService, etc.)
105+
- Service implementations: `org.openmrs.api.impl.*`
106+
- DAO interfaces: `org.openmrs.api.db.*`
107+
- Hibernate DAOs: `org.openmrs.api.db.hibernate.*`
108+
109+
- **web/** - Web layer containing controllers, filters, and web utilities
110+
- Controllers: `org.openmrs.web.controller.*`
111+
- Filters: `org.openmrs.web.filter.*`
112+
113+
- **webapp/** - WAR packaging module that assembles the final web application
114+
115+
- **test/** - Shared test infrastructure and base test classes
116+
117+
- **tools/** - Development tools (formatters, doclets)
118+
119+
- **liquibase/** - Database schema management and migration scripts
120+
121+
### Layered Architecture
122+
123+
OpenMRS follows a classic layered architecture:
124+
125+
1. **Domain Model Layer** (`org.openmrs.*`)
126+
- All domain objects extend either `BaseOpenmrsData` (for clinical data) or `BaseOpenmrsMetadata` (for configuration)
127+
- `BaseOpenmrsData` provides: uuid, creator, dateCreated, changedBy, dateChanged, voided, voidedBy, dateVoided, voidReason
128+
- `BaseOpenmrsMetadata` adds: name, description, retired, retiredBy, dateRetired, retireReason
129+
- Domain objects implement marker interfaces: `OpenmrsObject`, `Auditable`, `Voidable`, `Retireable`
130+
131+
2. **Service Layer** (`org.openmrs.api.*`)
132+
- All services implement `OpenmrsService` interface (onStartup/onShutdown lifecycle methods)
133+
- Service implementations extend `BaseOpenmrsService`
134+
- Services are annotated with `@Transactional` for transaction management
135+
- Retrieved via Spring using `Context.getService(ServiceClass.class)` or dependency injection
136+
- Common services: PatientService, ConceptService, EncounterService, ObsService, OrderService, PersonService
137+
138+
3. **DAO Layer** (`org.openmrs.api.db.*` and `org.openmrs.api.db.hibernate.*`)
139+
- DAO interfaces define data access contracts
140+
- Hibernate implementations provide persistence
141+
- Generic DAOs: `OpenmrsDataDAO`, `OpenmrsMetadataDAO`, `OpenmrsObjectDAO`
142+
- Entity-specific DAOs for complex queries
143+
144+
4. **Web Layer** (`org.openmrs.web.*`)
145+
- Spring MVC controllers handle HTTP requests
146+
- Filters handle initialization, authentication, and request processing
147+
- `Context` class provides static access to services and session management
148+
149+
### Key Design Patterns
150+
151+
**Context Pattern**: The `Context` class provides static access to authenticated user, services, and application state. Always use `Context.getService()` to retrieve services rather than direct instantiation.
152+
153+
**Service Locator**: Services are registered in Spring and accessed via `Context.getService(ServiceClass.class)`. Custom services from modules can be accessed using `Context.getService(CustomService.class)`.
154+
155+
**DAO Pattern**: Data access is abstracted through DAO interfaces with Hibernate implementations. This allows swapping persistence implementations without affecting business logic.
156+
157+
**Interceptors**: Hibernate interceptors enforce business rules at persistence layer:
158+
- `AuditableInterceptor` - Automatically sets audit fields (creator, dateCreated, etc.)
159+
- `ImmutableEntityInterceptor` - Prevents modification of immutable entities
160+
- `DropMillisecondsHibernateInterceptor` - Ensures database compatibility
161+
162+
**Module System**: OpenMRS supports dynamic loading of modules that can extend core functionality by providing additional services, domain objects, and web resources.
163+
164+
### Database Schema Management
165+
166+
OpenMRS uses Liquibase for database schema versioning and migration:
167+
168+
- Schema snapshots: `api/src/main/resources/org/openmrs/liquibase/snapshots/schema-only/`
169+
- Core data: `api/src/main/resources/org/openmrs/liquibase/snapshots/core-data/`
170+
- Updates: `api/src/main/resources/org/openmrs/liquibase/updates/`
171+
172+
When making database changes:
173+
1. Add changesets to the appropriate `liquibase-update-to-latest-*.xml` file
174+
2. Liquibase automatically applies changes on application startup
175+
3. For new major/minor versions, generate new snapshots (see liquibase/README.md)
176+
177+
### Testing Infrastructure
178+
179+
**Base Test Classes**:
180+
- `BaseContextSensitiveTest` - Loads full Spring context with H2 in-memory database for integration tests
181+
- Tests extending this class have access to all services via `Context.getService()`
182+
- Test data can be loaded using `@DataSet` annotations or by placing XML datasets in `test/resources`
183+
184+
**Test Naming Conventions**:
185+
- Unit tests: `*Test.java` (run in standard test phase)
186+
- Integration tests: `*IT.java` (run with `-Pintegration-test` profile)
187+
- Database integration tests: `*DatabaseIT.java` (separate execution group)
188+
189+
**Test Database**:
190+
- H2 in-memory database for most tests
191+
- Testcontainers for database-specific integration tests (MySQL, PostgreSQL, MariaDB)
192+
- Standard test database initialized with `initial_test_db.sql`
193+
194+
### Authentication and Security
195+
196+
- Spring Security handles authentication and authorization
197+
- Privileges control access to specific operations
198+
- Roles group privileges
199+
- Use `@Authorized` annotation on service methods to enforce privilege requirements
200+
- `Context.getAuthenticatedUser()` returns current authenticated user
201+
- CSRF protection via OWASP CSRFGuard
202+
203+
### Search and Indexing
204+
205+
- Hibernate Search with Lucene backend (or ElasticSearch as alternative)
206+
- Full-text search on Patients, Concepts, and other entities
207+
- Search indexes automatically maintained by Hibernate Search
208+
- Rebuild indexes via Administration UI or REST endpoint if needed
209+
210+
## Important Development Practices
211+
212+
### Working with Domain Objects
213+
214+
When creating or modifying domain objects:
215+
- Always extend appropriate base classes (`BaseOpenmrsData` or `BaseOpenmrsMetadata`)
216+
- Implement proper `equals()` and `hashCode()` based on uuid
217+
- Add Hibernate mapping annotations (`@Entity`, `@Table`, `@Column`, etc.)
218+
- Use `@AttributeOverride` for audit fields to customize column names if needed
219+
- For @ManyToOne audit fields, use `fetch = FetchType.LAZY` (default fetch is now LAZY)
220+
221+
### Working with Services
222+
223+
When implementing service methods:
224+
- Add `@Transactional` at class or method level
225+
- Use `@Authorized(PrivilegeConstants.SOME_PRIVILEGE)` to enforce security
226+
- Validate inputs using `ValidateUtil.validate(object)` for JSR-303 validation
227+
- Throw `APIException` or appropriate subclass for business rule violations
228+
- Delegate to DAO layer for all data access
229+
230+
### Working with DAOs
231+
232+
- Implement DAO interface in `org.openmrs.api.db`
233+
- Create Hibernate implementation in `org.openmrs.api.db.hibernate`
234+
- Use `SessionFactory` injected by Spring
235+
- Prefer HQL or Criteria API over native SQL when possible
236+
- For complex queries, use `@NamedQuery` on entity classes
237+
238+
### JIRA Workflow
239+
240+
OpenMRS uses JIRA for issue tracking at https://issues.openmrs.org
241+
242+
When working on issues:
243+
1. Find a "Ready For Work" issue
244+
2. Claim the issue (changes status to "In Progress")
245+
3. Create a branch named after the JIRA ticket (e.g., `TRUNK-6444`)
246+
4. Make changes following coding conventions
247+
5. Include ticket number in all commit messages: `TRUNK-6444: Description of change`
248+
6. Squash commits into atomic units before creating PR
249+
7. Create pull request and link it in JIRA
250+
8. Click "Request Code Review" button in JIRA
251+
252+
### Coding Conventions
253+
254+
- Follow Eclipse code formatter configuration: `tools/src/main/resources/eclipse/OpenMRSFormatter.xml`
255+
- Use checkstyle configuration: `checkstyle.xml`
256+
- All files must have MPL 2.0 license header
257+
- Use meaningful variable names and JavaDoc for public APIs
258+
- Maximum line length: variable (formatter handles this)
259+
- Use slf4j for logging: `private static final Logger log = LoggerFactory.getLogger(ClassName.class);`
260+
261+
### Module Development
262+
263+
Modules extend OpenMRS functionality:
264+
- Modules packaged as OMOD files (OpenMRS Module)
265+
- Can add new services, domain objects, web resources
266+
- Activated/deactivated at runtime
267+
- Module API separate from OMOD (web components)
268+
- See https://wiki.openmrs.org/display/docs/Modules for module development guide
269+
270+
### Performance Considerations
271+
272+
- Use lazy loading for associations where appropriate (now default for @ManyToOne audit fields)
273+
- Batch processing for large datasets
274+
- Cache frequently accessed data using Infinispan
275+
- Optimize HQL queries with proper indexes
276+
- Use pagination for large result sets
277+
- Profile with JProfiler or VisualVM if performance issues arise
278+
279+
## Common Troubleshooting
280+
281+
**Build failures**: Ensure Java 21 and Maven 3.8.0+ are installed. Clear local Maven repository if dependency issues occur: `rm -rf ~/.m2/repository/org/openmrs`
282+
283+
**Test failures**: Some integration tests require specific database state. Run `mvn clean install` to reset test environment.
284+
285+
**Module loading errors**: Check module compatibility with platform version. Modules must be built for Platform 2.x or 3.x.
286+
287+
**Database migration issues**: Check `liquibasechangelog` table for failed changesets. Review OpenMRS logs for Liquibase errors.
288+
289+
## Resources
290+
291+
- **JIRA**: https://issues.openmrs.org
292+
- **Wiki**: https://wiki.openmrs.org
293+
- **Talk Forum**: https://talk.openmrs.org
294+
- **Developer Guide**: https://openmrs.atlassian.net/wiki/spaces/docs/pages/25477022/Getting+Started+as+a+Developer
295+
- **Module Repository**: https://addons.openmrs.org
296+
- **Demo Site**: http://demo.openmrs.org

api/ConceptName/segments_1

69 Bytes
Binary file not shown.

api/ConceptName/write.lock

Whitespace-only changes.

api/Drug/segments_1

69 Bytes
Binary file not shown.

api/Drug/write.lock

Whitespace-only changes.

api/PatientIdentifier/segments_1

69 Bytes
Binary file not shown.

api/PatientIdentifier/write.lock

Whitespace-only changes.

api/PersonAttribute/segments_1

69 Bytes
Binary file not shown.

api/PersonAttribute/write.lock

Whitespace-only changes.

api/PersonName/segments_1

69 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)