Skip to content

Commit 0eb2539

Browse files
committed
Concept Set Snapshots/Locking/Unlocking feature implementation
1 parent df5175c commit 0eb2539

22 files changed

+902
-30
lines changed

.github/workflows/ci.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
java-version: 8
3131

3232
- name: Maven cache
33-
uses: actions/cache@v2
33+
uses: actions/cache@v4
3434
with:
3535
# Cache gradle directories
3636
path: ~/.m2
@@ -57,7 +57,7 @@ jobs:
5757
- uses: actions/checkout@v2
5858

5959
- name: Cache Docker layers
60-
uses: actions/cache@v2
60+
uses: actions/cache@v4
6161
with:
6262
path: /tmp/.buildx-cache
6363
key: ${{ runner.os }}-buildx-${{ github.sha }}

.github/workflows/release.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
java-version: 8
2727

2828
- name: Maven cache
29-
uses: actions/cache@v2
29+
uses: actions/cache@v4
3030
with:
3131
# Cache gradle directories
3232
path: ~/.m2

pom.xml

+8
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@
6464
<!-- CDM properties -->
6565
<source.name>CDM_NAME</source.name>
6666
<cdm.version>5</cdm.version>
67+
<!-- Snapshot datasource properties -->
68+
<snapshot.history.source.connection>jdbc:postgresql://localhost:5432/OHDSI_LOCK_HISTORY</snapshot.history.source.connection>
69+
<snapshot.history.source.schema>lock_history</snapshot.history.source.schema>
70+
<snapshot.history.source.dialect>postgresql</snapshot.history.source.dialect>
71+
<snapshot.history.source.username>userWithWritePrivs</snapshot.history.source.username>
72+
<snapshot.history.source.password>password</snapshot.history.source.password>
73+
<snapshot.history.flyway.locations>classpath:snapshots_db/migration/postgresql</snapshot.history.flyway.locations>
74+
<snapshot.locking.enabled>true</snapshot.locking.enabled>
6775
<!-- Person properties -->
6876
<person.viewDates>false</person.viewDates>
6977
<!-- Heracles properties -->

src/main/java/org/ohdsi/webapi/service/ConceptSetService.java

+114-18
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,8 @@
1515
*/
1616
package org.ohdsi.webapi.service;
1717

