diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java index 1ddf6ac8e..8b83698ee 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java @@ -108,14 +108,15 @@ public AuditTrailService( * @param action Restrict the results to only be about this type of action * @param fingerprint The fingerprint * @param operationID Restrict the results to only this operationID + * @param maxAuditTrails The max number of audit trails to fetch from database * @return an iterator to all AuditTrailEvents matching the criteria from the parameters */ public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date toDate, String fileID, String collectionID, String reportingComponent, String actor, FileAction action, - String fingerprint, String operationID) { + String fingerprint, String operationID, int maxAuditTrails) { return store.getAuditTrailsByIterator(fileID, collectionID, reportingComponent, null, null, actor, action, - fromDate, toDate, fingerprint, operationID); + fromDate, toDate, fingerprint, operationID, maxAuditTrails); } /** diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditDatabaseExtractor.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditDatabaseExtractor.java index fda4becb4..e79f60f62 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditDatabaseExtractor.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditDatabaseExtractor.java @@ -2,7 +2,7 @@ * #%L * Bitrepository Audit Trail Service * %% - * Copyright (C) 2010 - 2012 The State and University Library, The Royal Library and The State Archives, Denmark + * Copyright (C) 2010 - 2025 Royal Danish Library and The State Archives, Denmark * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -28,9 +28,11 @@ import org.slf4j.LoggerFactory; import java.sql.PreparedStatement; -import java.util.ArrayList; -import java.util.Arrays; +import java.sql.SQLException; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.bitrepository.audittrails.store.AuditDatabaseConstants.ACTOR_KEY; import static org.bitrepository.audittrails.store.AuditDatabaseConstants.ACTOR_NAME; @@ -64,15 +66,11 @@ * As such any change in extraction model should be reflected in the AuditEventIterator. * For further details @see {@link org.bitrepository.audittrails.store.AuditEventIterator} *

- *

* Order of extraction: * FileId, ContributorId, SequenceNumber, SeqNumber, ActorName, Operation, OperationDate, * AuditTrail, Information, OperationID, Certificate fingerprint */ public class AuditDatabaseExtractor { - /** - * The log. - */ private final Logger log = LoggerFactory.getLogger(getClass()); /** @@ -126,12 +124,10 @@ public class AuditDatabaseExtractor { private final DBConnector dbConnector; /** - * Constructor. - * * @param model The model for the restriction for the extraction from the database. * @param dbConnector The connector to the database, where the audit trails are to be extracted. */ - public AuditDatabaseExtractor(ExtractModel model, DBConnector dbConnector) { + AuditDatabaseExtractor(ExtractModel model, DBConnector dbConnector) { ArgumentValidator.checkNotNull(model, "ExtractModel model"); ArgumentValidator.checkNotNull(dbConnector, "DBConnector dbConnector"); @@ -145,16 +141,19 @@ public AuditDatabaseExtractor(ExtractModel model, DBConnector dbConnector) { * @return {@link AuditEventIterator} Iterator for extracting the AuditTrails */ public AuditEventIterator extractAuditEventsByIterator() { - String sql = createSelectString() + " FROM " + AUDIT_TRAIL_TABLE + joinWithFileTable() + joinWithActorTable() - + joinWithContributorTable() + createRestriction() - + " ORDER BY " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_DATE + " FETCH FIRST 1000 ROWS ONLY"; + String sql = createSelectString() + + " FROM " + AUDIT_TRAIL_TABLE + joinWithFileTable() + joinWithActorTable() + joinWithContributorTable() + + createRestriction() + + " ORDER BY " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_DATE + + createRowLimit(); try { + List arguments = extractArgumentsFromModel(); log.debug("Creating prepared statement with sql '{}' and arguments '{}' for AuditEventIterator", - sql, Arrays.asList(extractArgumentsFromModel())); + sql, arguments); PreparedStatement ps = DatabaseUtils.createPreparedStatement(dbConnector.getConnection(), - sql, extractArgumentsFromModel()); + sql, arguments.toArray()); return new AuditEventIterator(ps); - } catch (Exception e) { + } catch (SQLException | RuntimeException e) { throw new IllegalStateException("Failed to retrieve the audit trails from the database", e); } } @@ -166,21 +165,17 @@ public AuditEventIterator extractAuditEventsByIterator() { * @return Creates the SELECT string for the retrieval of the audit events. */ private String createSelectString() { - StringBuilder res = new StringBuilder(); - - res.append("SELECT "); - res.append(FILE_TABLE + "." + FILE_FILE_ID + ", "); - res.append(CONTRIBUTOR_TABLE + "." + CONTRIBUTOR_ID + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_SEQUENCE_NUMBER + ", "); - res.append(ACTOR_TABLE + "." + ACTOR_NAME + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_DATE + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_AUDIT + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_INFORMATION + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_ID + ", "); - res.append(AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_FINGERPRINT + " "); - - return res.toString(); + return "SELECT " + + FILE_TABLE + "." + FILE_FILE_ID + ", " + + CONTRIBUTOR_TABLE + "." + CONTRIBUTOR_ID + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_SEQUENCE_NUMBER + ", " + + ACTOR_TABLE + "." + ACTOR_NAME + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_DATE + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_AUDIT + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_INFORMATION + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_OPERATION_ID + ", " + + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_FINGERPRINT + " "; } /** @@ -189,8 +184,8 @@ private String createSelectString() { * @return The sql for joining the tables. */ private String joinWithFileTable() { - return " JOIN " + FILE_TABLE + " ON " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_FILE_KEY + " = " + FILE_TABLE + "." - + FILE_KEY + " "; + return " JOIN " + FILE_TABLE + + " ON " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_FILE_KEY + " = " + FILE_TABLE + "." + FILE_KEY + " "; } /** @@ -199,8 +194,8 @@ private String joinWithFileTable() { * @return The sql for joining the tables. */ private String joinWithActorTable() { - return " JOIN " + ACTOR_TABLE + " ON " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_ACTOR_KEY + " = " + ACTOR_TABLE - + "." + ACTOR_KEY + " "; + return " JOIN " + ACTOR_TABLE + + " ON " + AUDIT_TRAIL_TABLE + "." + AUDIT_TRAIL_ACTOR_KEY + " = " + ACTOR_TABLE + "." + ACTOR_KEY + " "; } /** @@ -295,56 +290,26 @@ private void nextArgument(StringBuilder res) { } } - /** - * @return The list of elements in the model which are not null. - */ - private Object[] extractArgumentsFromModel() { - List res = new ArrayList<>(); - - if (model.getFileID() != null) { - res.add(model.getFileID()); - } - - if (model.getCollectionID() != null) { - res.add(model.getCollectionID()); - } - - if (model.getContributorID() != null) { - res.add(model.getContributorID()); - } - - if (model.getMinSeqNumber() != null) { - res.add(model.getMinSeqNumber()); - } - - if (model.getMaxSeqNumber() != null) { - res.add(model.getMaxSeqNumber()); - } - - if (model.getActorName() != null) { - res.add(model.getActorName()); - } - - if (model.getOperation() != null) { - res.add(model.getOperation().toString()); - } - - if (model.getStartDate() != null) { - res.add(model.getStartDate().getTime()); - } - - if (model.getEndDate() != null) { - res.add(model.getEndDate().getTime()); - } - - if (model.getFingerprint() != null) { - res.add(model.getFingerprint()); - } - - if (model.getOperationID() != null) { - res.add(model.getOperationID()); + private String createRowLimit() { + if (model.getMaxAuditTrails() == null) { + return ""; } + return " FETCH FIRST ? ROWS ONLY"; + } - return res.toArray(); + /** + * @return The list of elements in the model which are not null, + * converted to types applicable for DatabaseUtils where appropriate. + */ + private List extractArgumentsFromModel() { + return Stream.of(model.getFileID(), model.getCollectionID(), model.getContributorID(), + model.getMinSeqNumber(), model.getMaxSeqNumber(), model.getActorName(), + model.getOperation() == null ? null : model.getOperation().toString(), + model.getStartDate() == null ? null : model.getStartDate().getTime(), + model.getEndDate() == null ? null : model.getEndDate().getTime(), + model.getFingerprint(), model.getOperationID(), model.getMaxAuditTrails()) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } + } diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailServiceDAO.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailServiceDAO.java index 1621aa164..4af2a7775 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailServiceDAO.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailServiceDAO.java @@ -50,9 +50,30 @@ public AuditTrailServiceDAO(DatabaseManager databaseManager) { @Override public AuditEventIterator getAuditTrailsByIterator(String fileID, String collectionID, String contributorID, - Long minSeqNumber, Long maxSeqNumber, String actorName, FileAction operation, - Date startDate, - Date endDate, String fingerprint, String operationID) { + Long minSeqNumber, Long maxSeqNumber, String actorName, + FileAction operation, + Date startDate, Date endDate, String fingerprint, + String operationID) { + return getAuditEventIteratorImplementation(fileID, collectionID, contributorID, minSeqNumber, maxSeqNumber, + actorName, operation, startDate, endDate, fingerprint, operationID, null); + } + + @Override + public AuditEventIterator getAuditTrailsByIterator(String fileID, String collectionID, String contributorID, + Long minSeqNumber, Long maxSeqNumber, String actorName, + FileAction operation, + Date startDate, Date endDate, String fingerprint, + String operationID, int maxAuditTrails) { + return getAuditEventIteratorImplementation(fileID, collectionID, contributorID, minSeqNumber, maxSeqNumber, + actorName, operation, startDate, endDate, fingerprint, operationID, maxAuditTrails); + } + + private AuditEventIterator getAuditEventIteratorImplementation(String fileID, String collectionID, + String contributorID, Long minSeqNumber, + Long maxSeqNumber, String actorName, + FileAction operation, Date startDate, Date endDate, + String fingerprint, String operationID, + Integer maxAuditTrails) { ExtractModel model = new ExtractModel(); model.setFileID(fileID); model.setCollectionID(collectionID); @@ -65,6 +86,7 @@ public AuditEventIterator getAuditTrailsByIterator(String fileID, String collect model.setEndDate(endDate); model.setFingerprint(fingerprint); model.setOperationID(operationID); + model.setMaxAuditTrails(maxAuditTrails); AuditDatabaseExtractor extractor = new AuditDatabaseExtractor(model, dbConnector); return extractor.extractAuditEventsByIterator(); diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailStore.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailStore.java index ac852ec76..dc4ec9837 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailStore.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/AuditTrailStore.java @@ -34,6 +34,7 @@ * Interface for the storage of audit trail information for the AuditTrailService. */ public interface AuditTrailStore { + /** * Obtain AuditEventIterator for extracting audit trails from the store. * When done with the iterator, the user should ensure that it is closed. @@ -56,6 +57,29 @@ AuditEventIterator getAuditTrailsByIterator(String fileID, String collectionID, Date startDate, Date endDate, String fingerprint, String operationID); + /** + * Obtain AuditEventIterator for extracting audit trails from the store. + * When done with the iterator, the user should ensure that it is closed. + * + * @param fileID [OPTIONAL] The id of the file for restricting the extraction. + * @param collectionID [OPTIONAL] The id of the collection from which to retrieve audit trails. + * @param contributorID [OPTIONAL] The id of the contributor for restricting the extraction. + * @param minSeqNumber [OPTIONAL] The minimum sequence number for restricting the extraction. + * @param maxSeqNumber [OPTIONAL] The maximum sequence number for restricting the extraction. + * @param actorName [OPTIONAL] The name of the actor for restricting the extraction. + * @param operation [OPTIONAL] The FileAction operation for restricting the extraction. + * @param startDate [OPTIONAL] The earliest date for the audits for restricting the extraction. + * @param endDate [OPTIONAL] The latest date for the audits for restricting the extraction. + * @param fingerprint [OPTIONAL] The fingerprint of the certificate for the audits + * @param operationID [OPTIONAL] The ID of the operation (conversationID) for the audits + * @param maxAuditTrails The max number of audit trails to fetch from database. + * @return The requested audit trails from the store. + */ + AuditEventIterator getAuditTrailsByIterator(String fileID, String collectionID, String contributorID, + Long minSeqNumber, Long maxSeqNumber, String actorName, FileAction operation, + Date startDate, + Date endDate, String fingerprint, String operationID, int maxAuditTrails); + /** * ingest audit trails into the store. * diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/ExtractModel.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/ExtractModel.java index ac051866c..697e04459 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/ExtractModel.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/store/ExtractModel.java @@ -74,8 +74,7 @@ class ExtractModel { */ private String operationID; - public ExtractModel() { - } + private Integer maxAuditTrails; /** * @return The fileID; @@ -233,4 +232,19 @@ public String getOperationID() { public void setOperationID(String operationID) { this.operationID = operationID; } + + /** + * @return The max number of audit trails to fetch from database or null for unlimited + */ + public Integer getMaxAuditTrails() { + return maxAuditTrails; + } + + /** + * @param maxAuditTrails The max number of audit trails to fetch from database or null for unlimited + */ + public void setMaxAuditTrails(Integer maxAuditTrails) { + this.maxAuditTrails = maxAuditTrails; + } + } diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java index 06271a838..999e20577 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java @@ -36,7 +36,9 @@ import org.bitrepository.common.utils.TimeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -77,14 +79,14 @@ public StreamingOutput queryAuditTrailEvents(@FormParam("fromDate") String fromD @FormParam("collectionID") String collectionID, @FormParam("fingerprint") String fingerprint, @FormParam("operationID") String operationID, - @FormParam("maxAuditTrails") Integer maxResults) { + @DefaultValue("1000") @FormParam("maxAuditTrails") Integer maxResults) { Date from = calendarUtils.makeStartDateObject(fromDate); Date to = calendarUtils.makeEndDateObject(toDate); final int maxAudits = maxResults; final AuditEventIterator it = service.queryAuditTrailEventsByIterator(from, to, contentOrNull(fileID), collectionID, contentOrNull(reportingComponent), contentOrNull(actor), filterAction(action), - contentOrNull(fingerprint), contentOrNull(operationID)); + contentOrNull(fingerprint), contentOrNull(operationID), maxAudits); if (it != null) { return output -> { JsonFactory jf = new JsonFactory(); @@ -93,14 +95,14 @@ collectionID, contentOrNull(reportingComponent), contentOrNull(actor), filterAct AuditTrailEvent event; jg.writeStartArray(); int numAudits = 0; - while ((event = it.getNextAuditTrailEvent()) != null && numAudits < maxAudits) { + while ((event = it.getNextAuditTrailEvent()) != null) { writeAuditResult(event, jg); numAudits++; } jg.writeEndArray(); jg.flush(); jg.close(); - } catch (Exception e) { + } catch (RuntimeException e) { log.error("Caught exception trying to stream audit trails", e); throw new WebApplicationException(e); } finally { @@ -114,8 +116,10 @@ collectionID, contentOrNull(reportingComponent), contentOrNull(actor), filterAct }; } else { throw new WebApplicationException( - Response.status(Response.Status.NO_CONTENT).entity("Failed to get audit trails from database") - .type(MediaType.TEXT_PLAIN).build()); + Response.status(Response.Status.NO_CONTENT) + .entity("Failed to get audit trails from database: it is null") + .type(MediaType.TEXT_PLAIN) + .build()); } } diff --git a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java index 511377311..f4798bbf7 100644 --- a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java +++ b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java @@ -63,7 +63,7 @@ public class AuditTrailServiceTest extends ExtendedTestCase { @BeforeClass(alwaysRun = true) - public void setup() throws Exception { + public void setup() { settings = TestSettingsProvider.reloadSettings("AuditTrailServiceUnderTest"); Collection c = settings.getRepositorySettings().getCollections().getCollection().get(0); settings.getRepositorySettings().getCollections().getCollection().clear(); @@ -113,20 +113,19 @@ public void auditTrailServiceTest() throws Exception { verify(store, times(1)).addAuditTrails(any(AuditTrailEvents.class), eq(TEST_COLLECTION), eq(DEFAULT_CONTRIBUTOR)); - service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, null, null, null); + service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, null, null, null, 10000); verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), - isNull(), isNull(), isNull(), isNull(), isNull()); - service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, FileAction.FAILURE, null, null); + isNull(), isNull(), isNull(), isNull(), isNull(), 10000); + service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, FileAction.FAILURE, null, null, 100); verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), - eq(FileAction.FAILURE), isNull(), isNull(), isNull(), isNull()); - + eq(FileAction.FAILURE), isNull(), isNull(), isNull(), isNull(), 100); addStep("Shutdown", ""); service.shutdown(); } - public class CollectionRunner implements Runnable { + public static class CollectionRunner implements Runnable { private final AuditTrailService service; boolean finished = false; diff --git a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/preserver/LocalAuditPreservationTest.java b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/preserver/LocalAuditPreservationTest.java index 40a383359..a0e726b7a 100644 --- a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/preserver/LocalAuditPreservationTest.java +++ b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/preserver/LocalAuditPreservationTest.java @@ -134,7 +134,9 @@ public AuditEventIterator answer(InvocationOnMock invocation) { // getPreservationSequenceNumber should be called twice, first to 'initialize' auditpacker, and second to // run the preserver/packer... verify(store, times(2)).getPreservationSequenceNumber(PILLAR_ID, collectionID); - verify(store).getAuditTrailsByIterator(null, null, PILLAR_ID, 0L, null, null, null, null, null, null, null); + verify(store).getAuditTrailsByIterator( + null, null, PILLAR_ID, 0L, null, null, + null, null, null, null, null); verify(iterator).getNextAuditTrailEvent(); //Assert.assertEquals(store.getCallsToGetAuditTrails(), settings.getRepositorySettings().getGetAuditTrailSettings().getNonPillarContributorIDs().size()); diff --git a/bitrepository-core/src/test/java/org/bitrepository/protocol/http/HttpFileExchangeTest.java b/bitrepository-core/src/test/java/org/bitrepository/protocol/http/HttpFileExchangeTest.java index ef6485025..736e463ff 100644 --- a/bitrepository-core/src/test/java/org/bitrepository/protocol/http/HttpFileExchangeTest.java +++ b/bitrepository-core/src/test/java/org/bitrepository/protocol/http/HttpFileExchangeTest.java @@ -41,7 +41,7 @@ public void checkUrlEncodingOfFilenamesTest() throws MalformedURLException { Settings mySettings = TestSettingsProvider.reloadSettings("uploadTest"); FileExchangeSettings fileExchangeSettings = mySettings.getReferenceSettings().getFileExchangeSettings(); fileExchangeSettings.setProtocolType(ProtocolType.HTTP); - fileExchangeSettings.setServerName("http:testserver.org"); + fileExchangeSettings.setServerName("testserver.org"); fileExchangeSettings.setPort(BigInteger.valueOf(8000)); fileExchangeSettings.setPath("dav"); HttpFileExchange fe = new HttpFileExchange(fileExchangeSettings); diff --git a/bitrepository-service/pom.xml b/bitrepository-service/pom.xml index b85efc600..d3a757ec4 100644 --- a/bitrepository-service/pom.xml +++ b/bitrepository-service/pom.xml @@ -39,7 +39,7 @@ org.postgresql postgresql - 42.4.1 + 42.7.6 com.mchange