org.pentaho.community.di.util.GraphUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.community.di.util.GraphUtils.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.pentaho.community.di.util;

import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
import com.tinkerpop.gremlin.java.GremlinPipeline;
import com.tinkerpop.pipes.PipeFunction;
import com.tinkerpop.pipes.branch.LoopPipe;
import org.pentaho.di.core.EngineMetaInterface;
import org.pentaho.di.core.gui.Point;
import org.pentaho.di.trans.TransHopMeta;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepMeta;

import java.util.LinkedList;
import java.util.List;

public class GraphUtils {

    public static final String PROPERTY_NAME = "name";
    public static final String PROPERTY_REF = "ref";
    public static final String PROPERTY_PLUGINID = "pluginId";
    public static final String PROPERTY_X = "x";
    public static final String PROPERTY_Y = "y";

    public static final String EDGE_HOPSTO = "hops_to";

    public static Graph createGraph(EngineMetaInterface meta) {
        if (meta == null) {
            return null;
        }
        Graph g = new TinkerGraph();
        if (meta instanceof TransMeta) {
            TransMeta transMeta = (TransMeta) meta;

            // Add nodes
            List<StepMeta> steps = transMeta.getSteps();
            if (steps != null) {
                for (StepMeta step : steps) {
                    Vertex v = g.addVertex(step.getName());
                    v.setProperty(PROPERTY_NAME, step.getName());
                    v.setProperty(PROPERTY_PLUGINID, step.getStepID());
                    Point location = step.getLocation();
                    v.setProperty(PROPERTY_X, location.x);
                    v.setProperty(PROPERTY_Y, location.y);
                    v.setProperty(PROPERTY_REF, step);
                }
            }
            int numHops = transMeta.nrTransHops();
            for (int i = 0; i < numHops; i++) {
                TransHopMeta hop = transMeta.getTransHop(i);
                StepMeta fromStep = hop.getFromStep();
                StepMeta toStep = hop.getToStep();
                Vertex fromV = g.getVertex(fromStep.getName());
                Vertex toV = g.getVertex(toStep.getName());
                g.addEdge(null, fromV, toV, EDGE_HOPSTO);
            }
        }
        return g;
    }

    public static List<Vertex> getInputSteps(Graph g) {
        GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<>(g);
        return pipe.V().filter(new PipeFunction<Vertex, Boolean>() {
            @Override
            public Boolean compute(Vertex vertex) {
                return Iterables.isEmpty(vertex.getEdges(Direction.IN));
            }
        }).toList();
    }

    public static List<Vertex> getLongestPath(Graph g) {
        List<Vertex> longestPath = new LinkedList<>();
        int maxLength = 0;

        // g.V().out.loop(1){it.loops<1000}{true}.path().last()
        GremlinPipeline<Vertex, List<Vertex>> pipe = new GremlinPipeline<>(g);

        List<List> paths = pipe.V().out().loop(1, new NumLoops<Vertex>(1000), new Emit<Vertex>(true)).path()
                .toList();

        if (paths != null) {
            // Not sure why Gremlin-Groovy orders the paths such that the last one is necessarily the longest, but the
            // Java version above does not. So we keep the longest ourselves
            for (List path : paths) {
                int pathLength = path.size();
                if (maxLength < pathLength) {
                    longestPath = (List<Vertex>) path;
                    maxLength = pathLength;
                }
            }
        }

        return longestPath;
    }

    public static <O> Function<Element, O> getProperty(final String key) {
        return new Function<Element, O>() {
            @Override
            public O apply(Element input) {
                return input.getProperty(key);
            }
        };
    }

    /**
     * This is a loop closure that returns true if the current loop count is less than the given number, false otherwise
     *
     * @param <S> the type of object passed into the loop closure
     */
    public static class NumLoops<S> implements PipeFunction<LoopPipe.LoopBundle<S>, Boolean> {
        private int numLoops = 1;

        public NumLoops(int numLoops) {
            this.numLoops = numLoops;
        }

        @Override
        public Boolean compute(LoopPipe.LoopBundle argument) {
            return argument.getLoops() < numLoops;
        }
    }

    /**
     * This is a loop closure that returns true if the current loop count is less than the given number, false otherwise
     */
    public static class Emit<S> implements PipeFunction<LoopPipe.LoopBundle<S>, Boolean> {
        private boolean emitValue;

        public Emit(boolean emitValue) {
            this.emitValue = emitValue;
        }

        @Override
        public Boolean compute(LoopPipe.LoopBundle argument) {
            return emitValue;
        }
    }
}