org.bndtools.rt.repository.marshall.CapReqJson.java Source code

Java tutorial

Introduction

Here is the source code for org.bndtools.rt.repository.marshall.CapReqJson.java

Source

/*******************************************************************************
 * Copyright (c) 2012 Neil Bartlett.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Neil Bartlett - initial API and implementation
 ******************************************************************************/
package org.bndtools.rt.repository.marshall;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.osgi.framework.Version;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;

import aQute.lib.io.IO;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public final class CapReqJson {

    public static void writeRequirementArray(Collection<? extends Requirement> requirements,
            JsonGenerator generator) throws IOException {
        generator.writeStartArray();
        for (Requirement req : requirements) {
            writeRequirement(req, generator);
        }
        generator.writeEndArray();
    }

    public static void writeCapabilityArray(Collection<? extends Capability> capabilities, JsonGenerator generator)
            throws IOException {
        generator.writeStartArray();
        for (Capability cap : capabilities) {
            writeCapability(cap, generator);
        }
        generator.writeEndArray();
    }

    public static void writeRequirement(Requirement requirement, JsonGenerator generator) throws IOException {
        generator.writeStartObject();
        generator.writeStringField("ns", requirement.getNamespace());

        Map<String, Object> attrs = requirement.getAttributes();
        if (!attrs.isEmpty()) {
            generator.writeArrayFieldStart("attrs");
            for (Entry<String, Object> entry : attrs.entrySet()) {
                writeAttribute(entry.getKey(), entry.getValue(), generator);
            }
            generator.writeEndArray();
        }

        Map<String, String> dirs = requirement.getDirectives();
        if (!dirs.isEmpty()) {
            generator.writeArrayFieldStart("dirs");
            for (Entry<String, String> entry : dirs.entrySet()) {
                writeDirective(entry.getKey(), entry.getValue(), generator);
            }
            generator.writeEndArray();
        }

        generator.writeEndObject();
    }

    public static void writeCapability(Capability capability, JsonGenerator generator) throws IOException {
        generator.writeStartObject();
        generator.writeStringField("ns", capability.getNamespace());

        Map<String, Object> attrs = capability.getAttributes();
        if (!attrs.isEmpty()) {
            generator.writeArrayFieldStart("attrs");
            for (Entry<String, Object> entry : attrs.entrySet()) {
                writeAttribute(entry.getKey(), entry.getValue(), generator);
            }
            generator.writeEndArray();
        }

        Map<String, String> dirs = capability.getDirectives();
        if (!dirs.isEmpty()) {
            generator.writeArrayFieldStart("dirs");
            for (Entry<String, String> entry : dirs.entrySet()) {
                writeDirective(entry.getKey(), entry.getValue(), generator);
            }
            generator.writeEndArray();
        }

        generator.writeEndObject();
    }

    public static void writeProviderArray(Map<Requirement, Collection<Capability>> providers,
            JsonGenerator generator) throws IOException {
        generator.writeStartArray();

        for (Entry<Requirement, Collection<Capability>> provider : providers.entrySet()) {
            generator.writeStartObject();

            generator.writeFieldName("req");
            writeRequirement(provider.getKey(), generator);

            generator.writeFieldName("providers");
            writeCapabilityArray(provider.getValue(), generator);

            generator.writeEndObject();
        }

        generator.writeEndArray();
    }

    private static void writeAttribute(String key, Object value, JsonGenerator generator) throws IOException {
        generator.writeStartObject();
        generator.writeStringField("name", key);
        if (value instanceof Version) {
            generator.writeStringField("value", value.toString());
            generator.writeStringField("type", "Version");
        } else if (value instanceof Double || value instanceof Float) {
            generator.writeStringField("value", value.toString());
            generator.writeStringField("type", "Double");
        } else if (value instanceof Long || value instanceof Integer) {
            generator.writeStringField("value", value.toString());
            generator.writeStringField("type", "Long");
        } else if (value instanceof String) {
            generator.writeStringField("value", (String) value);
        } else if (value == null) {
            throw new IOException("null values not supported");
        } else {
            throw new IOException("Unsupported value type " + value.getClass());
        }
        generator.writeEndObject();
    }

    private static void writeDirective(String key, String value, JsonGenerator generator) throws IOException {
        generator.writeStartObject();
        generator.writeStringField("name", key);
        generator.writeStringField("value", value);
        generator.writeEndObject();
    }

    public static List<Requirement> parseRequirements(JsonFactory jf, InputStream stream) throws IOException {
        List<Requirement> result;

        String collect = IO.collect(stream);
        JsonNode rootNode = new ObjectMapper(jf).readTree(collect);
        if (rootNode.isArray()) {
            result = new LinkedList<Requirement>();
            for (JsonNode reqNode : rootNode) {
                result.add(parseCapReq(reqNode).buildSyntheticRequirement());
            }
        } else if (rootNode.isObject()) {
            result = Collections.singletonList(parseCapReq(rootNode).buildRequirement());
        } else {
            throw new IllegalAccessError("JSON data is neither an Array nor an Object");
        }

        return result;
    }

    private static CapReqBuilder parseCapReq(JsonNode reqNode) throws IllegalArgumentException {
        String namespace = getRequiredField(reqNode, "ns").asText();
        CapReqBuilder builder = new CapReqBuilder(namespace);

        JsonNode dirsNode = reqNode.get("dirs");
        if (dirsNode != null) {
            if (dirsNode.isArray()) {
                for (JsonNode dirNode : dirsNode) {
                    toDirective(builder, dirNode);
                }
            } else if (dirsNode.isObject()) {
                toDirective(builder, dirsNode);
            } else {
                throw new IllegalAccessError("Value of 'dirs' node is neither an Array or an Object.");
            }
        }

        JsonNode attrsNode = reqNode.get("attrs");
        if (attrsNode != null) {
            if (attrsNode.isArray()) {
                for (JsonNode attrNode : attrsNode) {
                    toAttribute(builder, attrNode);
                }
            } else if (attrsNode.isObject()) {
                toAttribute(builder, attrsNode);
            } else {
                throw new IllegalAccessError("Value of 'attrs' node is neither an Array or an Object.");
            }
        }

        return builder;
    }

    private static void toDirective(CapReqBuilder builder, JsonNode dirNode) {
        String name = getRequiredValueField(dirNode, "name").asText();
        String value = getRequiredValueField(dirNode, "value").asText();

        builder.addDirective(name, value);
    }

    private static void toAttribute(CapReqBuilder builder, JsonNode attrNode) throws IllegalArgumentException {
        String name = getRequiredValueField(attrNode, "name").asText();
        Object value;
        JsonNode valueNode = getRequiredValueField(attrNode, "value");

        JsonNode typeNode = attrNode.get("type");
        AttributeType type = AttributeType.DEFAULT;
        if (typeNode != null) {
            String typeName = typeNode.asText();
            type = AttributeType.parseTypeName(typeName);
        }

        if (valueNode.isFloatingPointNumber()) {
            if (typeNode == null || type.equals(AttributeType.DOUBLE))
                value = valueNode.asDouble();
            else
                throw new IllegalArgumentException(String
                        .format("JSON type for value is floating point, does not match declared type '%s'", type));
        } else if (valueNode.isIntegralNumber()) {
            if (typeNode == null || type.equals(AttributeType.LONG))
                value = valueNode.asLong();
            else if (type.equals(AttributeType.DOUBLE))
                value = valueNode.asDouble();
            else
                throw new IllegalArgumentException(
                        String.format("JSON type for value is integral, does not match declared type '%s'", type));
        } else if (valueNode.isTextual()) {
            String valueStr = valueNode.asText();
            value = type.parseString(valueStr);
        } else {
            throw new IllegalArgumentException("JSON value node is not a recognised type");
        }

        builder.addAttribute(name, value);
    }

    private static JsonNode getRequiredField(JsonNode node, String fieldName) throws IllegalArgumentException {
        JsonNode child = node.get(fieldName);
        if (child == null)
            throw new IllegalArgumentException(String.format("Missing required field '%s'", fieldName));
        return child;
    }

    private static JsonNode getRequiredValueField(JsonNode node, String fieldName) {
        JsonNode valueNode = getRequiredField(node, fieldName);
        if (!valueNode.isValueNode())
            throw new IllegalArgumentException(
                    String.format("Field '%s' is required to be a value field.", fieldName));
        return valueNode;
    }
}