package eu.eudat.logic.mapper.prefilling; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import eu.eudat.data.DescriptionEntity; import eu.eudat.data.DescriptionTemplateEntity; import eu.eudat.data.TagEntity; import eu.eudat.logic.managers.DatasetManager; import eu.eudat.logic.managers.DatasetProfileManager; import eu.eudat.service.remotefetcher.config.entities.DefaultPrefillingMapping; import eu.eudat.service.remotefetcher.config.entities.PrefillingFixedMapping; import eu.eudat.service.remotefetcher.config.entities.PrefillingGet; import eu.eudat.service.remotefetcher.config.entities.PrefillingMapping; import eu.eudat.utilities.helpers.StreamDistinctBy; import eu.eudat.logic.utilities.json.JsonSearcher; import eu.eudat.commons.types.descriptiontemplate.fielddata.AutoCompleteDataEntity; import eu.eudat.models.data.datasetprofile.DatasetProfileOverviewModel; import eu.eudat.models.data.datasetwizard.DatasetWizardModel; import eu.eudat.service.remotefetcher.models.ExternalAutocompleteFieldResult; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; import eu.eudat.commons.enums.FieldType; @Component public class PrefillingMapper { private static final Logger logger = LoggerFactory.getLogger(PrefillingMapper.class); private static final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); private final DatasetProfileManager datasetProfileManager; @Autowired public PrefillingMapper(DatasetProfileManager datasetProfileManager) { this.datasetProfileManager = datasetProfileManager; } public DatasetWizardModel mapPrefilledEntityToDatasetWizard(Map prefilledEntity, PrefillingGet prefillingGet, String type, DescriptionTemplateEntity profile, DatasetManager datasetManager /*, LicenseManager licenseManager*/) throws Exception { DatasetWizardModel datasetWizardModel = new DatasetWizardModel(); datasetWizardModel.setProfile(new DatasetProfileOverviewModel().fromDataModel(profile)); DescriptionEntity descriptionEntity = new DescriptionEntity(); //descriptionEntity.setDescriptionTemplateId(profile.getId()); //TODO Map properties = new HashMap<>(); JsonNode parentNode = mapper.readTree(mapper.writeValueAsString(datasetManager.getPagedProfile(datasetWizardModel, descriptionEntity))); for (DefaultPrefillingMapping prefillingMapping: prefillingGet.getMappings()) { List sourceKeys = Arrays.asList(prefillingMapping.getSource().split("\\.")); Object sourceValue = null; for (String sourceKey: sourceKeys) { if (sourceValue == null) { sourceValue = prefilledEntity.get(sourceKey); } else if (sourceValue instanceof Map) { sourceValue = ((Map)sourceValue).get(sourceKey); } } try { setValue(prefillingMapping, mapper.writeValueAsString(sourceValue), datasetWizardModel, parentNode, properties, type/*, licenseManager*/); } catch (Exception e) { if (prefillingMapping.getSemanticTarget() != null && !prefillingMapping.getSemanticTarget().isEmpty()) { logger.warn("Couldn't map " + prefillingMapping.getSemanticTarget()); } else if (prefillingMapping.getTarget() != null && !prefillingMapping.getTarget().isEmpty()) { logger.warn("Couldn't map " + prefillingMapping.getTarget()); } } } for (PrefillingFixedMapping fixedMapping: prefillingGet.getFixedMappings()) { setValue(fixedMapping, fixedMapping.getValue(), datasetWizardModel, parentNode, properties, type/*, licenseManager*/); } descriptionEntity.setProperties(mapper.writeValueAsString(properties)); datasetWizardModel.setDatasetProfileDefinition(datasetManager.getPagedProfile(datasetWizardModel, descriptionEntity)); return datasetWizardModel; } private void setValue(PrefillingMapping prefillingMapping, String value, DatasetWizardModel datasetWizardModel, JsonNode parentNode, Map properties, String type/*, LicenseManager licenseManager*/) throws InvocationTargetException, IllegalAccessException, JsonProcessingException { String trimRegex = prefillingMapping.getTrimRegex() != null ? prefillingMapping.getTrimRegex() : ""; if (!value.startsWith("\"") && !value.startsWith("[") && !value.equals("null")) { value = "\"" + value + "\""; } JsonNode valueNode = mapper.readTree(value); List parsedValues = new ArrayList<>(); if (valueNode.isArray() && (valueNode.get(0) != null && !valueNode.get(0).isTextual())) { if (prefillingMapping.getSubSource() == null || prefillingMapping.getSubSource().isEmpty()) { throw new IllegalArgumentException("Source value is an array but no subSource field have been set"); } String parsedValue; for(int i = 0; i < valueNode.size(); i++){ JsonNode jsonObj = valueNode.get(i); String subSource = jsonObj.get(prefillingMapping.getSubSource()).asText(); parsedValue = subSource.replaceAll(trimRegex, ""); parsedValues.add(parsedValue); } parsedValues = parsedValues.stream().distinct().collect(Collectors.toList()); } String parsedValue = null; if (valueNode.isTextual()) { parsedValue = valueNode.textValue().replace(trimRegex, ""); }else if (valueNode.isArray() && (valueNode.get(0) != null && valueNode.get(0).isTextual())) { List values = new LinkedList<>(); for (int i = 0; i < valueNode.size(); i++) { values.add(valueNode.get(i).textValue().replace(trimRegex, "")); } parsedValue = String.join(", ", values); } if (prefillingMapping.getTarget() != null) { try { String methodName = "set" + prefillingMapping.getTarget().substring(0, 1).toUpperCase(Locale.ROOT) + prefillingMapping.getTarget().substring(1); Method setterMethod = Arrays.stream(DatasetWizardModel.class.getDeclaredMethods()) .filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()).get(0); Class[] params = setterMethod.getParameterTypes(); //GK: Tags Special logic if (parsedValue != null && !parsedValue.equals("null") && prefillingMapping.getTarget().equals("tags")) { parsedValue = mapper.valueToTree(parseTags(parsedValue)).toString(); } else if(!parsedValues.isEmpty() && prefillingMapping.getTarget().equals("tags")) { parsedValue = mapper.valueToTree(parseTags(String.join(", ", parsedValues))).toString(); } else { parsedValue = mapper.valueToTree(parsedValue).toString(); } setterMethod.invoke(datasetWizardModel, mapper.readValue(parsedValue, params[0])); }catch (InvocationTargetException | IllegalAccessException | JsonProcessingException e) { throw e; } } else { List nodes = JsonSearcher.findNodes(parentNode, "schematics", prefillingMapping.getSemanticTarget()); // zenodo prefilling customizations if(type.equals("zenodo")){ if(prefillingMapping.getSemanticTarget().equals("rda.dataset.distribution.data_access")){ if(parsedValue != null && parsedValue.equals("open")){ List issuedNodes = JsonSearcher.findNodes(parentNode, "schematics", "rda.dataset.issued"); if(!issuedNodes.isEmpty()){ String issuedIdNode = issuedNodes.get(0).get("id").asText(); String issuedValue = (String) properties.get(issuedIdNode); List licStartDateNodes = JsonSearcher.findNodes(parentNode, "schematics", "rda.dataset.distribution.license.start_date"); for (JsonNode licStartDateNode : licStartDateNodes) { String licStartDateId = licStartDateNode.get(0) != null ? licStartDateNode.get(0).get("id").asText() : licStartDateNode.get("id").asText(); properties.put(licStartDateId, issuedValue); } } } } if (prefillingMapping.getSemanticTarget().equals("rda.dataset.distribution.available_until") && parsedValue != null && !parsedValue.equals("null")) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd"); LocalDate date = LocalDate.parse(parsedValue, formatter); date = date.plusYears(20); parsedValue = date.toString(); } } for (JsonNode node: nodes) { String id = node.isArray() ? node.get(0).get("id").asText() : node.get("id").asText(); String renderStyle = node.isArray() ? node.get(0).get("viewStyle").get("renderStyle").asText() : node.get("viewStyle").get("renderStyle").asText(); switch (FieldType.of(renderStyle)) { case COMBO_BOX: if (parsedValues.isEmpty()) parsedValues.add(parsedValue); if (!parsedValues.stream().allMatch(Objects::isNull)) { properties.put(id, parseComboBoxValues(node, parsedValues)); } break; case TAGS: if(parsedValues.isEmpty()) { properties.put(id, mapper.valueToTree(parseTags(parsedValue)).toString()); } else { properties.put(id, mapper.valueToTree(parseTags(String.join(", ", parsedValues))).toString()); } break; case DATASET_IDENTIFIER: JSONObject datasetID = new JSONObject(); datasetID.put("identifier", parsedValue); if(type.equals("zenodo")){ datasetID.put("type", "doi"); } properties.put(id, datasetID.toString()); break; case LICENSES: // try { // List licenses = licenseManager.getLicenses("", ""); // String finalParsedValue = parsedValue; // licenses = licenses.stream().filter(license -> license.getPid().equals(finalParsedValue)).collect(Collectors.toList()); // boolean isMultiAutocomplete = node.isArray() ? node.get(0).get("data").get("multiAutoComplete").booleanValue() : node.get("data").get("multiAutoComplete").booleanValue(); // if(isMultiAutocomplete){ // List lic = new ArrayList<>(); // for(LicenseModel license: licenses){ // lic.add(mapper.writeValueAsString(license)); // } // properties.put(id, mapper.writeValueAsString(lic)); // } else { // properties.put(id, mapper.writeValueAsString(licenses.get(0))); // } // } // catch (MyNotFoundException | HugeResultSetException e){ // properties.put(id, parsedValue); // } break; default: if (!parsedValues.isEmpty()) properties.put(id, String.join(", ", parsedValues)); else { properties.put(id, parsedValue); } break; } } } } private Object parseComboBoxValues(JsonNode node, List parsedValues) throws JsonProcessingException { List normalizedValues = new ArrayList<>(); boolean isMultiSelect; String type = node.isArray() ? node.get(0).get("data").get("type").asText() : node.get("data").get("type").asText(); if(type.equals("autocomplete")) { JsonNode dataNode = node.isArray() ? node.get(0).get("data") : node.get("data"); AutoCompleteDataEntity autoCompleteDataEntity = mapper.treeToValue(dataNode, AutoCompleteDataEntity.class); isMultiSelect = autoCompleteDataEntity.getMultiAutoComplete(); for (String format : parsedValues) { List result = new ArrayList<>(); try { result = datasetProfileManager.getAutocomplete(autoCompleteDataEntity, format); } catch (Exception e) { logger.error(e.getMessage(), e); } result = result.stream().filter(StreamDistinctBy.distinctByKey(ExternalAutocompleteFieldResult::getId)).collect(Collectors.toList()); if(!result.isEmpty()){ List tempValues = new LinkedList<>(); for (ExternalAutocompleteFieldResult f : result) { if (format.equals(f.getId()) || f.getLabel().toUpperCase(Locale.ROOT).contains(format.toUpperCase(Locale.ROOT))) tempValues.add(mapper.valueToTree(f).toString()); } if (isMultiSelect) normalizedValues.addAll(tempValues); else if (!tempValues.isEmpty()) normalizedValues.add(tempValues.get(0)); } } return !normalizedValues.isEmpty() ? (isMultiSelect ? normalizedValues : normalizedValues.get(0)) : null; } else { JsonNode optionsNode = node.isArray() ? node.get(0).get("data").get("options") : node.get("data").get("options"); isMultiSelect = node.isArray() ? node.get(0).get("data").get("multiList").booleanValue() : node.get("data").get("multiList").booleanValue(); for (int i = 0; i < optionsNode.size(); i++) { String value = optionsNode.get(i).get("value").textValue(); if (parsedValues.contains(value)) { normalizedValues.add(value); } } List normalizedStringValues = normalizedValues.stream().map(Object::toString).collect(Collectors.toList()); return !normalizedValues.isEmpty() ? (isMultiSelect ? String.join(", ", normalizedStringValues) : normalizedValues.get(0)) : null; } } private static List parseTags(String value) throws JsonProcessingException { if (value == null || value.isEmpty()) return new LinkedList<>(); String[] rawTags = value.split(", "); List parsedTags = new LinkedList<>(); for (String rawTag : rawTags) { parsedTags.add(new TagEntity()); } return parsedTags; } }