18-
import java.io.ByteArrayOutputStream;
19-
import java.util.*;
20-
import java.util.stream.Collectors;
21-
import java.util.stream.StreamSupport;
22-
23-
import javax.transaction.Transactional;
24-
import javax.ws.rs.*;
25-
import javax.ws.rs.core.MediaType;
26-
import javax.ws.rs.core.Response;
27-
2818
import com.fasterxml.jackson.core.JsonProcessingException;
2919
import com.fasterxml.jackson.databind.ObjectMapper;
30-
import javax.cache.CacheManager;
31-
import javax.cache.configuration.MutableConfiguration;
32-
3320
import org.apache.shiro.authz.UnauthorizedException;
3421
import org.ohdsi.circe.vocabulary.ConceptSetExpression;
3522
import org.ohdsi.vocabulary.Concept;
@@ -40,16 +27,23 @@
4027
import org.ohdsi.webapi.conceptset.ConceptSetGenerationInfo;
4128
import org.ohdsi.webapi.conceptset.ConceptSetGenerationInfoRepository;
4229
import org.ohdsi.webapi.conceptset.ConceptSetItem;
43-
import org.ohdsi.webapi.conceptset.dto.ConceptSetVersionFullDTO;
4430
import org.ohdsi.webapi.conceptset.annotation.ConceptSetAnnotation;
31+
import org.ohdsi.webapi.conceptset.dto.ConceptSetVersionFullDTO;
4532
import org.ohdsi.webapi.exception.ConceptNotExistException;
4633
import org.ohdsi.webapi.security.PermissionService;
4734
import org.ohdsi.webapi.service.annotations.SearchDataTransformer;
35+
import org.ohdsi.webapi.service.dto.AnnotationDTO;
4836
import org.ohdsi.webapi.service.dto.AnnotationDetailsDTO;
4937
import org.ohdsi.webapi.service.dto.ConceptSetDTO;
50-
import org.ohdsi.webapi.service.dto.SaveConceptSetAnnotationsRequest;
51-
import org.ohdsi.webapi.service.dto.AnnotationDTO;
5238
import org.ohdsi.webapi.service.dto.CopyAnnotationsRequest;
39+
import org.ohdsi.webapi.service.dto.SaveConceptSetAnnotationsRequest;
40+
import org.ohdsi.webapi.service.lock.ConceptSetLockingService;
41+
import org.ohdsi.webapi.service.lock.dto.ConceptSetSnapshotActionRequest;
42+
import org.ohdsi.webapi.service.lock.dto.ConceptSetSnapshotParameters;
43+
import org.ohdsi.webapi.service.lock.dto.GetConceptSetSnapshotItemsRequest;
44+
import org.ohdsi.webapi.service.lock.dto.GetConceptSetSnapshotItemsResponse;
45+
import org.ohdsi.webapi.service.lock.dto.IsLockedBatchCheckRequest;
46+
import org.ohdsi.webapi.service.lock.dto.IsLockedBatchCheckResponse;
5347
import org.ohdsi.webapi.shiro.Entities.UserEntity;
5448
import org.ohdsi.webapi.shiro.Entities.UserRepository;
5549
import org.ohdsi.webapi.shiro.management.Security;
@@ -60,9 +54,9 @@
6054
import org.ohdsi.webapi.tag.domain.HasTags;
6155
import org.ohdsi.webapi.tag.dto.TagNameListRequestDTO;
6256
import org.ohdsi.webapi.util.CacheHelper;
57+
import org.ohdsi.webapi.util.ExceptionUtils;
6358
import org.ohdsi.webapi.util.ExportUtil;
6459
import org.ohdsi.webapi.util.NameUtils;
65-
import org.ohdsi.webapi.util.ExceptionUtils;
6660
import org.ohdsi.webapi.versioning.domain.ConceptSetVersion;
6761
import org.ohdsi.webapi.versioning.domain.Version;
6862
import org.ohdsi.webapi.versioning.domain.VersionBase;
@@ -79,6 +73,37 @@
7973
import org.springframework.dao.EmptyResultDataAccessException;
8074
import org.springframework.stereotype.Component;
8175

