diff --git a/.github/workflows/build-2.x.yaml b/.github/workflows/build-2.x.yaml
index c6164fbefc7e..3b507728f4b2 100644
--- a/.github/workflows/build-2.x.yaml
+++ b/.github/workflows/build-2.x.yaml
@@ -28,14 +28,14 @@ jobs:
- 8
runs-on: ${{ matrix.platform }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: ${{ matrix.java-version }}
- name: Cache Maven packages
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index b139ab896fda..883d0f20309c 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -8,12 +8,14 @@ on:
- master
- 2.4.x
- 2.5.x
+ - 2.6.x
pull_request:
types:
branches:
- master
- 2.4.x
- 2.5.x
+ - 2.6.x
workflow_dispatch:
jobs:
@@ -25,30 +27,20 @@ jobs:
java-version:
- 8
- 11
+ - 17
runs-on: ${{ matrix.platform }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: ${{ matrix.java-version }}
- - name: Cache Maven packages
- uses: actions/cache@v3
- with:
- path: ~/.m2
- key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- restore-keys: ${{ runner.os }}-m2
- - name: Cache SonarCloud packages
- uses: actions/cache@v3
- with:
- path: ~/.sonar/cache
- key: ${{ runner.os }}-sonar
- restore-keys: ${{ runner.os }}-sonar
+ cache: 'maven'
- name: Install dependencies
run: mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true --batch-mode --show-version --file pom.xml
- name: Build with Maven
- run: mvn clean install && mvn test -Pskip-default-test -Pintegration-test --batch-mode --file pom.xml
+ run: mvn clean install --batch-mode && mvn test -Pskip-default-test -Pintegration-test --batch-mode --file pom.xml
# this is necessary to populate the environment variables for Coveralls properly
- name: Set branch name and PR number
id: refs
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index ccfab002256e..23cbfb9bf8eb 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -38,11 +38,11 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
@@ -67,4 +67,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml
deleted file mode 100644
index f486ebb703e6..000000000000
--- a/.github/workflows/qa.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-name: QaFramework Trigger
-on:
- push:
- branches: [master]
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Trigger QAFramework
- uses: peter-evans/repository-dispatch@v2
- with:
- token: ${{secrets.ACTIONS_TOKEN}}
- repository: openmrs/openmrs-contrib-qaframework
- event-type: qa
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index e1666d19edb7..b7cb7eaf2d97 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v7
+ - uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 150
diff --git a/.gitignore b/.gitignore
index f1992bf4bb70..a77727e8d7f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,6 +75,7 @@ nb-configuration.xml
/webapp/src/main/webapp/WEB-INF/dwr-modules.xml
/webapp/src/main/webapp/WEB-INF/module_messages*
/web/WEB-INF/dwr-modules.xml
+/openmrs-merged.properties
#############
### log files ###
diff --git a/Dockerfile b/Dockerfile
index 6e9ef1837c54..08955eee9daf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,10 +8,47 @@
# Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
# graphic logo is a trademark of OpenMRS Inc.
+### Compile Stage (platform-agnostic)
+FROM --platform=$BUILDPLATFORM maven:3.8-amazoncorretto-8 as compile
+
+RUN yum -y update && yum -y install git && yum clean all
+
+WORKDIR /openmrs_core
+
+ENV OMRS_SDK_PLUGIN="org.openmrs.maven.plugins:openmrs-sdk-maven-plugin"
+ENV OMRS_SDK_PLUGIN_VERSION="4.5.0"
+
+COPY docker-pom.xml .
+
+ARG MVN_SETTINGS="-s /usr/share/maven/ref/settings-docker.xml"
+
+# Setup and cache SDK
+RUN mvn $MVN_SETTINGS -f docker-pom.xml $OMRS_SDK_PLUGIN:$OMRS_SDK_PLUGIN_VERSION:setup-sdk -N -DbatchAnswers=n
+
+COPY pom.xml .
+COPY test/pom.xml test/
+COPY tools/pom.xml tools/
+COPY liquibase/pom.xml liquibase/
+COPY api/pom.xml api/
+COPY web/pom.xml web/
+COPY webapp/pom.xml webapp/
+
+# Install dependencies
+RUN mvn $MVN_SETTINGS -B dependency:go-offline -P !default-tools.jar,!mac-tools.jar
+
+# Copy remaining files
+COPY . .
+
+# Append --build-arg MVN_ARGS='clean install' to change default maven arguments
+ARG MVN_ARGS='clean install -DskipTests'
+
+# Build the project
+RUN mvn $MVN_SETTINGS $MVN_ARGS
+
### Development Stage
FROM maven:3.8-amazoncorretto-8 as dev
-RUN yum -y update && yum -y install tar gzip && yum clean all
+RUN yum -y update && yum -y install tar gzip git && yum clean all
# Setup Tini
ARG TARGETARCH
@@ -30,70 +67,20 @@ ARG TOMCAT_SHA="57cbe9608a9c4e88135e5f5480812e8d57690d5f3f6c43a7c05fe647bddb7c3b
ARG TOMCAT_URL="https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz"
RUN curl -fL -o /tmp/apache-tomcat.tar.gz "$TOMCAT_URL" \
&& echo "${TOMCAT_SHA} /tmp/apache-tomcat.tar.gz" | sha512sum -c \
- && mkdir -p /usr/local/tomcat && gzip -d /tmp/apache-tomcat.tar.gz && tar -xvf /tmp/apache-tomcat.tar -C /usr/local/tomcat/ --strip-components=1 \
- && rm -rf /tmp/apache-tomcat.tar.gz /usr/local/tomcat/webapps/*
+ && mkdir -p /usr/local/tomcat && gzip -d /tmp/apache-tomcat.tar.gz \
+ && tar -xvf /tmp/apache-tomcat.tar -C /usr/local/tomcat/ --strip-components=1 \
+ && rm -rf /tmp/apache-tomcat.tar.gz /usr/local/tomcat/webapps/*
WORKDIR /openmrs_core
-ENV OPENMRS_SDK_PLUGIN="org.openmrs.maven.plugins:openmrs-sdk-maven-plugin:4.5.0"
-ENV OPENMRS_SDK_PLUGIN_VERSION="4.5.0"
-ENV MVN_ARGS_SETTINGS="-s /usr/share/maven/ref/settings-docker.xml"
+COPY --from=compile /usr/share/maven/ref /usr/share/maven/ref
-COPY checkstyle.xml checkstyle-suppressions.xml CONTRIBUTING.md findbugs-include.xml LICENSE license-header.txt \
- NOTICE.md README.md ruleset.xml SECURITY.md ./
-
-COPY pom.xml .
-
-# Setup and cache SDK
-RUN mvn $OPENMRS_SDK_PLUGIN:setup-sdk -N -DbatchAnswers=n $MVN_ARGS_SETTINGS
-
-# Store dependencies in /usr/share/maven/ref/repository for re-use when running
-# If mounting ~/.m2:/root/.m2 then the /usr/share/maven/ref content will be copied over from the image to /root/.m2
-RUN mvn --non-recursive dependency:go-offline $MVN_ARGS_SETTINGS
-
-# Copy remainig poms to satisfy dependencies
-COPY liquibase/pom.xml ./liquibase/
-COPY tools/pom.xml ./tools/
-COPY test/pom.xml ./test/
-COPY api/pom.xml ./api/
-COPY web/pom.xml ./web/
-COPY webapp/pom.xml ./webapp/
-
-# Exclude tools as it fails trying to fetch tools.jar
-RUN mvn -pl !tools dependency:go-offline $MVN_ARGS_SETTINGS
-
-# Append --build-arg MVN_ARGS='install' to change default maven arguments
-# Build modules individually to benefit from caching
-ARG MVN_ARGS='install'
-
-# Build the parent project
-RUN mvn --non-recursive $MVN_ARGS_SETTINGS $MVN_ARGS
-
-# Build individually to benefit from caching
-COPY liquibase ./liquibase/
-RUN mvn -pl liquibase $MVN_ARGS_SETTINGS $MVN_ARGS
-
-COPY tools/ ./tools/
-RUN mvn -pl tools $MVN_ARGS_SETTINGS $MVN_ARGS
-
-COPY test/ ./test/
-RUN mvn -pl test $MVN_ARGS_SETTINGS $MVN_ARGS
-
-COPY api/ ./api/
-RUN mvn -pl api $MVN_ARGS_SETTINGS $MVN_ARGS
-
-COPY web/ ./web/
-RUN mvn -pl web $MVN_ARGS_SETTINGS $MVN_ARGS
-
-COPY webapp/ ./webapp/
-RUN mvn -pl webapp $MVN_ARGS_SETTINGS $MVN_ARGS
+COPY --from=compile /openmrs_core /openmrs_core/
RUN mkdir -p /openmrs/distribution/openmrs_core/ \
- && cp /openmrs_core/webapp/target/openmrs.war /openmrs/distribution/openmrs_core/openmrs.war
-
-# Copy in the start-up scripts
-COPY wait-for-it.sh startup-init.sh startup.sh startup-dev.sh /openmrs/
-RUN chmod +x /openmrs/wait-for-it.sh && chmod +x /openmrs/startup-init.sh && chmod +x /openmrs/startup.sh \
+ && cp /openmrs_core/webapp/target/openmrs.war /openmrs/distribution/openmrs_core/openmrs.war \
+ && cp /openmrs_core/wait-for-it.sh /openmrs_core/startup-init.sh /openmrs_core/startup.sh /openmrs_core/startup-dev.sh /openmrs/ \
+ && chmod +x /openmrs/wait-for-it.sh && chmod +x /openmrs/startup-init.sh && chmod +x /openmrs/startup.sh \
&& chmod +x /openmrs/startup-dev.sh
EXPOSE 8080
@@ -107,7 +94,7 @@ CMD ["/openmrs/startup-dev.sh"]
### Production Stage
FROM tomcat:8.5-jdk8-corretto
-RUN yum -y update && yum -y install shadow-utils && yum clean all && rm -rf /usr/local/tomcat/webapps/*
+RUN yum -y update && yum clean all && rm -rf /usr/local/tomcat/webapps/*
# Setup Tini
ARG TARGETARCH
@@ -118,19 +105,23 @@ ARG TINI_SHA_ARM64="07952557df20bfd2a95f9bef198b445e006171969499a1d361bd9e6f8e5e
RUN if [ "$TARGETARCH" = "arm64" ] ; then TINI_URL="${TINI_URL}-arm64" TINI_SHA=${TINI_SHA_ARM64} ; fi \
&& curl -fsSL -o /usr/bin/tini ${TINI_URL} \
&& echo "${TINI_SHA} /usr/bin/tini" | sha256sum -c \
- && chmod +x /usr/bin/tini
+ && chmod g+rx /usr/bin/tini
RUN sed -i '/Connector port="8080"/a URIEncoding="UTF-8" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>"' \
- /usr/local/tomcat/conf/server.xml
+ /usr/local/tomcat/conf/server.xml \
+ && chmod -R g+rx /usr/local/tomcat \
+ && touch /usr/local/tomcat/bin/setenv.sh && chmod g+w /usr/local/tomcat/bin/setenv.sh \
+ && chmod -R g+w /usr/local/tomcat/webapps /usr/local/tomcat/logs /usr/local/tomcat/work /usr/local/tomcat/temp
-RUN adduser openmrs && mkdir -p /openmrs/data/modules \
+RUN mkdir -p /openmrs/data/modules \
&& mkdir -p /openmrs/data/owa \
&& mkdir -p /openmrs/data/configuration \
- && chown -R openmrs /openmrs
+ && mkdir -p /openmrs/data/configuration_checksums \
+ && chmod -R g+rw /openmrs
# Copy in the start-up scripts
-COPY wait-for-it.sh startup-init.sh startup.sh /openmrs/
-RUN chmod +x /openmrs/wait-for-it.sh && chmod +x /openmrs/startup-init.sh && chmod +x /openmrs/startup.sh
+COPY --from=dev /openmrs/wait-for-it.sh /openmrs/startup-init.sh /openmrs/startup.sh /openmrs/
+RUN chmod g+x /openmrs/wait-for-it.sh && chmod g+x /openmrs/startup-init.sh && chmod g+x /openmrs/startup.sh
WORKDIR /openmrs
@@ -140,6 +131,10 @@ COPY --from=dev /openmrs/distribution/openmrs_core/openmrs.war /openmrs/distribu
EXPOSE 8080
+# Run as non-root user using Bitnami approach, see e.g.
+# https://github.com/bitnami/containers/blob/6c8f10bbcf192ab4e575614491abf10697c46a3e/bitnami/tomcat/8.5/debian-11/Dockerfile#L54
+USER 1001
+
ENTRYPOINT ["/usr/bin/tini", "--"]
# See startup-init.sh for all configurable environment variables
diff --git a/README.md b/README.md
index 0994cd58e7f2..a5eb08a94bb2 100644
--- a/README.md
+++ b/README.md
@@ -106,7 +106,7 @@ docker-compose build
```
It calls `mvn install` by default. If you would like to customize mvn build arguments you can do so by running:
```bash
-docker-compose build --build-args MVN_ARGS='install -DskipTests'
+docker-compose build --build-arg MVN_ARGS='install -DskipTests'
```
It is also possible to use the built dev image to run jetty:
```bash
@@ -124,6 +124,28 @@ The production version can be run with:
```bash
docker-compose -f docker-compose.yml up
```
+If you want to debug, you need to run a development version and connect your debugger to port 8000, which is exposed by default.
+
+Unfortunately, at this point any code changes require full restart and rebuild of the docker container. To speed up the process,
+please use:
+```bash
+docker-compose build --build-arg MVN_ARGS='install -DskipTests'
+docker-compose up
+```
+We are working towards providing support for Spring Boot auto-reload feature, which will be documented here once ready.
+
+It is also possible to deploy an image built by our CI, which is published at
+https://hub.docker.com/r/openmrs/openmrs-core
+
+You can run any tag available with:
+```bash
+TAG=nightly docker-compose -f docker-compose.yml up
+```
+It is also possible to run a development version of an image with:
+```bash
+TAG=dev docker-compose up
+```
+All development versions contain dev suffix. The cache suffix is for use by our CI.
## Navigating the repository
diff --git a/api/pom.xml b/api/pom.xml
index ba4741d36910..d92c3468cc44 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -70,10 +70,6 @@
commons-io
commons-io
-
- org.azeckoski
- reflectutils
-
org.apache.velocity
velocity
@@ -279,6 +275,10 @@
org.apache.lucene
lucene-analyzers-phonetic
+
+ com.google.guava
+ guava
+
com.sun.mail
javax.mail
@@ -292,6 +292,10 @@
org.testcontainers
mysql
+
+ org.junit.jupiter
+ junit-jupiter-params
+
diff --git a/api/src/main/java/org/openmrs/BaseCustomizableMetadata.java b/api/src/main/java/org/openmrs/BaseCustomizableMetadata.java
index b18f445ab2c4..1b3d3e0f23ba 100644
--- a/api/src/main/java/org/openmrs/BaseCustomizableMetadata.java
+++ b/api/src/main/java/org/openmrs/BaseCustomizableMetadata.java
@@ -9,23 +9,35 @@
*/
package org.openmrs;
+import org.hibernate.annotations.BatchSize;
+import org.openmrs.attribute.Attribute;
+import org.openmrs.customdatatype.CustomValueDescriptor;
+import org.openmrs.customdatatype.Customizable;
+
+import javax.persistence.CascadeType;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import org.openmrs.attribute.Attribute;
-import org.openmrs.customdatatype.CustomValueDescriptor;
-import org.openmrs.customdatatype.Customizable;
-
/**
* Extension of {@link org.openmrs.BaseOpenmrsMetadata} for classes that support customization via user-defined attributes.
* @param the type of attribute held
* @since 1.9
*/
+@MappedSuperclass
public abstract class BaseCustomizableMetadata extends BaseChangeableOpenmrsMetadata implements Customizable {
+ @OrderBy("voided asc")
+ @BatchSize(size = 100)
+ @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
+ @JoinColumn(name = "location_id")
private Set attributes = new LinkedHashSet<>();
/**
diff --git a/api/src/main/java/org/openmrs/ConceptName.java b/api/src/main/java/org/openmrs/ConceptName.java
index 5691ad040a5b..8816525a75cb 100644
--- a/api/src/main/java/org/openmrs/ConceptName.java
+++ b/api/src/main/java/org/openmrs/ConceptName.java
@@ -16,6 +16,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
+import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilterFactory;
import org.apache.lucene.analysis.standard.StandardFilterFactory;
import org.apache.lucene.analysis.standard.StandardTokenizerFactory;
import org.codehaus.jackson.annotate.JsonIgnore;
@@ -37,8 +38,12 @@
* locale.
*/
@Indexed
-@AnalyzerDef(name = "ConceptNameAnalyzer", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = {
- @TokenFilterDef(factory = StandardFilterFactory.class), @TokenFilterDef(factory = LowerCaseFilterFactory.class) })
+@AnalyzerDef(
+ name = "ConceptNameAnalyzer", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = {
+ @TokenFilterDef(factory = StandardFilterFactory.class),
+ @TokenFilterDef(factory = LowerCaseFilterFactory.class),
+ @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class)
+ })
@Analyzer(definition = "ConceptNameAnalyzer")
public class ConceptName extends BaseOpenmrsObject implements Auditable, Voidable, java.io.Serializable {
diff --git a/api/src/main/java/org/openmrs/Condition.java b/api/src/main/java/org/openmrs/Condition.java
index 93fd2a81cac0..c16e86f6c1f4 100644
--- a/api/src/main/java/org/openmrs/Condition.java
+++ b/api/src/main/java/org/openmrs/Condition.java
@@ -9,6 +9,8 @@
*/
package org.openmrs;
+import org.openmrs.util.OpenmrsUtil;
+
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.AttributeOverride;
@@ -25,7 +27,6 @@
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
-
import java.util.Date;
/**
@@ -113,26 +114,79 @@ public Condition(CodedOrFreeText condition, ConditionClinicalStatus clinicalStat
this.endDate = endDate != null ? new Date(endDate.getTime()) : null;
this.patient = patient;
}
-
+
+ /**
+ * Creates a new Condition instance from the passed condition such that the newly created Condition
+ * matches the passed Condition @see Condition#matches, but does not equal the passed Condition (uuid, id differ)
+ * @param condition the Condition to copy
+ * @return a new Condition that is a copy of the passed condition
+ */
public static Condition newInstance(Condition condition) {
return copy(condition, new Condition());
}
-
+
+ /**
+ * Copies property values from the fromCondition to the toCondition such that fromCondition
+ * matches toCondition @see Condition#matches, but does not equal toCondition (uuid, id differ)
+ * @param fromCondition the Condition to copy from
+ * @param toCondition the Condition to copy into
+ * @return a new Condition that is a copy of the passed condition
+ */
public static Condition copy(Condition fromCondition, Condition toCondition) {
toCondition.setPreviousVersion(fromCondition.getPreviousVersion());
toCondition.setPatient(fromCondition.getPatient());
+ toCondition.setEncounter(fromCondition.getEncounter());
+ toCondition.setFormNamespaceAndPath(fromCondition.getFormNamespaceAndPath());
toCondition.setClinicalStatus(fromCondition.getClinicalStatus());
toCondition.setVerificationStatus(fromCondition.getVerificationStatus());
toCondition.setCondition(fromCondition.getCondition());
toCondition.setOnsetDate(fromCondition.getOnsetDate());
toCondition.setAdditionalDetail(fromCondition.getAdditionalDetail());
toCondition.setEndDate(fromCondition.getEndDate());
+ toCondition.setEndReason(fromCondition.getEndReason());
toCondition.setVoided(fromCondition.getVoided());
toCondition.setVoidedBy(fromCondition.getVoidedBy());
toCondition.setVoidReason(fromCondition.getVoidReason());
toCondition.setDateVoided(fromCondition.getDateVoided());
return toCondition;
}
+
+ /**
+ * Compares properties with those in the given Condition to determine if they have the same meaning
+ * This method will return true immediately following the creation of a Condition from another Condition
+ * @see Condition#newInstance(Condition)
+ * This method will return false if any value is different, excepting identity data (id, uuid)
+ * If the given instance is null, this will return false
+ * @param c the Condition to compare against
+ * @return true if the given Condition has the same meaningful properties as the passed Condition
+ * @since 2.6.1
+ */
+ public boolean matches(Condition c) {
+ if (c == null) {
+ return false;
+ }
+ CodedOrFreeText coft1 = getCondition() == null ? new CodedOrFreeText() : getCondition();
+ CodedOrFreeText coft2 = c.getCondition() == null ? new CodedOrFreeText() : c.getCondition();
+
+ boolean ret = (OpenmrsUtil.nullSafeEquals(getPreviousVersion(), c.getPreviousVersion()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getPatient(), c.getPatient()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getEncounter(), c.getEncounter()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getFormNamespaceAndPath(), c.getFormNamespaceAndPath()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getClinicalStatus(), c.getClinicalStatus()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getVerificationStatus(), c.getVerificationStatus()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(coft1.getCoded(), coft2.getCoded()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(coft1.getSpecificName(), coft2.getSpecificName()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(coft1.getNonCoded(), coft2.getNonCoded()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getOnsetDate(), c.getOnsetDate()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getAdditionalDetail(), c.getAdditionalDetail()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getEndDate(), c.getEndDate()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getEndReason(), c.getEndReason()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getVoided(), c.getVoided()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getVoidedBy(), c.getVoidedBy()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getVoidReason(), c.getVoidReason()));
+ ret = ret && (OpenmrsUtil.nullSafeEquals(getDateVoided(), c.getDateVoided()));
+ return ret;
+ }
/**
* Gets the condition id
diff --git a/api/src/main/java/org/openmrs/Encounter.java b/api/src/main/java/org/openmrs/Encounter.java
index a11a09d83756..9b5daced688f 100644
--- a/api/src/main/java/org/openmrs/Encounter.java
+++ b/api/src/main/java/org/openmrs/Encounter.java
@@ -480,6 +480,9 @@ public void setPatient(Patient patient) {
* @since 2.2
*/
public Set getDiagnoses() {
+ if (diagnoses == null) {
+ diagnoses = new LinkedHashSet<>();
+ }
return diagnoses;
}
diff --git a/api/src/main/java/org/openmrs/GlobalProperty.java b/api/src/main/java/org/openmrs/GlobalProperty.java
index 8201588e50d7..acc8ccae05ce 100644
--- a/api/src/main/java/org/openmrs/GlobalProperty.java
+++ b/api/src/main/java/org/openmrs/GlobalProperty.java
@@ -48,6 +48,13 @@ public class GlobalProperty extends BaseOpenmrsObject implements CustomValueDesc
private Date dateChanged;
+ private Privilege viewPrivilege;
+
+ private Privilege editPrivilege;
+
+ private Privilege deletePrivilege;
+
+
/**
* Default empty constructor
*/
@@ -337,4 +344,64 @@ public Date getDateChanged() {
public void setDateChanged(Date dateChanged) {
this.dateChanged = dateChanged;
}
+
+ /**
+ * Gets privilege which can view this globalProperty
+ * @return the viewPrivilege the privilege instance
+ *
+ * @since 2.7.0
+ */
+ public Privilege getViewPrivilege() {
+ return viewPrivilege;
+ }
+
+ /**
+ * Sets privilege which can view this globalProperty
+ * @param viewPrivilege the viewPrivilege to set
+ *
+ * @since 2.7.0
+ */
+ public void setViewPrivilege(Privilege viewPrivilege) {
+ this.viewPrivilege = viewPrivilege;
+ }
+
+ /**
+ * Gets privilege which can edit this globalProperty
+ * @return the editPrivilege the privilege instance
+ *
+ * @since 2.7.0
+ */
+ public Privilege getEditPrivilege() {
+ return editPrivilege;
+ }
+
+ /**
+ * Sets privilege which can edit this globalProperty
+ * @param editPrivilege the editPrivilege to set
+ *
+ * @since 2.7.0
+ */
+ public void setEditPrivilege(Privilege editPrivilege) {
+ this.editPrivilege = editPrivilege;
+ }
+
+ /**
+ * Get privilege which can delete this globalProperty
+ * @return the deletePrivilege the privilege instance
+ *
+ * @since 2.7.0
+ */
+ public Privilege getDeletePrivilege() {
+ return deletePrivilege;
+ }
+
+ /**
+ * Sets privilege which can delete this globalProperty
+ * @param deletePrivilege the deletePrivilege to set
+ *
+ * @since 2.7.0
+ */
+ public void setDeletePrivilege(Privilege deletePrivilege) {
+ this.deletePrivilege = deletePrivilege;
+ }
}
diff --git a/api/src/main/java/org/openmrs/Location.java b/api/src/main/java/org/openmrs/Location.java
index d465a6ccb729..329f063a8c75 100644
--- a/api/src/main/java/org/openmrs/Location.java
+++ b/api/src/main/java/org/openmrs/Location.java
@@ -9,15 +9,33 @@
*/
package org.openmrs;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.openmrs.annotation.Independent;
+import org.openmrs.api.APIException;
+import org.openmrs.api.context.Context;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
+import javax.persistence.Table;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import org.openmrs.annotation.Independent;
-import org.openmrs.api.APIException;
-import org.openmrs.api.context.Context;
-
/**
* A Location is a physical place, such as a hospital, a room, a clinic, or a district. Locations
* support a single hierarchy, such that each location may have one parent location. A
@@ -25,6 +43,10 @@
* and should be modeled using {@link LocationTag}s.
* Note: Prior to version 1.9 this class extended BaseMetadata
*/
+@Entity
+@Table(name = "location")
+@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+@AttributeOverride(name = "attributes", column = @Column(name = "location_id"))
public class Location extends BaseCustomizableMetadata implements java.io.Serializable, Attributable, Address {
public static final long serialVersionUID = 455634L;
@@ -32,59 +54,95 @@ public class Location extends BaseCustomizableMetadata implem
public static final int LOCATION_UNKNOWN = 1;
// Fields
-
+ @Id
+ @Column(name = "location_id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer locationId;
-
+
+ @ManyToOne
+ @JoinColumn(name = "location_type_concept_id")
private Concept type;
+ @Column(name = "address1")
private String address1;
+ @Column(name = "address2")
private String address2;
+ @Column(name = "city_village")
private String cityVillage;
+ @Column(name = "state_province")
private String stateProvince;
+ @Column(name = "country", length = 50)
private String country;
+ @Column(name = "postal_code", length = 50)
private String postalCode;
+ @Column(name = "latitude", length = 50)
private String latitude;
+ @Column(name = "longitude", length = 50)
private String longitude;
+ @Column(name = "county_district")
private String countyDistrict;
+ @Column(name = "address3")
private String address3;
+ @Column(name = "address4")
private String address4;
+ @Column(name = "address6")
private String address6;
+ @Column(name = "address5")
private String address5;
+ @Column(name = "address7")
private String address7;
+ @Column(name = "address8")
private String address8;
+ @Column(name = "address9")
private String address9;
+ @Column(name = "address10")
private String address10;
+ @Column(name = "address11")
private String address11;
+ @Column(name = "address12")
private String address12;
+ @Column(name = "address13")
private String address13;
+ @Column(name = "address14")
private String address14;
-
+
+ @Column(name = "address15")
private String address15;
+ @ManyToOne
+ @JoinColumn(name = "parent_location")
private Location parentLocation;
+ @OneToMany(mappedBy = "parentLocation", cascade = CascadeType.ALL, orphanRemoval = true)
+ @BatchSize(size = 100)
+ @OrderBy("name")
private Set childLocations;
+ @ManyToMany(fetch = FetchType.LAZY)
+ @JoinTable(
+ name = "location_tag_map",
+ joinColumns = @JoinColumn(name = "location_id"),
+ inverseJoinColumns = @JoinColumn(name = "location_tag_id"))
@Independent
private Set tags;
diff --git a/api/src/main/java/org/openmrs/LocationAttributeType.java b/api/src/main/java/org/openmrs/LocationAttributeType.java
index bd67e3581fe5..c9f1e67225bb 100644
--- a/api/src/main/java/org/openmrs/LocationAttributeType.java
+++ b/api/src/main/java/org/openmrs/LocationAttributeType.java
@@ -9,16 +9,35 @@
*/
package org.openmrs;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
import org.openmrs.attribute.AttributeType;
import org.openmrs.attribute.BaseAttributeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
/**
* A user-defined extension to the {@link Location} class.
* @see AttributeType
* @since 1.9
*/
+@Entity
+@Table(name = "location_attribute_type")
public class LocationAttributeType extends BaseAttributeType implements AttributeType {
-
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "location_attribute_type_id_seq")
+ @GenericGenerator(
+ name = "location_attribute_type_id_seq",
+ strategy = "native",
+ parameters = @Parameter(name = "sequence", value = "location_attribute_type_location_attribute_type_id_seq")
+ )
+ @Column(name = "location_attribute_type_id")
private Integer locationAttributeTypeId;
/**
diff --git a/api/src/main/java/org/openmrs/Order.java b/api/src/main/java/org/openmrs/Order.java
index bb0b542b1854..e9157dc3aeca 100644
--- a/api/src/main/java/org/openmrs/Order.java
+++ b/api/src/main/java/org/openmrs/Order.java
@@ -58,11 +58,14 @@ public enum Action {
/**
* Valid values for the status of an order that is received from a filler
* @since 2.2.0
+ * @since 2.6.1 added ON_HOLD & DECLINED
*/
public enum FulfillerStatus {
- RECEIVED,
+ RECEIVED,
IN_PROGRESS,
EXCEPTION,
+ ON_HOLD,
+ DECLINED,
COMPLETED
}
diff --git a/api/src/main/java/org/openmrs/PatientState.java b/api/src/main/java/org/openmrs/PatientState.java
index d12b4ae45aeb..9166d2b78175 100644
--- a/api/src/main/java/org/openmrs/PatientState.java
+++ b/api/src/main/java/org/openmrs/PatientState.java
@@ -11,11 +11,24 @@
import java.util.Date;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
import org.openmrs.util.OpenmrsUtil;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
/**
* PatientState
*/
+@Entity
+@Table(name = "patient_state")
public class PatientState extends BaseFormRecordableOpenmrsData implements java.io.Serializable, Comparable {
public static final long serialVersionUID = 0L;
@@ -23,17 +36,33 @@ public class PatientState extends BaseFormRecordableOpenmrsData implements java.
// ******************
// Properties
// ******************
-
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "patient_state_id_seq")
+ @GenericGenerator(
+ name = "patient_state_id_seq",
+ strategy = "native",
+ parameters = @Parameter(name = "sequence", value = "patient_state_patient_state_id_seq")
+ )
+ @Column(name = "patient_state_id")
private Integer patientStateId;
-
+
+ @ManyToOne
+ @JoinColumn(name = "patient_program_id", nullable = false)
private PatientProgram patientProgram;
-
+
+ @ManyToOne
+ @JoinColumn(name = "state", nullable = false)
private ProgramWorkflowState state;
-
+
+ @Column(name = "start_date", length = 19)
private Date startDate;
-
+
+ @Column(name = "end_date", length = 19)
private Date endDate;
-
+
+ @ManyToOne
+ @JoinColumn(name = "encounter_id")
private Encounter encounter;
// ******************
diff --git a/api/src/main/java/org/openmrs/PersonAddress.java b/api/src/main/java/org/openmrs/PersonAddress.java
index 6c78767d25c8..17c5da255c83 100644
--- a/api/src/main/java/org/openmrs/PersonAddress.java
+++ b/api/src/main/java/org/openmrs/PersonAddress.java
@@ -9,78 +9,117 @@
*/
package org.openmrs;
-import static org.apache.commons.lang3.StringUtils.defaultString;
-
-import java.util.Calendar;
-import java.util.Date;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.openmrs.util.OpenmrsUtil;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import java.util.Calendar;
+import java.util.Date;
+
+import static org.apache.commons.lang3.StringUtils.defaultString;
+
/**
* This class is the representation of a person's address. This class is many-to-one to the Person
* class, so a Person/Patient/User can have zero to n addresses
*/
+@Entity
+@Table(name = "person_address")
public class PersonAddress extends BaseChangeableOpenmrsData implements java.io.Serializable, Cloneable, Comparable, Address {
public static final long serialVersionUID = 343333L;
// Fields
-
+ @Id
+ @Column(name = "person_address_id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer personAddressId;
-
+
+ @ManyToOne
+ @JoinColumn(name = "person_id")
private Person person;
+ @Column(name = "preferred", length = 1, nullable = false)
private Boolean preferred = false;
-
+
+ @Column(name = "address1")
private String address1;
-
+
+ @Column(name = "address2")
private String address2;
-
+
+ @Column(name = "address3")
private String address3;
-
+
+ @Column(name = "address4")
private String address4;
-
+
+ @Column(name = "address5")
private String address5;
-
+
+ @Column(name = "address6")
private String address6;
-
+
+ @Column(name = "address7")
private String address7;
-
+
+ @Column(name = "address8")
private String address8;
-
+
+ @Column(name = "address9")
private String address9;
-
+
+ @Column(name = "address10")
private String address10;
-
+
+ @Column(name = "address11")
private String address11;
-
+
+ @Column(name = "address12")
private String address12;
-
+
+ @Column(name = "address13")
private String address13;
-
+
+ @Column(name = "address14")
private String address14;
-
+
+ @Column(name = "address15")
private String address15;
+ @Column(name = "city_village")
private String cityVillage;
+ @Column(name = "county_district")
private String countyDistrict;
+ @Column(name = "state_province")
private String stateProvince;
+ @Column(name = "country")
private String country;
+ @Column(name = "postal_code", length = 50)
private String postalCode;
+ @Column(name = "latitude", length = 50)
private String latitude;
-
+
+ @Column(name = "longitude", length = 50)
private String longitude;
+ @Column(name = "start_date", length = 19)
private Date startDate;
+ @Column(name = "end_date", length = 19)
private Date endDate;
// Constructors
diff --git a/api/src/main/java/org/openmrs/PersonAttributeType.java b/api/src/main/java/org/openmrs/PersonAttributeType.java
index d2d490e45a97..751dfe991c26 100644
--- a/api/src/main/java/org/openmrs/PersonAttributeType.java
+++ b/api/src/main/java/org/openmrs/PersonAttributeType.java
@@ -9,31 +9,50 @@
*/
package org.openmrs;
-import java.io.Serializable;
-import java.util.Comparator;
-
import org.codehaus.jackson.annotate.JsonIgnore;
import org.hibernate.search.annotations.Field;
import org.openmrs.util.OpenmrsUtil;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.Comparator;
+
/**
* PersonAttributeType
*/
+@Entity
+@Table(name = "person_attribute_type")
public class PersonAttributeType extends BaseChangeableOpenmrsMetadata implements java.io.Serializable, Comparable {
public static final long serialVersionUID = 2112313431211L;
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "person_attribute_type_id")
private Integer personAttributeTypeId;
+ @Column(name = "format", length = 50)
private String format;
+ @Column(name = "foreign_key")
private Integer foreignKey;
+ @Column(name = "sort_weight", nullable = false)
private Double sortWeight;
@Field
+ @Column(name = "searchable", nullable = false)
private Boolean searchable = false;
+ @ManyToOne
+ @JoinColumn(name = "edit_privilege")
private Privilege editPrivilege;
/** default constructor */
diff --git a/api/src/main/java/org/openmrs/Relationship.java b/api/src/main/java/org/openmrs/Relationship.java
index cd6e2f7355fc..59c840693ec1 100644
--- a/api/src/main/java/org/openmrs/Relationship.java
+++ b/api/src/main/java/org/openmrs/Relationship.java
@@ -9,27 +9,53 @@
*/
package org.openmrs;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
import java.util.Date;
/**
* Relationship
*/
+@Entity
+@Table(name = "relationship")
public class Relationship extends BaseChangeableOpenmrsData {
public static final long serialVersionUID = 323423L;
// Fields
-
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "relationship_id_seq")
+ @GenericGenerator(
+ name = "relationship_id_seq",
+ strategy = "native",
+ parameters = @Parameter(name = "sequence", value = "relationship_relationship_id_seq")
+ )
+ @Column(name = "relationship_id")
private Integer relationshipId;
-
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "person_a", nullable = false)
private Person personA;
-
+
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "relationship", nullable = false)
private RelationshipType relationshipType;
-
+
+ @ManyToOne(optional = false)
+ @JoinColumn(name = "person_b", nullable = false)
private Person personB;
-
+
+ @Column(name = "start_date",length = 19)
private Date startDate;
-
+ @Column(name = "end_date", length = 19)
private Date endDate;
// Constructors
diff --git a/api/src/main/java/org/openmrs/User.java b/api/src/main/java/org/openmrs/User.java
index dcd69ac55d45..77c51355c50e 100644
--- a/api/src/main/java/org/openmrs/User.java
+++ b/api/src/main/java/org/openmrs/User.java
@@ -9,6 +9,20 @@
*/
package org.openmrs;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.Table;
+import javax.persistence.Transient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -21,6 +35,14 @@
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+import org.hibernate.annotations.Parameter;
import org.openmrs.api.context.Context;
import org.openmrs.util.LocaleUtility;
import org.openmrs.util.OpenmrsConstants;
@@ -36,6 +58,10 @@
* key-value pairs for either quick info or display specific info that needs to be persisted (like
* locale preferences, search options, etc)
*/
+
+@Entity
+@Table(name = "users")
+@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User extends BaseOpenmrsObject implements java.io.Serializable, Attributable, Auditable, Retireable {
public static final long serialVersionUID = 2L ;
@@ -43,38 +69,76 @@ public class User extends BaseOpenmrsObject implements java.io.Serializable, Att
private static final Logger log = LoggerFactory.getLogger(User.class);
// Fields
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_user_id_seq")
+ @GenericGenerator(
+ name = "users_user_id_seq",
+ strategy = "native",
+ parameters = @Parameter(name = "sequence", value = "users_user_id_seq")
+ )
+ @Column(name = "user_id")
private Integer userId;
-
+
+ @ManyToOne
+ @JoinColumn(name = "person_id", nullable = false)
+ @LazyCollection(LazyCollectionOption.FALSE)
+ @Cascade(CascadeType.SAVE_UPDATE)
private Person person;
-
+
+ @Column(name = "system_id", nullable = false, length = 50)
private String systemId;
-
+
+ @Column(name = "username", length = 50)
private String username;
-
+
+ @Column(name = "email", length = 255, unique = true)
private String email;
-
+
+ @ManyToMany
+ @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role"))
+ @LazyCollection(LazyCollectionOption.FALSE)
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.EVICT })
private Set roles;
-
+
+ @ElementCollection
+ @CollectionTable(name = "user_property", joinColumns = @JoinColumn(name = "user_id", nullable = false))
+ @MapKeyColumn(name = "property", length = 255)
+ @Column(name = "property_value", length = Integer.MAX_VALUE)
+ @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.EVICT })
private Map userProperties;
-
+
+ @Transient
private List proficientLocales = null;
-
+
+ @Transient
private String parsedProficientLocalesProperty = "";
-
+
+ @ManyToOne
+ @JoinColumn(name = "creator", nullable = false)
private User creator;
-
+
+ @Column(name = "date_created", nullable = false, length = 19)
private Date dateCreated;
-
+
+ @ManyToOne
+ @JoinColumn(name = "changed_by")
private User changedBy;
-
+
+ @Column(name = "date_changed", length = 19)
private Date dateChanged;
-
+
+ @Column(name = "retired", nullable = false, length = 1)
private boolean retired;
-
+
+ @ManyToOne
+ @JoinColumn(name = "retired_by")
private User retiredBy;
-
+
+ @Column(name = "date_retired", length = 19)
private Date dateRetired;
-
+
+ @Column(name = "retire_reason", length = 255)
private String retireReason;
// Constructors
diff --git a/api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java b/api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java
index c6b256df2f1b..348cad8fae1b 100644
--- a/api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java
+++ b/api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java
@@ -125,9 +125,8 @@ public void before(Method method, Object[] args, Object target) throws Throwable
other = (String) args[1];
}
- ValidateUtil.validate(mainArgument);
-
recursivelyHandle(SaveHandler.class, (OpenmrsObject) mainArgument, other);
+ ValidateUtil.validate(mainArgument);
}
// if the first argument is a list of openmrs objects, handle them all now
else if (Reflect.isCollection(mainArgument) && isOpenmrsObjectCollection(mainArgument)) {
@@ -145,9 +144,8 @@ else if (Reflect.isCollection(mainArgument) && isOpenmrsObjectCollection(mainArg
Collection openmrsObjects = (Collection) mainArgument;
for (OpenmrsObject object : openmrsObjects) {
- ValidateUtil.validate(object);
-
recursivelyHandle(SaveHandler.class, object, other);
+ ValidateUtil.validate(object);
}
}
diff --git a/api/src/main/java/org/openmrs/api/OrderService.java b/api/src/main/java/org/openmrs/api/OrderService.java
index 80173581afaf..fb8ef6e31274 100644
--- a/api/src/main/java/org/openmrs/api/OrderService.java
+++ b/api/src/main/java/org/openmrs/api/OrderService.java
@@ -834,6 +834,19 @@ public Order discontinueOrder(Order orderToDiscontinue, String reasonNonCoded, D
@Authorized({ PrivilegeConstants.EDIT_ORDERS, PrivilegeConstants.ADD_ORDERS })
public OrderGroup saveOrderGroup(OrderGroup orderGroup) throws APIException;
+ /**
+ * Saves an order group with a specific order context
+ *
+ * @param orderGroup the order group to be saved
+ * @param orderContext the order context data transfer object containing care setting and
+ * the order type to save with the order group
+ * @return the order group that was saved with the specified order context data
+ * @since 2.7.0
+ * @throws APIException
+ */
+ @Authorized({ PrivilegeConstants.EDIT_ORDERS, PrivilegeConstants.ADD_ORDERS })
+ public OrderGroup saveOrderGroup(OrderGroup orderGroup, OrderContext orderContext) throws APIException;
+
/**
* Fetches all order groups for the specified patient
*
diff --git a/api/src/main/java/org/openmrs/api/ProviderService.java b/api/src/main/java/org/openmrs/api/ProviderService.java
index 7015c048f582..fe041a074ff8 100644
--- a/api/src/main/java/org/openmrs/api/ProviderService.java
+++ b/api/src/main/java/org/openmrs/api/ProviderService.java
@@ -36,14 +36,13 @@ public interface ProviderService extends OpenmrsService {
* @return a list of provider objects.
* Should get all providers
*/
-
@Authorized( { PrivilegeConstants.GET_PROVIDERS })
public List getAllProviders();
/**
- * Gets all Provider
+ * Gets all providers
*
- * @param includeRetired - whether or not to include retired Provider
+ * @param includeRetired - if true, retired providers are also included
* Should get all providers that are unretired
*/
@Authorized( { PrivilegeConstants.GET_PROVIDERS })
@@ -225,14 +224,25 @@ public List getProviders(String query, Integer start, Integer length,
public ProviderAttributeType getProviderAttributeType(Integer providerAttributeTypeId);
/**
- * Get a provider attribute type by it's uuid
+ * Get a provider attribute type by its uuid
*
* @param uuid the uuid of the provider attribute type
* @return the provider attribute type for the given uuid
- * Should get the provider attribute type by it's uuid
+ * Should get the provider attribute type by its uuid
*/
public ProviderAttributeType getProviderAttributeTypeByUuid(String uuid);
+ /**
+ * Get a provider attribute type by its name
+ *
+ * @param name the name of the provider attribute type
+ * @return the provider attribute type for the given name
+ * Should get the provider attribute type by its name
+ * @since 2.7.0, 2.6.3
+ */
+ @Authorized({PrivilegeConstants.GET_PROVIDER_ATTRIBUTE_TYPES})
+ public ProviderAttributeType getProviderAttributeTypeByName(String name);
+
/**
* Get a provider attribute by it's providerAttributeID
*
@@ -243,11 +253,11 @@ public List getProviders(String query, Integer start, Integer length,
public ProviderAttribute getProviderAttribute(Integer providerAttributeID);
/**
- * Get a provider attribute by it's providerAttributeUuid
+ * Get a provider attribute by its providerAttributeUuid
*
* @param uuid the provider attribute uuid of the providerAttribute
* @return the provider attribute for the given providerAttributeUuid
- * Should get the provider attribute by it's providerAttributeUuid
+ * Should get the provider attribute by its providerAttributeUuid
*/
public ProviderAttribute getProviderAttributeByUuid(String uuid);
diff --git a/api/src/main/java/org/openmrs/api/UserService.java b/api/src/main/java/org/openmrs/api/UserService.java
index 5dedac6aae09..932f261206b7 100644
--- a/api/src/main/java/org/openmrs/api/UserService.java
+++ b/api/src/main/java/org/openmrs/api/UserService.java
@@ -35,6 +35,8 @@
* @see org.openmrs.api.context.Context
*/
public interface UserService extends OpenmrsService {
+
+ public static final String ADMIN_PASSWORD_LOCKED_PROPERTY = "admin_password_locked";
/**
* Create user with given password.
@@ -318,16 +320,17 @@ public interface UserService extends OpenmrsService {
/**
* Changes the current user's password.
*
- * @param pw current password
- * @param pw2 new password
+ * @param oldPassword current password
+ * @param newPassword new password
* @throws APIException
* Should match on correctly hashed sha1 stored password
* Should match on incorrectly hashed sha1 stored password
* Should match on sha512 hashed password
* Should be able to update password multiple times
+ * Should respect locking via runtime properties
*/
@Logging(ignoredArgumentIndexes = { 0, 1 })
- public void changePassword(String pw, String pw2) throws APIException;
+ public void changePassword(String oldPassword, String newPassword) throws APIException;
/**
* Changes password of {@link User} passed in
diff --git a/api/src/main/java/org/openmrs/api/ValidationException.java b/api/src/main/java/org/openmrs/api/ValidationException.java
index 296efa868067..2f85997f899f 100644
--- a/api/src/main/java/org/openmrs/api/ValidationException.java
+++ b/api/src/main/java/org/openmrs/api/ValidationException.java
@@ -92,7 +92,7 @@ public Errors getErrors() {
return errors;
}
- /**
+ /**message.prop
* @since 1.11
*/
public void setErrors(Errors errors) {
diff --git a/api/src/main/java/org/openmrs/api/context/Context.java b/api/src/main/java/org/openmrs/api/context/Context.java
index df667e819fbe..154bbaa39813 100644
--- a/api/src/main/java/org/openmrs/api/context/Context.java
+++ b/api/src/main/java/org/openmrs/api/context/Context.java
@@ -374,19 +374,7 @@ public static void refreshAuthenticatedUser() {
public static void becomeUser(String systemId) throws ContextAuthenticationException {
log.info("systemId: {}", systemId);
- User user = getUserContext().becomeUser(systemId);
-
- // if assuming identity procedure finished successfully, we should change context locale parameter
- Locale locale = null;
- if (user.getUserProperties().containsKey(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE)) {
- String localeString = user.getUserProperty(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE);
- locale = LocaleUtility.fromSpecification(localeString);
- }
- // when locale parameter is not valid or does not exist
- if (locale == null) {
- locale = LocaleUtility.getDefaultLocale();
- }
- Context.setLocale(locale);
+ getUserContext().becomeUser(systemId);
}
/**
@@ -699,7 +687,12 @@ public static boolean isAuthenticated() {
if (Daemon.isDaemonThread()) {
return true;
} else {
- return getAuthenticatedUser() != null;
+ try {
+ return getAuthenticatedUser() != null;
+ } catch (APIException e) {
+ log.info("Could not get authenticated user inside called to isAuthenticated(), assuming no user context has been defined", e);
+ return false;
+ }
}
}
diff --git a/api/src/main/java/org/openmrs/api/context/Daemon.java b/api/src/main/java/org/openmrs/api/context/Daemon.java
index d212cfc866ea..2fe6c82e2d62 100644
--- a/api/src/main/java/org/openmrs/api/context/Daemon.java
+++ b/api/src/main/java/org/openmrs/api/context/Daemon.java
@@ -89,7 +89,11 @@ public void run() {
exceptionThrown = e;
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
};
@@ -151,7 +155,7 @@ public void run() {
if (!CollectionUtils.isEmpty(roleNames)) {
List roles = roleNames.stream().map(roleName -> Context.getUserService().getRole(roleName)).collect(Collectors.toList());
- roles.forEach(role -> user.addRole(role));
+ roles.forEach(user::addRole);
}
returnedObject = Context.getUserService().createUser(user, password);
@@ -160,7 +164,11 @@ public void run() {
exceptionThrown = e;
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
};
@@ -214,7 +222,11 @@ public void run() {
exceptionThrown = e;
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
@@ -266,7 +278,11 @@ public void run() {
runnable.run();
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
};
@@ -311,7 +327,11 @@ public void run() {
exceptionThrown = e;
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
};
@@ -362,7 +382,11 @@ public void run() {
runnable.run();
}
finally {
- Context.closeSession();
+ try {
+ Context.closeSession();
+ } finally {
+ isDaemonThread.remove();
+ }
}
}
};
diff --git a/api/src/main/java/org/openmrs/api/context/ServiceContext.java b/api/src/main/java/org/openmrs/api/context/ServiceContext.java
index 9533f26ba423..b84f835ae9cb 100644
--- a/api/src/main/java/org/openmrs/api/context/ServiceContext.java
+++ b/api/src/main/java/org/openmrs/api/context/ServiceContext.java
@@ -759,7 +759,9 @@ public void setModuleService(List