diff --git a/src/main/java/edu/harvard/mcz/imagecapture/data/NahimaManager.java b/src/main/java/edu/harvard/mcz/imagecapture/data/NahimaManager.java index 9ecc315..b7f843e 100644 --- a/src/main/java/edu/harvard/mcz/imagecapture/data/NahimaManager.java +++ b/src/main/java/edu/harvard/mcz/imagecapture/data/NahimaManager.java @@ -3,6 +3,7 @@ import com.github.mizosoft.methanol.MediaType; import com.github.mizosoft.methanol.MultipartBodyPublisher; import com.github.mizosoft.methanol.MutableRequest; +import edu.harvard.mcz.imagecapture.ImageCaptureApp; import edu.harvard.mcz.imagecapture.ImageCaptureProperties; import edu.harvard.mcz.imagecapture.entity.ICImage; import edu.harvard.mcz.imagecapture.entity.Specimen; @@ -24,8 +25,8 @@ public class NahimaManager extends AbstractRestClient { private final String url; private final String username; private final String password; - private String token; private final Map> resolveCache = new HashMap<>(); + private String token; public NahimaManager(String url, String username, String password) throws IOException, InterruptedException, RuntimeException { // normalize URL @@ -46,7 +47,6 @@ public NahimaManager(String url, String username, String password) throws IOExce /** * Start a Nahima session - * */ protected void startSessionAndRetrieveToken() throws RuntimeException { String queryUrl = this.url + "session"; @@ -61,7 +61,6 @@ protected void startSessionAndRetrieveToken() throws RuntimeException { /** * Do login to Nahima - * */ protected void login() throws IOException, InterruptedException, RuntimeException { String queryUrl = this.url + "session/authenticate?method=easydb&token=" + this.token; @@ -121,14 +120,14 @@ public Object[] uploadImagesForSpecimen(Specimen specimen) throws IOException, I /** * Run the query to create an object in Nahima * - * @param object the object to create - * @param pool the pool to create the object in + * @param object the object to create + * @param objType the pool to create the object in * @return the created object as it is in Nahima */ - public JSONObject createObjectInNahima(JSONObject object, String pool) throws IOException, InterruptedException { + public JSONObject createObjectInNahima(JSONObject object, String objType) throws IOException, InterruptedException { // docs: // https://docs.easydb.de/en/technical/api/db/ - String queryURL = this.url + "db/" + pool + "?token=" + token; + String queryURL = this.url + "db/" + objType + "?token=" + token; // EasyDB seems to have mixed up PUT & POST, but well, we don't care String returnValue = this.putRequest(queryURL, (new JSONArray()).put(object).toString(), new HashMap<>() {{ put("Content-Type", "application/json"); @@ -145,6 +144,26 @@ public JSONObject createObjectInNahima(JSONObject object, String pool) throws IO return (JSONObject) (new JSONArray(returnValue)).get(0); } + protected JSONObject loadFromCache(String id, String objectType) { + Map typeCache = resolveCache.get(objectType); + if (typeCache != null) { + JSONObject cacheLoaded = typeCache.get(id); + if (cacheLoaded != null) { + return cacheLoaded; + } + } + return null; + } + + protected void storeInCache(String id, String objectType, JSONObject result) { + Map typeCache = resolveCache.get(objectType); + if (typeCache == null) { + typeCache = new HashMap<>(); + resolveCache.put(objectType, typeCache); + } + typeCache.put(id, result); + } + /** * Search for a string in a Nahima objecttype * @@ -156,11 +175,10 @@ public JSONObject createObjectInNahima(JSONObject object, String pool) throws IO */ public JSONObject searchForString(String searchString, String objectType, String searchMode, boolean ignoreCache) throws IOException, InterruptedException { // check cache for results - Map typeCache = resolveCache.get(objectType); - if (typeCache != null) { - JSONObject cacheLoaded = typeCache.get(searchString); - if (cacheLoaded != null && !ignoreCache) { - return cacheLoaded; + if (!ignoreCache) { + JSONObject fromCache = loadFromCache(searchString, objectType); + if (fromCache != null) { + return fromCache; } } @@ -190,11 +208,7 @@ public JSONObject searchForString(String searchString, String objectType, String // store result in cache JSONObject result = this.postRequest(queryURL, query); - if (typeCache == null) { - typeCache = new HashMap<>(); - resolveCache.put(objectType, typeCache); - } - typeCache.put(searchString, result); + storeInCache(searchString, objectType, result); return result; } @@ -218,13 +232,13 @@ public JSONObject searchForString(String searchString, String objectType, boolea * @param objectType the object type that is searched * @return the object if there is only one, null if not */ - public JSONObject resolveStringSearchToOne(String search, String objectType) throws IOException, InterruptedException { + public JSONObject resolveStringSearchToOne(String search, String objectType, boolean ignoreCache) throws IOException, InterruptedException { if (search == null || objectType == null) { log.warn("Cannot search as search " + search + " or objectType " + objectType + " is null"); return null; } - JSONObject results = this.searchForString(search, objectType); + JSONObject results = this.searchForString(search, objectType, ignoreCache); if (results.has("code") && results.getString("code").startsWith("error")) { throw new RuntimeException("Failed to resolve search. Error code: " + results.getString("code")); @@ -240,6 +254,10 @@ public JSONObject resolveStringSearchToOne(String search, String objectType) thr } } + public JSONObject resolveStringSearchToOne(String search, String objectType) throws IOException, InterruptedException { + return resolveStringSearchToOne(search, objectType, false); + } + /** * Find a person in Nahima * @@ -300,6 +318,35 @@ public JSONObject resolveUnitFor(String unit, String unitSubject) throws IOExcep return results; } + /** + * Find a typusstatus in Nahima + * + * @param nrType the search string + * @return the nahima returned object if only one + */ + public JSONObject resolveOtherNrType(String nrType) throws IOException, InterruptedException { + JSONObject results = this.resolveStringSearchToOne(nrType, "id_typen"); + // TODO: create / select correct + if (results == null && nrType != null) { + // TODO: create + JSONObject toCreate = new JSONObject(new HashMap<>() {{ + put("_idx_in_objects", 0); + put("_mask", "id_typen_all_fields"); + put("_objecttype", "id_typen"); + put("id_typen", new JSONObject(new HashMap<>() {{ + put("_id", JSONObject.NULL); + put("_version", 1); + put("name", nrType); + put("bemerkung", "Created by " + ImageCaptureApp.APP_NAME + " " + ImageCaptureApp.getAppVersion()); + }})); + }}); + this.createObjectInNahima(toCreate, "id_typen"); + // TODO: it would be simpler to store the created in cache. But well... current format does not allow + return this.resolveStringSearchToOne(nrType, "id_typen", true); + } + return results; + } + /** * Find a unit in Nahima * diff --git a/src/main/java/edu/harvard/mcz/imagecapture/entity/fixed/WorkFlowStatus.java b/src/main/java/edu/harvard/mcz/imagecapture/entity/fixed/WorkFlowStatus.java index 50afb94..ed1b7cf 100644 --- a/src/main/java/edu/harvard/mcz/imagecapture/entity/fixed/WorkFlowStatus.java +++ b/src/main/java/edu/harvard/mcz/imagecapture/entity/fixed/WorkFlowStatus.java @@ -84,7 +84,7 @@ public class WorkFlowStatus { * indicate further progress to complete load of all data into MCZbase. Record * is now not editable in DataShot. */ - public static final String STAGE_DONE = "Moved to MCZbase"; + public static final String STAGE_DONE = "Moved to Nahima"; /** * Specimen record has to be deleted. diff --git a/src/main/java/edu/harvard/mcz/imagecapture/serializer/nahima/Specimen2JSONSerializer.java b/src/main/java/edu/harvard/mcz/imagecapture/serializer/nahima/Specimen2JSONSerializer.java index 107b3b1..8f14f9b 100644 --- a/src/main/java/edu/harvard/mcz/imagecapture/serializer/nahima/Specimen2JSONSerializer.java +++ b/src/main/java/edu/harvard/mcz/imagecapture/serializer/nahima/Specimen2JSONSerializer.java @@ -1,6 +1,8 @@ package edu.harvard.mcz.imagecapture.serializer.nahima; +import edu.harvard.mcz.imagecapture.ImageCaptureApp; import edu.harvard.mcz.imagecapture.data.NahimaManager; +import edu.harvard.mcz.imagecapture.entity.Number; import edu.harvard.mcz.imagecapture.entity.*; import edu.harvard.mcz.imagecapture.serializer.ToJSONSerializerInterface; import org.apache.commons.lang3.time.DateUtils; @@ -40,6 +42,32 @@ public JSONObject serialize2JSON(Object target) { result.put("_id", JSONObject.NULL); result.put("_pool", NahimaManager.defaultPool); // here, it already starts to get complicated, fuu. + // first, other ids, incl. specimen ID + JSONArray otherIds = new JSONArray(); + for (Number otherNr : toSerialize.getNumbers()) { + Map otherNrMap = new HashMap<>() {{ + put("andereid", otherNr.getNumber()); + put("bemerkung", String.join(" ", otherNr.getNumber(), String.valueOf(otherNr.getNumberId()), otherNr.getNumberType())); + }}; + try { + otherNrMap.put("typ", nahimaManager.resolveOtherNrType(otherNr.getNumberType())); + } catch (IOException | InterruptedException e) { + log.error("Failed to resolve nr type", e); + } + otherIds.put(new JSONObject(otherNrMap)); + } + // also add specimen id as other id + JSONObject dataShotId = new JSONObject(new HashMap() {{ + put("andereid", String.valueOf(toSerialize.getSpecimenId())); + }}); + try { + dataShotId.put("typ", nahimaManager.resolveOtherNrType(ImageCaptureApp.APP_NAME + "-ID")); + } catch (IOException | InterruptedException e) { + log.error("Failed to resolve nr type", e); + } + otherIds.put(dataShotId); + result.put("_nested:entomologie__andereids", otherIds); + // JSONArray reverseNestedDeterminations = new JSONArray(); for (Determination det : toSerialize.getDeterminations()) { Map reverseNestedCollectionMap = new HashMap<>() {{ @@ -77,7 +105,7 @@ public JSONObject serialize2JSON(Object target) { identifierPersons.put(nahimaManager.reduceAssociateForAssociation(identifierPerson)); } } catch (IOException | InterruptedException e) { - log.info("Failed to resolve person", e); + log.error("Failed to resolve person", e); } reverseNestedDetermination.put("_nested:bestimmung__bestimmer_person", identifierPersons); @@ -85,7 +113,7 @@ public JSONObject serialize2JSON(Object target) { JSONObject resolvedTypeStatus = nahimaManager.resolveTypeStatus(det.getTypeStatus()); reverseNestedDetermination.put("typusstatus", resolvedTypeStatus); } catch (IOException | InterruptedException e) { - log.info("Failed to resolve type status", e); + log.error("Failed to resolve type status", e); } // TODO: other fields