/* * Copyright 2015-2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.hawkular.inventory.json; import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import org.hawkular.inventory.api.model.Entity; import org.hawkular.inventory.api.model.InventoryStructure; import com.fasterxml.jackson.core.JsonLocation; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; /** * @author Lukas Krejci * @since 0.15.0 */ public class InventoryStructureDeserializer extends JsonDeserializer<InventoryStructure.Offline<?>> { public static final String LEGAL_ENTITY_TYPES = Stream.of(InventoryStructure.EntityType.values()) .map(Enum::name) .collect(Collectors.joining("', '", "'", "'")); @Override public InventoryStructure.Offline<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { JsonNode tree = jsonParser.readValueAsTree(); if (tree == null) { throw new JsonParseException("Inventory structure expected but got nothing.", jsonParser.getCurrentLocation()); } JsonToken token = tree.asToken(); if (token != JsonToken.START_OBJECT) { throw new JsonParseException("Expected object but got " + token.asString(), JsonLocation.NA); } JsonNode typeNode = tree.get("type"); if (!typeNode.isTextual()) { throw new JsonParseException("'type' must be a text", JsonLocation.NA); } String typeName = typeNode.textValue(); InventoryStructure.EntityType type; try { type = InventoryStructure.EntityType.valueOf(typeName); } catch (IllegalArgumentException e) { throw new JsonParseException("Unrecognized value of 'type'. Supported values are " + LEGAL_ENTITY_TYPES + " but got '" + typeName + "'.", JsonLocation.NA); } Entity.Blueprint root = deserializationContext.readValue( prepareTraverse(tree.get("data"), deserializationContext), type.blueprintType); InventoryStructure.Builder bld = InventoryStructure.Offline.of(root); parseChildren(tree, bld, deserializationContext); return bld.build(); } private void parseChildren(JsonNode root, InventoryStructure.AbstractBuilder<?> bld, DeserializationContext mapper) throws IOException { JsonNode children = root.get("children"); if (children == null) { return; } if (!children.isObject()) { throw new JsonParseException("The 'children' is supposed to be an object.", JsonLocation.NA); } else { Iterator<Map.Entry<String, JsonNode>> fields = children.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> e = fields.next(); String typeName = e.getKey(); JsonNode childrenNode = e.getValue(); if (!childrenNode.isArray()) { continue; } InventoryStructure.EntityType type; try { type = InventoryStructure.EntityType.valueOf(typeName); } catch (IllegalArgumentException ex) { throw new JsonParseException("Unrecognized value of 'type'. Supported values are " + LEGAL_ENTITY_TYPES + " but got '" + typeName + "'.", JsonLocation.NA); } Iterator<JsonNode> childrenNodes = childrenNode.elements(); while (childrenNodes.hasNext()) { JsonNode childNode = childrenNodes.next(); Entity.Blueprint bl = mapper.readValue(prepareTraverse(childNode.get("data"), mapper), type.blueprintType); InventoryStructure.ChildBuilder<?> childBld = bld.startChild(bl); parseChildren(childNode, childBld, mapper); childBld.end(); } } } } private static JsonParser prepareTraverse(JsonNode node, DeserializationContext ctx) throws IOException { JsonParser parser = node.traverse(ctx.getParser().getCodec()); parser.nextToken(); return parser; } }