All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.ferstl.depgraph.graph.GraphBuilder Maven / Gradle / Ivy

Go to download

This Maven plugin generates dependency graphs on single modules or in an aggregated form on multi-module projects. The graphs are represented by .dot files. In case that Graphviz is installed on the machine where this plugin is run, the .dot file can be directly converted into all supported image files.

There is a newer version: 4.0.3
Show newest version
/*
 * Copyright (c) 2014 - 2016 by Stefan Ferstl 
 *
 * 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 com.github.ferstl.depgraph.graph;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import com.github.ferstl.depgraph.graph.dot.DotAttributeBuilder;
import com.github.ferstl.depgraph.graph.dot.DotGraphFormatter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

/**
 * A builder to create DOT strings by defining edges between
 * Nodes. The builder allows some customizations including custom {@link NodeRenderer}s and
 * {@link EdgeRenderer}s.
 *
 * @param  Type of the graph nodes.
 */
public final class GraphBuilder {

  private String graphName;
  private GraphFormatter graphFormatter;
  private NodeRenderer nodeIdRenderer;
  private NodeRenderer nodeNameRenderer;
  private EdgeRenderer edgeRenderer;
  private boolean omitSelfReferences;
  private final Map> nodeDefinitions;
  private final Set edges;

  public static  GraphBuilder create() {
    return new GraphBuilder<>();
  }

  public GraphBuilder() {
    DotAttributeBuilder graphAttributeBuilder = new DotAttributeBuilder();
    DotAttributeBuilder nodeAttributeBuilder = new DotAttributeBuilder().shape("box").fontName("Helvetica");
    DotAttributeBuilder edgeAttributeBuilder = new DotAttributeBuilder().fontName("Helvetica").fontSize(10);

    this.graphName = "G";
    this.graphFormatter = new DotGraphFormatter(graphAttributeBuilder, nodeAttributeBuilder, edgeAttributeBuilder);
    this.nodeIdRenderer = createDefaultNodeIdRenderer();
    this.nodeNameRenderer = createDefaultNodeNameRenderer();
    this.edgeRenderer = createDefaultEdgeRenderer();

    this.nodeDefinitions = new LinkedHashMap<>();
    this.edges = new LinkedHashSet<>();
  }

  public GraphBuilder graphName(String name) {
    this.graphName = name;
    return this;
  }

  public GraphBuilder useNodeIdRenderer(NodeRenderer nodeIdRenderer) {
    this.nodeIdRenderer = nodeIdRenderer;
    return this;
  }

  public GraphBuilder useNodeNameRenderer(NodeRenderer nodeNameRenderer) {
    this.nodeNameRenderer = nodeNameRenderer;
    return this;
  }

  public GraphBuilder useEdgeRenderer(EdgeRenderer edgeRenderer) {
    this.edgeRenderer = edgeRenderer;
    return this;
  }

  public GraphBuilder omitSelfReferences() {
    this.omitSelfReferences = true;
    return this;
  }

  public GraphBuilder graphFormatter(GraphFormatter formatter) {
    this.graphFormatter = formatter;
    return this;
  }

  public boolean isEmpty() {
    return this.nodeDefinitions.isEmpty();
  }

  /**
   * Adds a single node to the graph.
   *
   * @param node The node to add.
   * @return This builder.
   */
  public GraphBuilder addNode(T node) {
    String nodeId = this.nodeIdRenderer.render(node);
    String nodeName = this.nodeNameRenderer.render(node);
    this.nodeDefinitions.put(nodeId, new Node<>(nodeId, nodeName, node));

    return this;
  }

  /**
   * Adds the two given nodes to the graph and creates an edge between them if they are not {@code null}.
   * Nothing will be added to the graph if one or both nodes are {@code null}.
   *
   * @param from From node.
   * @param to To node.
   * @return This builder.
   */
  // no edge will be created in case one or both nodes are null.
  public GraphBuilder addEdge(T from, T to) {
    if (from != null && to != null) {
      addNode(from);
      addNode(to);

      safelyAddEdge(from, to);
    }

    return this;
  }

  /**
   * Returns the node that was added first to this builder or the given node if new.
   *
   * @param node Node.
   * @return The firstly added node or the given node if not present.
   */
  public T getEffectiveNode(T node) {
    String key = this.nodeIdRenderer.render(node);
    if (this.nodeDefinitions.containsKey(key)) {
      return this.nodeDefinitions.get(key).nodeObject;
    }

    return node;
  }

  @Override
  public String toString() {
    // Work around some generics restrictions
    ImmutableList.Builder> nodeListBuilder = ImmutableList.builder();
    for (Node node : this.nodeDefinitions.values()) {
      nodeListBuilder.add(node);
    }
    ImmutableList> nodeList = nodeListBuilder.build();
    ImmutableSet edgeSet = ImmutableSet.copyOf(this.edges);

    return this.graphFormatter.format(this.graphName, nodeList, edgeSet);
  }

  private void safelyAddEdge(T fromNode, T toNode) {
    String fromNodeId = this.nodeIdRenderer.render(fromNode);
    String toNodeId = this.nodeIdRenderer.render(toNode);

    if (!this.omitSelfReferences || !fromNodeId.equals(toNodeId)) {
      Edge edge = new Edge(fromNodeId, toNodeId, this.edgeRenderer.render(fromNode, toNode));
      this.edges.add(edge);
    }
  }

  private static  EdgeRenderer createDefaultEdgeRenderer() {
    return new EdgeRenderer() {

      @Override
      public String render(T from, T to) {
        return "";
      }

    };
  }

  private static  NodeRenderer createDefaultNodeIdRenderer() {
    return new NodeRenderer() {

      @Override
      public String render(T node) {
        return node.toString();
      }
    };
  }

  private static  NodeRenderer createDefaultNodeNameRenderer() {
    return new NodeRenderer() {

      @Override
      public String render(T node) {
        return "";
      }
    };
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy