Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.regnosys.rosetta.translate.datamodel.json.CreateiQJsonSchemaParser Maven / Gradle / Ivy
package com.regnosys.rosetta.translate.datamodel.json;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.regnosys.rosetta.common.util.UrlUtils;
import com.regnosys.rosetta.translate.IngestException;
import com.regnosys.rosetta.translate.datamodel.Attribute;
import com.regnosys.rosetta.translate.datamodel.Entity;
import com.regnosys.rosetta.translate.datamodel.Schema;
/**
* TODO: This class has a lot of ISDA-Create specific logic in it, including hardcoding the
* enclosing ISDA Create JSON document (their schema only covers the answers section).
* Should be renamed, and any general code separated out.
*/
public class CreateiQJsonSchemaParser implements JsonSchemaParser {
private static final Logger LOG = Logger.getLogger(JsonSchemaParser.class);
private Map definitions;
@Override
public Schema parseModel(URL input) {
try {
ObjectMapper objectMapper = new ObjectMapper();
Map jsonMap = objectMapper.readValue(UrlUtils.openURL(input), new TypeReference>() {
});
List attributes = processMap(jsonMap);
Collection globalEntities = attributes.stream()
.map(a -> a.getType())
.collect(Collectors.toList());
//
return new Schema(attributes, globalEntities);
} catch (IOException e) {
throw new IngestException("Error when ingesting json", e);
}
}
@SuppressWarnings("unchecked")
List processMap(Map map) {
definitions = handleDefinitions(map);
List extends Object> children = tryGetChildren(map).orElseThrow(() -> new UnsupportedOperationException("No children or repeatChildren found"));
List allAttributes = new ArrayList<>(children.size());
for (Object child : children) {
// Assumption here : each one of these children is a Map which will become an Attribute
Map childMap = (Map) child;
Attribute firstLevelAttribute = constructAttributeTree(childMap, null).get();
allAttributes.add(firstLevelAttribute);
}
List root = new ArrayList<>();
root.add(new JsonAttribute("id", new JsonEntity("id", "string")));
root.add(createPartyAttribute("partyA"));
root.add(createPartyAttribute("partyB"));
root.add(createDocAttribute());
List partyAnswersAttributes = new ArrayList<>(2);
partyAnswersAttributes.add(new JsonAttribute("partyA", new JsonEntity("partyA", "#partyAnswers", allAttributes)));
partyAnswersAttributes.add(new JsonAttribute("partyB", new JsonEntity("partyB", "#partyAnswers", allAttributes)));
JsonEntity answers = new JsonEntity("answers", "container", partyAnswersAttributes);
root.add(new JsonAttribute("answers", answers));
return root;
}
// Manual step for now the document {} segment with 5 attributes
private Attribute createDocAttribute() {
Attribute idAttr = new JsonAttribute("id", new JsonEntity("id", "string"));
Attribute docYearAttr = new JsonAttribute("year", new JsonEntity("year", "integer"));
Attribute docTypeAttr = new JsonAttribute("documentType", new JsonEntity("documentType", "string"));
Attribute docGovLawAttr = new JsonAttribute("governingLaw", new JsonEntity("governingLaw", "string"));
Attribute docAbbreviationAttr = new JsonAttribute("abbreviation", new JsonEntity("abbreviation", "string"));
Attribute docDescriptionAttr = new JsonAttribute("description", new JsonEntity("description", "string"));
Attribute docPublisherAttr = new JsonAttribute("publisher", new JsonEntity("publisher", "string"));
Attribute hasSchemaAttr = new JsonAttribute("hasSchema", new JsonEntity("hasSchema", "boolean"));
Attribute docVersionAttr = new JsonAttribute("version", new JsonEntity("version", "string"));
return new JsonAttribute("document",
new JsonEntity("document", "container",
Lists.newArrayList(idAttr, docYearAttr, docTypeAttr, docGovLawAttr, docAbbreviationAttr, docDescriptionAttr, docPublisherAttr, hasSchemaAttr, docVersionAttr)));
}
private Attribute createPartyAttribute(String party) {
List entityAttributes = Arrays.asList(
new JsonAttribute("id", new JsonEntity("id", "string")),
new JsonAttribute("name", new JsonEntity("name", "string")));
Attribute entityAttr = new JsonAttribute("entity", new JsonEntity("entity", "container", entityAttributes));
List accountAttributes = Arrays.asList(
new JsonAttribute("id", new JsonEntity("id", "string")),
new JsonAttribute("name", new JsonEntity("name", "string")));
Attribute accountAttr = new JsonAttribute("account", new JsonEntity("account", "container", accountAttributes));
return new JsonAttribute(party, new JsonEntity(party, "container", Arrays.asList(entityAttr, accountAttr)));
}
@SuppressWarnings("unchecked")
private Optional constructAttributeTree(Map childMap, final Entity current) {
if (childMap.containsKey("name")) {
String propertyName = getName(childMap);
String propertyType = getType(childMap);
Entity entity = constructEntity(propertyName, propertyType);
// sub-case
if ("radio".equals(propertyType)) {
// should contain options if it is radio
List extends Object> options = (List extends Object>) childMap.get("options");
for(Object option : options) {
// Assumption: element is a map
Map optionMap = (Map) option;
if (optionMap.containsKey("children")) {
Optional> children = tryGetChildren(optionMap);
if (children.isPresent()) {
// radio options are flattened to the same level
Entity newCurrent = current == null ? entity : current;
for (Object child : children.get()) {
Optional attr = constructAttributeTree((Map) child, newCurrent);
if (attr.isPresent()) {
newCurrent.addAttribute(attr.get());
}
}
}
}
}
}
Optional> children = tryGetChildren(childMap);
if (children.isPresent()) {
// Assumption here : that children is an ArrayList
for (Object child : children.get()) {
if (isMap(child)) {
Optional attr = constructAttributeTree((Map) child, entity);
if (attr.isPresent()) {
entity.addAttribute(attr.get());
}
}
// sometimes it is a list - one level
else if (isList(child)) {
for (Object innerItem : (List extends Object>) child) {
if (isMap(innerItem)) {
Optional attr = constructAttributeTree((Map) innerItem, entity);
if (attr.isPresent()) {
entity.addAttribute(attr.get());
}
}
// sometimes it is a 2 -level list - two levels
else if (isList(innerItem)) {
List extends Object> innerList = (List extends Object>) innerItem;
for (Object obj : innerList) {
// Assumption: always a map here
Optional attr = constructAttributeTree((Map) obj, entity);
if (attr.isPresent()) {
entity.addAttribute(attr.get());
}
}
}
}
}
}
return Optional.of(new JsonAttribute(propertyName, entity));
}
// end of recursion
return Optional.of(new JsonAttribute(propertyName, entity));
} else if ("group".equals(childMap.get("type"))) {
// handling the cases where there is no child with name but there is a "group" type that contains children with "name"
Entity newCurrent = current;
// 1st assumption here : only one or two levels down group types!
Optional> children = tryGetChildren(childMap);
if (children.isPresent()) {
for (Object groupM : children.get()) {
if (isMap(groupM)) {
Optional attr = constructAttributeTree((Map) groupM, newCurrent);
if (attr.isPresent()) {
newCurrent.addAttribute(attr.get());
}
}
// sometimes it is a list - two levels
else if (isList(groupM)) {
List extends Object> innerList = (List extends Object>) groupM;
for (Object obj : innerList) {
// Assumption: always a map here
Optional attr = constructAttributeTree((Map) obj, newCurrent);
if (attr.isPresent()) {
newCurrent.addAttribute(attr.get());
}
}
}
}
}
} else if (childMap.containsKey("$ref")) {
// no "name" property , but a "$ref" property... only happens in "group" types
String refname = (String) childMap.get("$ref");
Entity refEntity = new JsonEntity((JsonEntity) definitions.get(refname));
refEntity.getAttributes()
.forEach(a -> current.addAttribute(a));
}
return Optional.empty();
}
private Entity constructEntity(String propertyName, String propertyType) {
if (propertyType.startsWith("#")) {
// use predefined type
JsonEntity otherEntity = (JsonEntity) definitions.get(propertyType);
List attributes = getContainerEntityAttributes(otherEntity);
return new JsonEntity(propertyName, propertyType, attributes);
}
return new JsonEntity(propertyName, propertyType);
}
private List getContainerEntityAttributes(JsonEntity otherEntity) {
// a definition entity has exactly one root attribute,grab all the contained attributes
assert otherEntity.getType()
.equals("definition");
return otherEntity.getAttributes()
.get(0)
.getType()
.getAttributes();
}
private Optional> tryGetChildren(Map childMap) {
Object children = null;
if (childMap.containsKey("children")) {
children = childMap.get("children");
} else if (childMap.containsKey("repeatChildren")) {
children = childMap.get("repeatChildren");
}
return Optional.ofNullable(children).map(this::toList);
}
/**
* If children is just one child then wrap it in a list.
*/
private List> toList(Object children) {
if (children instanceof LinkedHashMap) {
return Arrays.asList(children);
} else if (children instanceof List) {
return (List>) children;
} else {
throw new UnsupportedOperationException("Children contains unexpected type [%s]" + children.getClass());
}
}
@SuppressWarnings("unchecked")
Map handleDefinitions(Map map) {
Map definedTypes = new LinkedHashMap<>();
if (map.containsKey("definitions")) {
// Assumption here : first level definitions is always a Map (vs a List on children)
for (Entry def : ((Map) map.get("definitions")).entrySet()) {
String propertyName = def.getKey();
// set up the map so can reuse the children-parsing code
if (isMap(def.getValue())) {
Map actual = (Map) def.getValue();
// if no name specified, sets a default name to create a 'dummy' container attribute and kick-off the process
if (!actual.containsKey("name")) {
actual.put("name", propertyName);
}
JsonEntity entity = new JsonEntity(propertyName, "definition");
definedTypes.put("#" + propertyName, entity);
Optional attr = constructAttributeTree(actual, entity);
if (attr.isPresent()) {
entity.addAttribute(attr.get());
}
} else {
LOG.debug("Definition [ " + propertyName + " ] contains a List. Ignoring atm.");
}
}
}
return flattenAnyDoublyContained(definedTypes);
}
private Map flattenAnyDoublyContained(Map definedTypes) {
Set> entrySet = definedTypes.entrySet();
for (Entry entry : entrySet) {
Entity containerEntity = entry.getValue();
String containerName = containerEntity.getName()
.getName();
if (containerEntity.getAttributes()
.size() == 1) {
Attribute attribute = containerEntity.getAttributes()
.get(0);
// TODO revisit this : flatten - awfully ugly
if (attribute.getName()
.equals(containerName)
&& containerName.startsWith("17")) {
entry.setValue(attribute.getType());
}
}
}
return definedTypes;
}
@SuppressWarnings("unchecked")
private String getName(Map map) {
if (map.containsKey("name")) {
Object nameC = map.get("name");
if (nameC instanceof String) {
return (String) nameC;
}
if (isMap(nameC)) {
Map nameMap = (Map) nameC;
if (nameMap.containsKey("position") && nameMap.containsKey("suffix")) {
return ((String) nameMap.get("position") + (String) nameMap.get("suffix"));
}
}
}
throw new UnsupportedOperationException("map does not contain 'name' property");
}
private String getType(Map childMap) {
if (childMap.containsKey("type")) {
return (String) childMap.get("type");
} else if (childMap.containsKey("$ref")) {
return (String) childMap.get("$ref");
}
throw new UnsupportedOperationException("child map does not contain 'type' or '$ref' property");
}
private boolean isMap(Object obj) {
return obj instanceof Map, ?>;
}
private boolean isList(Object obj) {
return obj instanceof List>;
}
}