Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,77 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version> <!-- Use the latest stable version -->
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<!-- Prepare the JaCoCo agent to track coverage during tests -->
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- Merge e2e & u-t execution data files after tests are run -->
<execution>
<id>merge-ut-e2e</id>
<phase>test</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<includes>
<include>jacoco.exec</include>
<include>keploy-e2e.exec</include>
</includes>
</fileSet>
</fileSets>
<!-- Output of merged data -->
<destFile>${project.build.directory}/ut-e2e-merged.exec</destFile>
</configuration>
</execution>
<!-- Generate report based on the different execution data -->
<!-- Generate unit test report-->
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
<!-- Use merged data file -->
<outputDirectory>${project.reporting.outputDirectory}/ut</outputDirectory>
</configuration>
</execution>
<!-- Generate combined (e2e+ut) report test report-->
<execution>
<id>combined-ut-e2e</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/ut-e2e-merged.exec</dataFile>
<!-- Use merged data file -->
<outputDirectory>${project.reporting.outputDirectory}/e2e-ut-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public class CustomAuthenticationManager implements AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final UserDetails userDetail = customUserDetailsService.loadUserByUsername(authentication.getName());
if (!passwordEncoder.matches(authentication.getCredentials().toString(), userDetail.getPassword())) {
throw new BadCredentialsException("Wrong password");
}
// if (!passwordEncoder.matches(authentication.getCredentials().toString(), userDetail.getPassword())) {
// throw new BadCredentialsException("Wrong password");
// }
return new UsernamePasswordAuthenticationToken(userDetail.getUsername(), userDetail.getPassword(), userDetail.getAuthorities());
}

Expand Down
72 changes: 71 additions & 1 deletion src/main/java/org/isf/ward/rest/WardController.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper; // For JSON parsing

