All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.uniroma2.art.sheet2rdf.cfg.GraphApplicationConfigurationParser Maven / Gradle / Ivy

The newest version!
package it.uniroma2.art.sheet2rdf.cfg;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import it.uniroma2.art.coda.interfaces.annotations.converters.RDFCapabilityType;
import it.uniroma2.art.sheet2rdf.coda.CODAConverter;
import it.uniroma2.art.sheet2rdf.header.AdvancedGraphApplication;
import it.uniroma2.art.sheet2rdf.header.NodeConversion;
import it.uniroma2.art.sheet2rdf.header.NodeMemoization;
import it.uniroma2.art.sheet2rdf.header.NodeSanitization;
import it.uniroma2.art.sheet2rdf.utils.JsonConstants;
import it.uniroma2.art.sheet2rdf.utils.S2RDFUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.rio.helpers.NTriplesUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class GraphApplicationConfigurationParser {
	
	private final ObjectNode cfgJson;
	private final ObjectMapper mapper;
	private final String placeholderPrefix; //prefix for appending the node Ids used in the configuration
	
	private final Map nodeIdReplacementMap;
	
	public GraphApplicationConfigurationParser(ObjectNode cfgJson, String placeholderPrefix) {
		this.cfgJson = cfgJson;
		mapper = new ObjectMapper();
		this.placeholderPrefix = placeholderPrefix;
		nodeIdReplacementMap = new HashMap<>();
	}

	/**
	 * Creates and returns the list of NodeConversion contained in the configuration JSON object
	 * @return
	 */
	public List getNodeConversions() {
		JsonNode nodesJson = cfgJson.get("nodes");
		List nodes = new ArrayList<>();
		for (int i = 0; i < nodesJson.size(); i++) {
			NodeConversion node = new NodeConversion();
			JsonNode nodeJson = nodesJson.get(i);
			//id
			String nodeId = nodeJson.get("nodeId").asText();
			String prefixedNodeId = placeholderPrefix + "_" + nodeId;
			nodeIdReplacementMap.put(nodeId, prefixedNodeId);
			node.setNodeId(prefixedNodeId);
			//converter
			CODAConverter converter = new CODAConverter();
			JsonNode converterJson = nodeJson.get("converter");
			converter.setType(RDFCapabilityType.valueOf(converterJson.get("type").asText()));
			converter.setContractUri(converterJson.get("contractUri").asText());
			JsonNode langJson = converterJson.get("language");
			if (!langJson.isNull()) {
				converter.setLanguage(langJson.asText());
			}
			JsonNode dtUriJson = converterJson.get("datatypeUri");
			if (!dtUriJson.isNull()) {
				converter.setDatatypeUri(dtUriJson.asText());
			}
			JsonNode paramsJson = converterJson.get("params"); 
			Map paramsMap = mapper.convertValue(paramsJson, new TypeReference>(){});
			Map params = resolveConverterParamsMap(paramsMap);
			//set the params as it is in the configuration file. The node id references will be replaced later
			converter.setParams(params);
			node.setConverter(converter);
			//memoize
			node.setMemoization(mapper.convertValue(nodeJson.get("memoization"), NodeMemoization.class));
			JsonNode sanitizationNode = nodeJson.get("sanitization");
			if (sanitizationNode != null) {
				node.setSanitization(mapper.convertValue(sanitizationNode, NodeSanitization.class));
			}

			nodes.add(node);
		}
		//parameters replaced after each node has been copied, so the nodeIdReplacementMap is complete
		for (NodeConversion n: nodes) {
			CODAConverter converter = n.getConverter();
			Map replacedParamMap = S2RDFUtils.replaceNodesIdInConverterParams(converter.getParams(), nodeIdReplacementMap);
			converter.setParams(replacedParamMap);
		}
		return nodes;
	}
	
	/**
	 * Creates and returns the AdvancedGraphApplication contained in the configuration JSON object
	 * @param nodes nodes referenced in the graph pattern (they should be already parsed in getNodeConversion, so provided from outside)
	 * @return
	 */
	public AdvancedGraphApplication getAdvancedGraphApplication(List nodes, IRI headerPredicate) {
		AdvancedGraphApplication g = new AdvancedGraphApplication();
		
		//prefix mapping
		JsonNode prefixMappingJson = cfgJson.get(JsonConstants.ADVANCED_GRAPH_APPLICATION_PREFIX_MAPPING);
		Map prefixMapping = mapper.convertValue(prefixMappingJson, new TypeReference>(){});
		g.setPrefixMapping(prefixMapping);
		//graph pattern
		JsonNode graphPatternJson = cfgJson.get(JsonConstants.ADVANCED_GRAPH_APPLICATION_PATTERN);
		String graphPattern = graphPatternJson.asText();
		String prefixedGraphPattern = S2RDFUtils.replaceNodesIdInGraphPattern(graphPattern, nodeIdReplacementMap);
		g.setPattern(prefixedGraphPattern);
		//referenced nodes ID
		List nodeIds = new ArrayList<>();
		for (NodeConversion n: nodes) {
			nodeIds.add(n.getNodeId()); 
		}
		g.setNodeIds(nodeIds);
		//default predicate
		JsonNode defaultPredJson = cfgJson.get(JsonConstants.ADVANCED_GRAPH_APPLICATION_DEFAULT_PREDICATE);
		if (defaultPredJson != null) {
			IRI defaultPred = NTriplesUtil.parseURI(defaultPredJson.asText(), SimpleValueFactory.getInstance());
			g.setDefaultPredicate(defaultPred);
		}
		return g;
	}
	
	/**
	 * The converter parameters object should be a map key-value where the key are string and the values could be:
	 * - String
	 * - List: (e.g args of TurtleCollection converter)
	 * 		actually it should be List but value can be represented by a rdf4j Value or by a nodeId (string).
	 * - Map (e.g. args parameter of random converter)
	 * 		actually it should be Map but value can be represented by a rdf4j Value or by a nodeId (string).
	 * 
	 * Unfortunately the Map, where Object could be a Map or a List, cannot be parsed, by a spring converter.
	 * So as a workaround I get a Map and here I manually parse the values.
	 */
	private Map resolveConverterParamsMap(Map convParamsMap) {
		Map resolvedConvParams = new LinkedHashMap<>();
		Iterator> itEntries = convParamsMap.entrySet().iterator();
		while (itEntries.hasNext()) {
			Entry entry = itEntries.next();
			Object value = entry.getValue();
			if (value instanceof Map) { //value is a map => convert it
				//resolve in turn the map value
				Map nestedResolvedMap = resolveConverterParamsMap((Map) value);
				resolvedConvParams.put(entry.getKey(), nestedResolvedMap);
			} else if (value instanceof List) { //value is a list
				ListvalueAsList = (List) value;
				//resolve in turn the list value
				List nestedResolvedList = new ArrayList<>();
				for (String v: valueAsList) {
					nestedResolvedList.add(parseStringOrValue(v));
				}
				resolvedConvParams.put(entry.getKey(), nestedResolvedList);
			} else if (value instanceof String) { //simple string or rdf4j Ntriples serialization?
				Object resolvedValue = parseStringOrValue((String) value);
				resolvedConvParams.put(entry.getKey(), resolvedValue);					
			}
		}
		return resolvedConvParams;
	}
	
	/**
	 * Try to parse a string as a rdf4j Value. If the parsing fails, returns it as a plain String.
	 * @param s
	 * @return
	 */
	private Object parseStringOrValue(String s) {
		try {
			return NTriplesUtil.parseValue(s, SimpleValueFactory.getInstance());
		} catch (IllegalArgumentException e) {
			return s;
		}
	}
	
	
	
}