76+
import javax.cache.CacheManager;
77+
import javax.cache.configuration.MutableConfiguration;
78+
import javax.transaction.Transactional;
79+
import javax.ws.rs.Consumes;
80+
import javax.ws.rs.DELETE;
81+
import javax.ws.rs.DefaultValue;
82+
import javax.ws.rs.GET;
83+
import javax.ws.rs.NotFoundException;
84+
import javax.ws.rs.POST;
85+
import javax.ws.rs.PUT;
86+
import javax.ws.rs.Path;
87+
import javax.ws.rs.PathParam;
88+
import javax.ws.rs.Produces;
89+
import javax.ws.rs.QueryParam;
90+
import javax.ws.rs.core.MediaType;
91+
import javax.ws.rs.core.Response;
92+
import java.io.ByteArrayOutputStream;
93+
import java.util.ArrayList;
94+
import java.util.Arrays;
95+
import java.util.Collection;
96+
import java.util.Collections;
97+
import java.util.Date;
98+
import java.util.HashMap;
99+
import java.util.List;
100+
import java.util.Locale;
101+
import java.util.Map;
102+
import java.util.Objects;
103+
import java.util.Set;
104+
import java.util.stream.Collectors;
105+
import java.util.stream.StreamSupport;
106+
82107
/**
83108
* Provides REST services for working with
84109
* concept sets.
@@ -145,6 +170,8 @@ public void customize(CacheManager cacheManager) {
145170
@Autowired
146171
private ObjectMapper mapper;
147172

173+
@Autowired
174+
private ConceptSetLockingService conceptSetLockingService;
148175

149176
@Value("${security.defaultGlobalReadPermissions}")
150177
private boolean defaultGlobalReadPermissions;
@@ -564,6 +591,75 @@ public ConceptSetDTO updateConceptSet(@PathParam("id") final int id, ConceptSetD
564591
ConceptSet conceptSet = conversionService.convert(conceptSetDTO, ConceptSet.class);
565592
return conversionService.convert(updateConceptSet(updated, conceptSet), ConceptSetDTO.class);
566593
}
594+
@Path("/{id}/list-snapshots")
595+
@GET
596+
@Produces(MediaType.APPLICATION_JSON)
597+
@Transactional
598+
public List<ConceptSetSnapshotParameters> listSnapshots(@PathParam("id") final int id) throws Exception {
599+
return conceptSetLockingService.listSnapshotsByConceptSetId(id);
600+
}
601+
@POST
602+
@Path("/{id}/snapshot")
603+
@Consumes(MediaType.APPLICATION_JSON)
604+
@Produces(MediaType.APPLICATION_JSON)
605+
@Transactional
606+
public Response invokeSnapshotAction(@PathParam("id") final int id, ConceptSetSnapshotActionRequest snapshotActionRequest) {
607+
try {
608+
String sourceKey = snapshotActionRequest.getSourceKey();
609+
610+
if(snapshotActionRequest.isTakeSnapshot()) {
611+
612+
ConceptSetExpression conceptSetExpression = getConceptSetExpression(id, sourceKey);
613+
Collection<Concept> includedConcepts = vocabService.executeIncludedConceptLookup(sourceKey, conceptSetExpression);
614+
Collection<Concept> includedSourceCodes = vocabService.executeMappedLookup(sourceKey, conceptSetExpression);
615+
616+
conceptSetLockingService.invokeSnapshotAction(id, snapshotActionRequest, conceptSetExpression, includedConcepts, includedSourceCodes);
617+
} else {
618+
conceptSetLockingService.invokeSnapshotAction(id, snapshotActionRequest, null, null, null);
619+
}
620+
return Response.ok().entity("Snapshot action successfully invoked.").build();
621+
} catch (Exception e) {
622+
log.error("Invoke snapshot action failed", e);
623+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
624+
.entity("Invoke snapshot action failed: " + e.getMessage())
625+
.build();
626+
}
627+
}
628+
629+
@POST
630+
@Path("/check-locked")
631+
@Consumes(MediaType.APPLICATION_JSON)
632+
@Produces(MediaType.APPLICATION_JSON)
633+
public Response checkIsLockedBatch(IsLockedBatchCheckRequest isLockedBatchCheckRequest) {
634+
IsLockedBatchCheckResponse response = new IsLockedBatchCheckResponse();
635+
try {
636+
List<Integer> ids = isLockedBatchCheckRequest.getConceptSetIds();
637+
Map<Integer, Boolean> lockStatuses = conceptSetLockingService.areLocked(ids);
638+
response.setLockStatus(lockStatuses);
639+
return Response.ok(response).build();
640+
} catch (Exception e) {
641+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
642+
.entity("Error checking lock statuses: " + e.getMessage())
643+
.build();
644+
}
645+
}
646+
647+
@POST
648+
@Path("/get-snapshot-items")
649+
@Consumes(MediaType.APPLICATION_JSON)
650+
@Produces(MediaType.APPLICATION_JSON)
651+
public Response getSnapshotItems(GetConceptSetSnapshotItemsRequest request) {
652+
try {
653+
List<ConceptSetExpression.ConceptSetItem> conceptSetItems = conceptSetLockingService.getConceptSetSnapshotItemsBySnapshotId(request.getSnapshotId(), request.getSnapshotItemType());
654+
GetConceptSetSnapshotItemsResponse response = new GetConceptSetSnapshotItemsResponse();
655+
response.setConceptSetItems(conceptSetItems);
656+
return Response.ok(response).build();
657+
} catch (Exception e) {
658+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
659+
.entity("Error fetching snapshot items: " + e.getMessage())
660+
.build();
661+
}
662+
}
567663

568664
private ConceptSet updateConceptSet(ConceptSet dst, ConceptSet src) {
569665

@@ -1030,4 +1126,4 @@ public Response deleteConceptSetAnnotation(@PathParam("conceptSetId") final int
10301126
return Response.ok().build();
10311127
} else throw new NotFoundException("Concept set annotation not found");
10321128
}
1033-
}
1129+
}

0 commit comments

Comments
 (0)