import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down Expand Up @@ -72,8 +79,71 @@ public WardController(WardBrowserManager wardManager, WardMapper wardMapper) {
*/
@GetMapping(value = "/wards")
public List<WardDTO> getWards() throws OHServiceException {
LOGGER.info("Get wards");
LOGGER.info("Fetching wards from multiple Go microservices...");

// Use Java's built-in HttpClient
HttpClient httpClient = HttpClient.newHttpClient();
ObjectMapper objectMapper = new ObjectMapper(); // To convert JSON response into WardDTO

List<String> endpoints = List.of(
"http://localhost:8081/data",
"http://localhost:8082/data",
"http://localhost:8083/data",
"http://localhost:8084/data"
);

for (String endpoint : endpoints) {
System.out.println("Fetching data from " + endpoint);
try {
// Create HTTP request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.GET()
.build();

// Send request and receive response
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Received response from " + endpoint);
if (response.statusCode() == 200) {
System.out.println("Received data from " + endpoint);
// Convert JSON response to WardDTO
WardDTO externalData = objectMapper.readValue(response.body(), WardDTO.class);
System.out.println("Received Ward Data: Code=" + externalData.getCode() + ", Description=" + externalData.getDescription());
// Log received data for debugging
LOGGER.info("Received Ward Data: Code={}, Description={}",
externalData.getCode(), externalData.getDescription());

// Convert external data to a WardDTO
WardDTO wardDTO = new WardDTO();
wardDTO.setCode(externalData.getCode() != null ? externalData.getCode() : "UNKNOWN");
wardDTO.setDescription(externalData.getDescription() != null ? externalData.getDescription() : "No Description");
wardDTO.setTelephone(externalData.getTelephone() != null ? externalData.getTelephone() : "N/A");
wardDTO.setFax(externalData.getFax() != null ? externalData.getFax() : "N/A");
wardDTO.setEmail(externalData.getEmail() != null ? externalData.getEmail() : "N/A");
wardDTO.setBeds(externalData.getBeds() != null ? externalData.getBeds() : 0);
wardDTO.setNurs(externalData.getNurs() != null ? externalData.getNurs() : 0);
wardDTO.setDocs(externalData.getDocs() != null ? externalData.getDocs() : 0);
wardDTO.setPharmacy(externalData.isPharmacy());
wardDTO.setMale(externalData.isMale());
wardDTO.setFemale(externalData.isFemale());
wardDTO.setOpd(externalData.isOpd());
wardDTO.setVisitDuration(externalData.getVisitDuration() != null ? externalData.getVisitDuration() : 0);
wardDTO.setLock(externalData.getLock() != null ? externalData.getLock() : 0);

// Create the Ward in the database
Ward createdWard = wardManager.newWard(mapper.map2Model(wardDTO));
if (createdWard == null) {
throw new OHAPIException(new OHExceptionMessage("Failed to create Ward from external data: " + externalData));
}
} else {
LOGGER.warn("Failed to fetch Ward data from {} (Status Code: {})", endpoint, response.statusCode());
}
} catch (Exception e) {
LOGGER.error("Error fetching data from {}: {}", endpoint, e.getMessage());
}
}

// Return all stored wards
return mapper.map2DTOList(wardManager.getWards());
}

Expand Down
48 changes: 48 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# logging.file.name=oh-rest-api.log
# logging.level.org.springframework=DEBUG
# logging.level.org.springframework.web=DEBUG
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
server.servlet.context-path=/
server.address=localhost
server.port=8080
server.servlet.session.cookie.http-only=true
#server.servlet.session.cookie.secure=true # only over HTTPS
spring.pid.fail-on-write-error=true
spring.pid.file=OH_API_PID
spring.mustache.check-template-location=false
spring.jpa.open-in-view=false

### In production change to http://<domain>
cors.allowed.origins=http://localhost:3000

### Swagger-UI (info)
api.host=API_HOST:API_PORT
api.protocol=http
springdoc.swagger-ui.tagsSorter=alpha
springdoc.swagger-ui.doc-expansion=none

### Without the following overriding property the following error is generated:
### Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'org.springframework.transaction.config.internalTransactionAdvisor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration; factoryMethodName=transactionAdvisor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]] for bean 'org.springframework.transaction.config.internalTransactionAdvisor': There is already [Root bean: class [org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
### Seems like a Hibernate/SpringBoot conflict: see https://stackoverflow.com/questions/55545627/springboot-conflicts-with-hibernate
spring.main.allow-bean-definition-overriding=true

### Without the following SpringBoot 2.6.x has a conflict with a bug in SpringFox
### See: https://stackoverflow.com/questions/70036953/springboot-2-6-0-spring-fox-3-failed-to-start-bean-documentationpluginsboot/70037507#70037507
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

### Security token secret (JWT)
jwt.token.secret=0bc21321f41b8748d2a5022fa1e0382469cc749a5f1eae752530b4f001d41578

### JWT token validity, 30 minutes (1,800 seconds)
jwt.token.validityInSeconds=1800000000

### JWT token validity for remember me, 3 days (259,200 seconds)
jwt.token.validityInSecondsForRememberMe=259200

# Hibernate properties
# needed to start application even without DB connection
spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect
spring.jpa.hibernate.ddl-auto=none
3 changes: 3 additions & 0 deletions src/main/resources/database.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
jdbc.url=jdbc:mysql://localhost:3306/oh?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
jdbc.username=isf
jdbc.password=isf123
6 changes: 6 additions & 0 deletions src/main/resources/dicom.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#dicom.manager.impl=org.isf.dicom.manager.FileSystemDicomManager # filesystem storage
#dicom.manager.impl=org.isf.dicom.manager.SqlDicomManager # database storage
#dicom.max.size=1024B, 2048B, 1M, 16M, 256M, 512M, 1024M, 1G # image size examples
dicom.manager.impl=org.isf.dicom.manager.FileSystemDicomManager
dicom.storage.filesystem=./data/dicom_storage
dicom.max.size=4M
37 changes: 37 additions & 0 deletions src/main/resources/examination.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This file contains PatientExamination module settings
LIST_SIZE = 10
HEIGHT_MIN = 0
HEIGHT_MAX = 250
HEIGHT_INIT = 0
#HEIGHT_STEP = 1
#WEIGHT_UNIT = Kg
WEIGHT_MIN = 0
WEIGHT_MAX = 200
WEIGHT_INIT = 0
WEIGHT_STEP = 0.1
#AP_UNIT = mmHg
AP_MIN_INIT = 80
AP_MAX_INIT = 120
#HR_UNIT = bpm
HR_MIN = 0
HR_MAX = 240
HR_INIT = 60
#TEMP_UNIT = °C
TEMP_INIT = 36
TEMP_MIN = 30
TEMP_MAX = 50
TEMP_STEP = 0.1
#SAT_UNIT = %
SAT_INIT = 98
SAT_MIN = 50
#SAT_MAX = 100
SAT_STEP = 0.1
HGT_MIN = 30
HGT_MAX = 600
HGT_INIT = 80
DIURESIS_MIN = 0
DIURESIS_MAX = 2500
DIURESIS_INIT = 100
RR_INIT = 20
RR_MIN = 0
RR_MAX = 100
58 changes: 58 additions & 0 deletions src/main/resources/log4j2-spring.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

status = INFO
rootLogger.level = INFO
rootLogger.appenderRef.console.ref = STDOUT
rootLogger.appenderRef.rolling.ref = RollingFile

# Direct log messages to STDOUT
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{dd/MMM/yyyy HH:mm:ss}] [%X{OHUserGroup}:%X{OHUser}] %-p - %m%n

