org.apache.giraph.debugger.mock.TestGraphGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.giraph.debugger.mock.TestGraphGenerator.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.giraph.debugger.mock;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Writable;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

/**
 * The code generator to generate the end-to-end test case.
 *
 * author Brian Truong Ba Quan
 */
public class TestGraphGenerator extends VelocityBasedGenerator {

    /**
     * Currently supported writables on vertices and edges or ids of vertices.
     */
    private enum WritableType {
        /**
         * {@link NullWritable}.
         */
        NULL,
        /**
         * {@link LongWritable}.
         */
        LONG,
        /**
         * {@link DoubleWritable}.
         */
        DOUBLE
    };

    /**
     * Generates an end-to-end unit test.
     * @param inputStrs a set of strings storing edge and vertex values and
     * ids of vertices.
     * @return an end-to-end unit test stored as a string (to be saved in a file.)
     */
    public String generate(String[] inputStrs) throws IOException {
        VelocityContext context = buildContext(inputStrs);

        try (StringWriter sw = new StringWriter()) {
            Template template = Velocity.getTemplate("TestGraphTemplate.vm");
            template.merge(context, sw);
            return sw.toString();
        }
    }

    /**
     * Builds the velocity context from the given input strings storing edge,
     * vertex values and ids of vertices.
     * @param inputStrs an array of strings storing edge and vertex values.
     * @return {@link VelocityContext} object.
     */
    private VelocityContext buildContext(String[] inputStrs) {
        VelocityContext context = new VelocityContext();
        context.put("helper", new FormatHelper());
        // Parse the string and check whether the inputs are integers or
        // floating-point numbers
        String[][] tokens = new String[inputStrs.length][];
        WritableType idWritableType = WritableType.NULL;
        WritableType valueWritableType = WritableType.NULL;
        WritableType edgeValueWritableType = WritableType.NULL;
        for (int i = 0; i < inputStrs.length; i++) {
            tokens[i] = inputStrs[i].trim().split("\\s+");
            String[] nums = tokens[i][0].split(":");
            WritableType type = parseWritableType(nums[0]);
            idWritableType = type.ordinal() > idWritableType.ordinal() ? type : idWritableType;
            if (nums.length > 1) {
                type = parseWritableType(nums[1]);
                valueWritableType = type.ordinal() > valueWritableType.ordinal() ? type : valueWritableType;
            }

            for (int j = 1; j < tokens[i].length; j++) {
                nums = tokens[i][j].split(":");
                type = parseWritableType(nums[0]);
                idWritableType = type.ordinal() > idWritableType.ordinal() ? type : idWritableType;
                if (nums.length > 1) {
                    type = parseWritableType(nums[1]);
                    edgeValueWritableType = type.ordinal() > edgeValueWritableType.ordinal() ? type
                            : edgeValueWritableType;
                }
            }
        }

        Map<Object, TemplateVertex> vertexMap = new LinkedHashMap<>(inputStrs.length);
        String str;
        for (int i = 0; i < inputStrs.length; i++) {
            String[] nums = tokens[i][0].split(":");
            Object id = convertToSuitableType(nums[0], idWritableType);
            str = nums.length > 1 ? nums[1] : "0";
            Object value = convertToSuitableType(str, valueWritableType);
            TemplateVertex vertex = vertexMap.get(id);
            if (vertex == null) {
                vertex = new TemplateVertex(id);
                vertexMap.put(id, vertex);
            }
            vertex.setValue(value);

            for (int j = 1; j < tokens[i].length; j++) {
                nums = tokens[i][j].split(":");
                Object nbrId = convertToSuitableType(nums[0], idWritableType);
                str = nums.length > 1 ? nums[1] : "0";
                Object edgeValue = convertToSuitableType(str, edgeValueWritableType);
                if (!vertexMap.containsKey(nbrId)) {
                    vertexMap.put(nbrId, new TemplateVertex(nbrId));
                }
                vertex.addNeighbor(nbrId, edgeValue);
            }
        }

        updateContextByWritableType(context, "vertexIdClass", idWritableType);
        updateContextByWritableType(context, "vertexValueClass", valueWritableType);
        updateContextByWritableType(context, "edgeValueClass", edgeValueWritableType);
        context.put("vertices", vertexMap);

        return context;
    }

