com.reprezen.swagedit.model.Model.java Source code

Java tutorial

Introduction

Here is the source code for com.reprezen.swagedit.model.Model.java

Source

/*******************************************************************************
 * Copyright (c) 2016 ModelSolv, Inc. and others.
 * 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:
 *    ModelSolv, Inc. - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.reprezen.swagedit.model;

import static com.reprezen.swagedit.model.NodeDeserializer.ATTRIBUTE_MODEL;
import static com.reprezen.swagedit.model.NodeDeserializer.ATTRIBUTE_PARENT;
import static com.reprezen.swagedit.model.NodeDeserializer.ATTRIBUTE_POINTER;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;

import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.reprezen.swagedit.Activator;
import com.reprezen.swagedit.schema.SwaggerSchema;

/**
 * Represents the content of a YAML/JSON document.
 *
 */
public class Model {

    private final Map<JsonPointer, AbstractNode> nodes = new LinkedHashMap<>();
    private final SwaggerSchema schema;
    private IPath path;

    private Model(SwaggerSchema schema) {
        this(schema, null);
    }

    private Model(SwaggerSchema schema, IPath path) {
        this.schema = schema;
        this.path = path;
    }

    /**
     * Returns an empty model
     * 
     * @param schema
     * @return empty model
     */
    public static Model empty(SwaggerSchema schema) {
        Model model = new Model(schema);
        ObjectNode root = new ObjectNode(model, null, JsonPointer.compile(""));
        root.setType(model.schema.getType(root));
        model.add(root);

        return model;
    }

    /**
     * Returns a model build by parsing a YAML content.
     * 
     * @param text
     * @return model
     */
    public static Model parseYaml(SwaggerSchema schema, String text) {
        if (Strings.emptyToNull(text) == null) {
            return empty(schema);
        }

        Model model = new Model(schema);
        try {
            reader(model).readValue(text);
        } catch (IllegalArgumentException | IOException e) {
            e.printStackTrace();
        }

        for (AbstractNode node : model.allNodes()) {
            node.setType(model.schema.getType(node));
        }

        return model;
    }

    /**
     * Parses all files into a list of models.
     * 
     * @param files
     * @return list of models
     */
    public static Iterable<Model> parseYaml(Iterable<IFile> files) {
        if (files == null || Iterables.isEmpty(files)) {
            return Lists.newArrayList();
        }

        final SwaggerSchema schema = Activator.getDefault().getSchema();
        final List<Model> models = Lists.newArrayList();
        for (IFile file : files) {
            Model model = new Model(schema, file.getFullPath());
            try {
                reader(model).readValue(file.getLocationURI().toURL());
            } catch (IllegalArgumentException | IOException e) {
                e.printStackTrace();
                continue;
            }

            models.add(model);
        }
        return models;
    }

    protected static ObjectMapper createMapper() {
        final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        final SimpleModule module = new SimpleModule();
        module.addDeserializer(AbstractNode.class, new NodeDeserializer());
        mapper.registerModule(module);
        return mapper;
    }

    protected static ObjectReader reader(Model model) {
        return createMapper().reader() //
                .withAttribute(ATTRIBUTE_MODEL, model) //
                .withAttribute(ATTRIBUTE_PARENT, null) //
                .withAttribute(ATTRIBUTE_POINTER, JsonPointer.compile("")) //
                .withType(AbstractNode.class);
    }

    /**
     * Creates a new object node
     * 
     * @param node
     *            parent or null
     * @param node
     *            pointer
     * @return object node
     */
    public ObjectNode objectNode(AbstractNode parent, JsonPointer ptr) {
        return (ObjectNode) add(new ObjectNode(this, parent, ptr));
    }

    /**
     * Creates a new array node
     * 
     * @param node
     *            parent or null
     * @param node
     *            pointer
     * @return array node
     */
    public ArrayNode arrayNode(AbstractNode parent, JsonPointer ptr) {
        return (ArrayNode) add(new ArrayNode(this, parent, ptr));
    }