# File Appender (with classes), daily rotation
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName= LOG_DEST/openhospital.log
appender.rolling.filePattern= LOG_DEST/openhospital.log.%d{yyyy-MM-dd}
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{dd/MMM/yyyy HH:mm:ss}] [%X{OHUserGroup}:%X{OHUser}] %-p - %m (%l)%n
appender.rolling.policies.type = Policies
# To change log file every day
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true


# DB Appender (table columns)
appender.jdbc.type = JDBC
appender.jdbc.name = jdbc
appender.jdbc.connectionSource.driverClassName = org.mariadb.jdbc.Driver
appender.jdbc.connectionSource.type = DriverManager
appender.jdbc.connectionSource.connectionString = dbc:mariadb://DBSERVER:DBPORT/DBNAME?autoReconnect=true
appender.jdbc.connectionSource.userName = DBUSER
appender.jdbc.connectionSource.password = DBPASS
appender.jdbc.tableName = logs
appender.jdbc.ignoreExceptions = false
appender.jdbc.columnConfigs[0].type = COLUMN
appender.jdbc.columnConfigs[0].name = LOG_TIME
appender.jdbc.columnConfigs[0].pattern = %d
appender.jdbc.columnConfigs[0].isUnicode = false
appender.jdbc.columnConfigs[1].type = COLUMN
appender.jdbc.columnConfigs[1].name = LOG_LEVEL
appender.jdbc.columnConfigs[1].pattern = %5p
appender.jdbc.columnConfigs[1].isUnicode = false
appender.jdbc.columnConfigs[2].type = COLUMN
appender.jdbc.columnConfigs[2].name = MESSAGE
appender.jdbc.columnConfigs[2].pattern = %mm%ex%n
appender.jdbc.columnConfigs[2].isUnicode = false


# Assigning appenders to Hibernate packages (DB loggers)
# - hibernate.SQL to DEBUG for SQL queries to be logged
# - hibernate.type to TRACE for queries parameters to be logged with "binding parameter [?]"
##logger.hibernate-SQL.name=org.hibernate.SQL
##logger.hibernate-SQL.level=DEBUG
##
##logger.hibernate-type.name=org.hibernate.orm.jdbc.bind
##logger.hibernate-type.level=TRACE
Loading