    /**
     * Returns the {@link Writable} type of the given string value. Tries to
     * parse into different types, Long, double, and if one succeeds returns that
     * type. Otherwise returns null type.
     * @param str string containing a value.
     * @return {@link Writable} type of the given value of the string.
     */
    private WritableType parseWritableType(String str) {
        if (str == null) {
            return WritableType.NULL;
        } else {
            try {
                Long.valueOf(str);
                return WritableType.LONG;
            } catch (NumberFormatException ex) {
                return WritableType.DOUBLE;
            }
        }
    }

    /**
     * Puts the a given type of a value of an edge or a vertex or id
     * of a vertex into the context.
     * @param context {@link VelocityContext} to populate.
     * @param contextKey currently one of vertexIdClass, vertexValueClass, or
     * edgeValueClass.
     * @param type currently one of {@link NullWritable}, {@link LongWritable},
     * {@link DoubleWritable}.
     */
    private void updateContextByWritableType(VelocityContext context, String contextKey, WritableType type) {
        switch (type) {
        case NULL:
            context.put(contextKey, NullWritable.class.getSimpleName());
            break;
        case LONG:
            context.put(contextKey, LongWritable.class.getSimpleName());
            break;
        case DOUBLE:
            context.put(contextKey, DoubleWritable.class.getSimpleName());
            break;
        default:
            throw new IllegalStateException("Unknown type!");
        }
    }

    /**
     * Constructs a {@link Writable} object with the appropriate type that
     * contains the specified content. For example, type can be LongWritable,
     * and content can be 100L, and this method would return a new
     * {@link LongWritable} that has value 100.
     * @param contents contetns of the writable.
     * @param type type of the writable.
     * @return a {@link Writable} object of appropriate type, whose value contains
     * the given contents.
     */
    private Writable convertToSuitableType(String contents, WritableType type) {
        switch (type) {
        case NULL:
            return NullWritable.get();
        case LONG:
            return new LongWritable(Long.valueOf(contents));
        case DOUBLE:
            return new DoubleWritable(Double.valueOf(contents));
        default:
            throw new IllegalStateException("Unknown type!");
        }
    }

    /**
     * A wrapper around a simple in-memory representation of a vertex to use
     * during test generation.
     */
    public static class TemplateVertex {
        /**
         * Id of the vertex.
         */
        private final Object id;
        /**
         * Value of the vertex.
         */
        private Object value;
        /**
         * Neighbors of the vertex.
         */
        private final ArrayList<TemplateNeighbor> neighbors;

        /**
         * Constructor.
         * @param id if the vertex.
         */
        public TemplateVertex(Object id) {
            super();
            this.id = id;
            this.neighbors = new ArrayList<>();
        }

        public Object getId() {
            return id;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public ArrayList<TemplateNeighbor> getNeighbors() {
            return neighbors;
        }

        /**
         * Adds a neighbor to the vertex's adjacency list.
         * @param nbrId id of the neighbor.
         * @param edgeValue value on the edge to the neighbor.
         */
        public void addNeighbor(Object nbrId, Object edgeValue) {
            neighbors.add(new TemplateNeighbor(nbrId, edgeValue));
        }
    }

    /**
     * A wrapper around a simple in-memory representation of a neighbor of a
     * vertex to use during test generation.
     */

    public static class TemplateNeighbor {
        /**
         * Id of the neighbor.
         */
        private final Object id;
        /**
         * Value on the edge from vertex to the neighbor.
         */
        private final Object edgeValue;

        /**
         * Constructor.
         * @param id id of the neighbor.
         * @param edgeValue value on the edge from vertex to the neighbor.
         */
        public TemplateNeighbor(Object id, Object edgeValue) {
            super();
            this.id = id;
            this.edgeValue = edgeValue;
        }

        public Object getId() {
            return id;
        }

        public Object getEdgeValue() {
            return edgeValue;
        }
    }
}