    /**
     * Creates a new value node
     * 
     * @param node
     *            parent or null
     * @param node
     *            pointer
     * @param node
     *            value
     * @return value node
     */
    public ValueNode valueNode(AbstractNode parent, JsonPointer ptr, Object value) {
        return (ValueNode) add(new ValueNode(this, parent, ptr, value));
    }

    /**
     * Returns the path of the file that contains the model content.
     * 
     * @param path
     */
    public IPath getPath() {
        return path;
    }

    public void setPath(IPath path) {
        this.path = path;
    }

    /**
     * Returns the node inside the model that can be
     * 
     * @param pointer
     * @return node
     */
    public AbstractNode find(JsonPointer pointer) {
        return nodes.get(pointer);
    }

    private AbstractNode add(AbstractNode node) {
        if (node != null && node.getPointer() != null) {
            nodes.put(node.getPointer(), node);
        }
        return node;
    }

    /**
     * Returns the model's root node.
     * 
     * @return node
     */
    public AbstractNode getRoot() {
        return nodes.get(JsonPointer.compile(""));
    }

    /**
     * Returns the pointer for the node whose content is at the position specified by a line and column.
     * 
     * @param line
     * @param column
     * @return
     */
    public JsonPointer getPath(int line, int column) {
        AbstractNode node = getNode(line, column);
        if (node != null) {
            return node.getPointer();
        }
        return JsonPointer.compile("");
    }

    /**
     * Returns the node whose content is at the position specified by a line and column.
     * 
     * @param line
     * @param column
     * @return
     */
    public AbstractNode getNode(int line, int column) {
        if (column == 0) {
            return getRoot();
        }

        AbstractNode found = forLine(line);
        if (found != null) {
            found = findChildren(found, line, column);
            int c = found.getStart().getColumn();
            if (column > c || (column == c && found.getParent().isArray())) {
                return found;
            } else {
                return found.getParent();
            }
        } else {
            found = findBeforeLine(line, column);
            if (found != null) {
                return findCorrectNode(found, column);
            }
        }

        return found;
    }

    /**
     * Returns all nodes within this model
     * 
     * @return iterable of nodes
     */
    public Iterable<AbstractNode> allNodes() {
        return nodes.values();
    }

    protected AbstractNode findChildren(AbstractNode current, int line, int column) {
        for (AbstractNode el : current.elements()) {
            if (el.getStart().getLine() == line) {
                if (el instanceof ValueNode) {
                    if (column >= contentColumn(el)) {
                        return el;
                    }
                } else {
                    if (column >= el.getStart().getColumn()) {
                        return el;
                    }
                }
            }
        }
        return current;
    }

    protected AbstractNode findCorrectNode(AbstractNode current, int column) {
        if (current.getStart().getColumn() == column) {
            if (current.getParent() instanceof ObjectNode) {
                return current.getParent();
            }
        }

        if (current.getStart().getColumn() < column) {
            return current;
        } else {
            return findCorrectNode(current.getParent(), column);
        }
    }

    protected AbstractNode forLine(int line) {
        final AbstractNode root = getRoot();
        for (AbstractNode node : allNodes()) {
            if (node != root && node.getStart().getLine() == line) {
                return node;
            }
        }
        return null;
    }

    protected AbstractNode findBeforeLine(int line, int column) {
        AbstractNode root = getRoot();
        AbstractNode found = null, before = null;
        Iterator<AbstractNode> it = allNodes().iterator();

        while (found == null && it.hasNext()) {
            AbstractNode current = it.next();
            if (root == current) {
                continue;
            }

            if (current.getStart().getLine() < line) {
                before = current;
            } else {
                found = before;
            }
        }

        if (found == null && before != null) {
            found = before;
        }

        return found;
    }

    protected int contentColumn(AbstractNode n) {
        String property = Strings.emptyToNull(n.getProperty());
        if (property == null) {
            return n.getStart().getColumn();
        }

        return (property.length() + 1) + n.getStart().getColumn();
    }

}