Skip to content

Commit

Permalink
[GLT-4259] updated to Spring 6 (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
djcooke authored Oct 24, 2024
1 parent fab2359 commit 826b695
Show file tree
Hide file tree
Showing 24 changed files with 396 additions and 403 deletions.
2 changes: 1 addition & 1 deletion pinery-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<artifactId>prometheus-metrics-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
import ca.on.oicr.pinery.api.SampleProject;
import ca.on.oicr.pinery.api.Type;
import ca.on.oicr.pinery.api.User;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;
import io.prometheus.metrics.core.datapoints.Timer;
import io.prometheus.metrics.core.metrics.Gauge;
import io.prometheus.metrics.core.metrics.Histogram;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
Expand All @@ -38,16 +41,16 @@ public class Cache implements DataProvider {

private static final Logger log = LoggerFactory.getLogger(Cache.class);

private static final Histogram cacheUpdateTime = Histogram.build()
private static final Histogram cacheUpdateTime = Histogram.builder()
.name("pinery_cache_update_time")
.help("Time to update the cache (in seconds)")
.buckets(60, 180, 300, 600, 900, 1200, 1800, 3600)
.classicUpperBounds(60, 180, 300, 600, 900, 1200, 1800, 3600)
.register();
private static final Gauge cacheUpdateFailures = Gauge.build()
private static final Gauge cacheUpdateFailures = Gauge.builder()
.name("pinery_cache_update_failures")
.help("Number of consecutive cache update failures")
.register();
private static final Gauge cacheLastUpdated = Gauge.build()
private static final Gauge cacheLastUpdated = Gauge.builder()
.name("pinery_cache_last_updated")
.help("Timestamp of the last cache update (completion)")
.register();
Expand Down Expand Up @@ -115,7 +118,7 @@ public void update() {
}

if (doUpdate) {
Histogram.Timer cacheUpdateTimer = cacheUpdateTime.startTimer();
Timer cacheUpdateTimer = cacheUpdateTime.startTimer();
try {
log.debug("Attempting update");
List<Requisition> newRequisitions = lims.getRequisitions();
Expand Down Expand Up @@ -157,7 +160,7 @@ public void update() {
cacheComplete = true;
lastUpdated = Instant.now();
cacheUpdateFailures.set(0);
cacheLastUpdated.setToCurrentTime();
cacheLastUpdated.set(System.currentTimeMillis());
log.debug("Update successful");
}
} catch (RuntimeException e) {
Expand Down
9 changes: 4 additions & 5 deletions pinery-ws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ implementation such as the one by [MISO-LIMS](https://github.com/miso-lims/miso-

## Minimum Requirements

* Maven 3
* JDK 11
- Maven 3
- JDK 17
- Tomcat 10

## Deploying to Tomcat

### Tomcat Configuration

Tomcat 9 is the recommended servlet container for Pinery.

You may wish to set the timezone explicitly, as not all source LIMS provide a time zone. It may also
be necessary to increase the JVM memory. You can alter these by configuring Tomcat's JAVA_OPTS. e.g.

Expand All @@ -33,6 +32,6 @@ JAVA_OPTS="-Duser.timezone=GMT -Djava.awt.headless=true -Xmx6144m -XX:MaxPermSiz
4. Copy the built `.war` file from the Pinery implemention to `$CATALINA_HOME/webapps/`, naming it
to match your `context.xml` above. If Tomcat is configured to autodeploy, the webapp will be
(re)deployed automatically; otherwise, deploy the webapp manually
* **WARNING**: In some cases with autodeploy enabled, Tomcat may delete the context XML during redeployment.
- **WARNING**: In some cases with autodeploy enabled, Tomcat may delete the context XML during redeployment.
You can prevent this by stopping tomcat before copying the WAR into the webapps directory, or by making the
file immutable via `chattr +i <filename>`
30 changes: 21 additions & 9 deletions pinery-ws/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,21 @@
<artifactId>pinery-ws-dto</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- Needed by SpringDoc -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand Down Expand Up @@ -97,15 +98,15 @@

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<artifactId>prometheus-metrics-core</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_hotspot</artifactId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_servlet</artifactId>
<artifactId>prometheus-metrics-exporter-servlet-jakarta</artifactId>
</dependency>
<dependency>
<groupId>io.prometheus.jmx</groupId>
Expand Down Expand Up @@ -134,5 +135,16 @@
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- generate metadata for reflection on method parameters. Required to so that
PathVariable/RequestParam annotations don't require specification of names -->
<parameters>true</parameters>
</configuration>
</plugin>
</plugins>
</build>
</project>
22 changes: 12 additions & 10 deletions pinery-ws/src/main/java/ca/on/oicr/pinery/ws/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@

import ca.on.oicr.pinery.service.impl.Cache;
import ca.on.oicr.pinery.ws.component.RestException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(tags = {"Admin"})
@Tag(name = "Admin")
public class AdminController {

@Autowired private Cache cache;
@Autowired
private Cache cache;

@PostMapping("/updatecache")
@ApiOperation(value = "Forces a cache refresh")
@Operation(summary = "Forces a cache refresh")
@ApiResponses({
@ApiResponse(code = 204, message = "Success"),
@ApiResponse(code = 400, message = "Caching not enabled"),
@ApiResponse(code = 500, message = "Error updating cache")
@ApiResponse(responseCode = "204", description = "Success"),
@ApiResponse(responseCode = "400", description = "Caching not enabled"),
@ApiResponse(responseCode = "500", description = "Error updating cache")
})
@ResponseStatus(HttpStatus.NO_CONTENT)
public void updateCache() {
Expand Down
28 changes: 17 additions & 11 deletions pinery-ws/src/main/java/ca/on/oicr/pinery/ws/AssayResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import ca.on.oicr.pinery.ws.component.RestException;
import ca.on.oicr.ws.dto.AssayDto;
import ca.on.oicr.ws.dto.Dtos;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -22,23 +24,27 @@

@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = {"Assays"})
@Tag(name = "Assays")
public class AssayResource {

@Autowired private AssayService assayService;
@Autowired
private AssayService assayService;

@GetMapping("/assays")
@ApiOperation(value = "List all assays", response = AssayDto.class, responseContainer = "List")
@Operation(summary = "List all assays")
public List<AssayDto> getAssays() {
List<Assay> assays = assayService.getAssays();
return assays.stream().map(Dtos::asDto).collect(Collectors.toList());
}

@GetMapping("/assay/{id}")
@ApiOperation(value = "Find assay by ID", response = AssayDto.class)
@ApiResponses({@ApiResponse(code = 404, message = "No assay found")})
@Operation(summary = "Find assay by ID")
@ApiResponses({
@ApiResponse(useReturnTypeSchema = true, responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "No assay found", content = @Content)
})
public AssayDto getAssay(
@ApiParam(value = "ID of assay to fetch") @PathVariable("id") Integer id) {
@Parameter(description = "ID of assay to fetch") @PathVariable("id") Integer id) {
Assay assay = assayService.getAssay(id);
if (assay == null) {
throw new RestException(HttpStatus.NOT_FOUND, String.format("No assay with ID: %d", id));
Expand Down
15 changes: 7 additions & 8 deletions pinery-ws/src/main/java/ca/on/oicr/pinery/ws/BoxResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import ca.on.oicr.pinery.service.BoxService;
import ca.on.oicr.ws.dto.BoxDto;
import ca.on.oicr.ws.dto.Dtos;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
Expand All @@ -15,16 +16,14 @@

@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = {"Boxes"})
@Tag(name = "Boxes")
public class BoxResource {

@Autowired private BoxService boxService;
@Autowired
private BoxService boxService;

@GetMapping("/boxes")
@ApiOperation(
value = "List all boxes",
response = ca.on.oicr.ws.dto.BoxDto.class,
responseContainer = "List")
@Operation(summary = "List all boxes")
public List<BoxDto> getBoxes() {
List<Box> boxes = boxService.getBoxes();
return Dtos.asDtoList(boxes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
import ca.on.oicr.ws.dto.Dtos;
import ca.on.oicr.ws.dto.InstrumentDto;
import ca.on.oicr.ws.dto.InstrumentModelDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.net.URI;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -28,16 +30,14 @@

@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = {"Instruments"})
@Tag(name = "Instruments")
public class InstrumentResource {

@Autowired private InstrumentService instrumentService;
@Autowired
private InstrumentService instrumentService;

@GetMapping("/instrumentmodels")
@ApiOperation(
value = "List all instrument models",
response = ca.on.oicr.ws.dto.InstrumentModelDto.class,
responseContainer = "List")
@Operation(summary = "List all instrument models")
public List<InstrumentModelDto> getInstrumentModels(UriComponentsBuilder uriBuilder) {
List<InstrumentModel> instrumentModels = instrumentService.getInstrumentModels();
List<InstrumentModelDto> result = Lists.newArrayList();
Expand All @@ -50,13 +50,14 @@ public List<InstrumentModelDto> getInstrumentModels(UriComponentsBuilder uriBuil
}

@GetMapping("/instrumentmodel/{id}")
@ApiOperation(
value = "Find instrument model by ID",
response = ca.on.oicr.ws.dto.InstrumentModelDto.class)
@ApiResponses({@ApiResponse(code = 404, message = "Instrument model not found")})
@Operation(summary = "Find instrument model by ID")
@ApiResponses({
@ApiResponse(useReturnTypeSchema = true, responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "Instrument model not found", content = @Content)
})
public InstrumentModelDto getInstrumentModel(
UriComponentsBuilder uriBuilder,
@ApiParam(value = "ID of instrument model to fetch") @PathVariable("id") Integer id) {
@Parameter(description = "ID of instrument model to fetch") @PathVariable("id") Integer id) {
InstrumentModel instrumentModel = instrumentService.getInstrumentModel(id);
if (instrumentModel == null) {
throw new RestException(HttpStatus.NOT_FOUND, "Instrument model not found");
Expand All @@ -67,10 +68,7 @@ public InstrumentModelDto getInstrumentModel(
}

@GetMapping("/instruments")
@ApiOperation(
value = "List all instruments",
response = ca.on.oicr.ws.dto.InstrumentDto.class,
responseContainer = "List")
@Operation(summary = "List all instruments")
public List<InstrumentDto> getInstruments(UriComponentsBuilder uriBuilder) {
List<Instrument> instruments = instrumentService.getInstruments();
List<InstrumentDto> result = Lists.newArrayList();
Expand All @@ -83,15 +81,14 @@ public List<InstrumentDto> getInstruments(UriComponentsBuilder uriBuilder) {
}

@GetMapping("/instrumentmodel/{id}/instruments")
@ApiOperation(
value = "List all instruments for a given instrument model ID",
response = ca.on.oicr.ws.dto.InstrumentDto.class,
responseContainer = "List")
@ApiResponses({@ApiResponse(code = 404, message = "No instruments found")})
@Operation(summary = "List all instruments for a given instrument model ID")
@ApiResponses({
@ApiResponse(useReturnTypeSchema = true, responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "No instruments found", content = @Content)
})
public List<InstrumentDto> getInstrumentsModelInstrument(
UriComponentsBuilder uriBuilder,
@ApiParam(value = "ID of instrument model to fetch instruments for") @PathVariable("id")
Integer id) {
@Parameter(description = "ID of instrument model to fetch instruments for") @PathVariable("id") Integer id) {
List<Instrument> instruments = instrumentService.getInstrumentModelInstrument(id);
List<InstrumentDto> result = Lists.newArrayList();
for (Instrument instrument : instruments) {
Expand All @@ -103,11 +100,14 @@ public List<InstrumentDto> getInstrumentsModelInstrument(
}

@GetMapping("/instrument/{id}")
@ApiOperation(value = "Find instrument by ID", response = ca.on.oicr.ws.dto.InstrumentDto.class)
@ApiResponses({@ApiResponse(code = 404, message = "No instrument found")})
@Operation(summary = "Find instrument by ID")
@ApiResponses({
@ApiResponse(useReturnTypeSchema = true, responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "No instrument found", content = @Content)
})
public InstrumentDto getInstrument(
UriComponentsBuilder uriBuilder,
@ApiParam(value = "ID of instrument to fetch") @PathVariable("id") Integer instrumentId) {
@Parameter(description = "ID of instrument to fetch") @PathVariable("id") Integer instrumentId) {
Instrument instrument = instrumentService.getInstrument(instrumentId);
if (instrument == null) {
throw new RestException(HttpStatus.NOT_FOUND, "No instrument found with ID: " + instrumentId);
Expand Down
Loading

0 comments on commit 826b695

Please sign in to comment.