From 7f208c32a9d9d7b30567bdf10031f10924bc5906 Mon Sep 17 00:00:00 2001 From: redmitry Date: Wed, 13 Mar 2024 16:11:09 +0100 Subject: [PATCH] restore beacon's /info from log if beacon is down --- pom.xml | 2 +- .../network/config/NetworkConfiguration.java | 86 ++++++++++++------- .../ga4gh/beacon/network/log/BeaconLog.java | 33 ++++++- 3 files changed, 86 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index 8acef24..ab78759 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ es.bsc.inb.ga4gh beacon-v2-validator-code - 0.0.4 + 0.0.7 diff --git a/src/main/java/es/bsc/inb/ga4gh/beacon/network/config/NetworkConfiguration.java b/src/main/java/es/bsc/inb/ga4gh/beacon/network/config/NetworkConfiguration.java index 0a30976..07aa08b 100644 --- a/src/main/java/es/bsc/inb/ga4gh/beacon/network/config/NetworkConfiguration.java +++ b/src/main/java/es/bsc/inb/ga4gh/beacon/network/config/NetworkConfiguration.java @@ -35,6 +35,7 @@ import es.bsc.inb.ga4gh.beacon.network.log.BeaconLogEntity; import es.bsc.inb.ga4gh.beacon.network.log.BeaconLogEntity.METHOD; import es.bsc.inb.ga4gh.beacon.network.log.BeaconLogEntity.REQUEST_TYPE; +import es.bsc.inb.ga4gh.beacon.network.log.BeaconLogLevel; import es.bsc.inb.ga4gh.beacon.network.model.BeaconNetworkInfoResponse; import es.bsc.inb.ga4gh.beacon.validator.BeaconMetadataSchema; import es.bsc.inb.ga4gh.beacon.validator.BeaconMetadataValidator; @@ -175,20 +176,40 @@ private void updateBeacons(NetworkConfigChangedEvent event) { */ private void updateBeacon(String endpoint) { final List err = new ArrayList(); - if (updateMetadata(endpoint, BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA, err)) { - final String beaconId = getBeaconId(endpoint); // beaconId can't be null - for (BeaconMetadataSchema schema : BeaconMetadataSchema.values()) { - if (BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA != schema) { - final int nerrors = err.size(); - updateMetadata(endpoint, schema, err); - if (beaconId != null && nerrors != err.size()) { - metadata.get(schema).remove(beaconId); + if (updateMetadata(endpoint, BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA, + BeaconLogLevel.METADATA, err)) { // always write "/info" metadata + String beacon_id = getBeaconId(endpoint); + if (err.isEmpty()) { + // beaconId can't be null if no errors in metadata! + for (BeaconMetadataSchema schema : BeaconMetadataSchema.values()) { + if (BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA != schema) { + final int nerrors = err.size(); + updateMetadata(endpoint, schema, BeaconLogLevel.LEVEL, err); + if (beacon_id != null && nerrors != err.size()) { + metadata.get(schema).remove(beacon_id); + } } } - } - if (err.isEmpty()) { - errors.remove(endpoint); - } else { + if (err.isEmpty()) { + errors.remove(endpoint); + } else { + errors.put(endpoint, err); + } + } else if (beacon_id == null) { + // the beacon is not accessible and never was loaded (beacon_id == null) + final BeaconLogEntity log_entity = log.getLastResponse(endpoint + + validator.ENDPOINTS.get(BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA)); + if (log_entity != null) { + final BeaconInformationalResponse response = validator.parseMetadata(log_entity.getResponse(), + BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA); + beacon_id = getBeaconId(response); + if (beacon_id != null) { + final Map map = (Map)metadata.get(BeaconMetadataSchema.BEACON_INFO_RESPONSE_SCHEMA); + map.put(beacon_id, response); + endpoints.put(beacon_id, endpoint); + } + } errors.put(endpoint, err); } } @@ -204,6 +225,7 @@ private void updateBeacon(String endpoint) { * @return false if no changes in metadata happened, true otherwise */ private boolean updateMetadata(String endpoint, BeaconMetadataSchema schema, + BeaconLogLevel level, List errors) { boolean changed = true; @@ -231,24 +253,18 @@ private boolean updateMetadata(String endpoint, BeaconMetadataSchema schema, err = validator.validate(schema, value); if (err.isEmpty()) { final BeaconInformationalResponse response = validator.parseMetadata(json, schema); - if (response != null) { + final String beacon_id = getBeaconId(response); + if (beacon_id != null) { hashes.put(metadata_endpoint, json.hashCode()); - final BeaconInformationalResponseMeta rmeta = response.getMeta(); - if (rmeta != null) { - final String beacon_id = rmeta.getBeaconId(); - if (beacon_id != null) { - endpoints.put(beacon_id, endpoint); - final Map map = (Map)metadata.get(schema); - map.put(beacon_id, response); - } - } else { // should never happen if json schema is correct! - log_entry.setMessage("missed BeaconInformationalResponseMeta in response"); - err.add(new BeaconValidationMessage( - BeaconValidationErrorType.CONTENT_ERROR, - null, metadata_endpoint, null, - log_entry.getMessage())); - - } + endpoints.put(beacon_id, endpoint); + final Map map = (Map)metadata.get(schema); + map.put(beacon_id, response); + } else { // should never happen if json schema is correct! + log_entry.setMessage("missed beaconId in response"); + err.add(new BeaconValidationMessage( + BeaconValidationErrorType.CONTENT_ERROR, + null, metadata_endpoint, null, + log_entry.getMessage())); } } else { log_entry.setMessage(err.get(err.size() - 1).message); @@ -263,7 +279,7 @@ private boolean updateMetadata(String endpoint, BeaconMetadataSchema schema, } } - log.log(log_entry); + log.log(log_entry, level); return changed; } @@ -301,6 +317,16 @@ public Map> getErrors() { return errors; } + private String getBeaconId(BeaconInformationalResponse response) { + if (response != null) { + final BeaconInformationalResponseMeta rmeta = response.getMeta(); + if (rmeta != null) { + return rmeta.getBeaconId(); + } + } + return null; + } + private String getBeaconId(String endpoint) { for (Map.Entry entry : endpoints.entrySet()) { if (endpoint.equals(entry.getValue())) { diff --git a/src/main/java/es/bsc/inb/ga4gh/beacon/network/log/BeaconLog.java b/src/main/java/es/bsc/inb/ga4gh/beacon/network/log/BeaconLog.java index a8f165c..e74a88c 100644 --- a/src/main/java/es/bsc/inb/ga4gh/beacon/network/log/BeaconLog.java +++ b/src/main/java/es/bsc/inb/ga4gh/beacon/network/log/BeaconLog.java @@ -1,6 +1,6 @@ /** * ***************************************************************************** - * Copyright (C) 2023 ELIXIR ES, Spanish National Bioinformatics Institute (INB) + * Copyright (C) 2024 ELIXIR ES, Spanish National Bioinformatics Institute (INB) * and Barcelona Supercomputing Center (BSC) * * Modifications to the initial code base are copyright of their respective @@ -30,6 +30,9 @@ import jakarta.inject.Singleton; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityTransaction; +import jakarta.persistence.Query; +import jakarta.persistence.TypedQuery; +import java.net.URI; /** * @author Dmitry Repchevsky @@ -41,15 +44,37 @@ public class BeaconLog { @Inject private EntityManager em; + public BeaconLogEntity getLastResponse(String url) { + final EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + final TypedQuery query = + em.createQuery("SELECT l FROM log l WHERE code < 300 AND url = :url ORDER BY l.id DESC", + BeaconLogEntity.class); + query.setParameter("url", url); + query.setMaxResults(1); + final BeaconLogEntity entry = query.getSingleResult(); + tx.commit(); + return entry; + } catch (Exception ex) { + tx.rollback(); + } + return null; + } + public void log(BeaconLogEntity record) { + log(record, BeaconLogLevel.LEVEL); + } + + public void log(BeaconLogEntity record, BeaconLogLevel level) { - if (BeaconLogLevel.LEVEL == BeaconLogLevel.NONE || - (BeaconLogLevel.LEVEL == BeaconLogLevel.METADATA && + if (level == BeaconLogLevel.NONE || + (level == BeaconLogLevel.METADATA && record.getType() != REQUEST_TYPE.METADATA)) { return; } - if (BeaconLogLevel.LEVEL.compareTo(BeaconLogLevel.RESPONSES) < 0 && + if (level.compareTo(BeaconLogLevel.RESPONSES) < 0 && record.getType() == REQUEST_TYPE.QUERY) { record.setMessage(null); record.setResponse(null);