org.eclipse.jetty.start.ModuleGraphWriter Maven / Gradle / Ivy
The newest version!
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.start;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;
/**
* Generate a graphviz dot graph of the modules found
*/
public class ModuleGraphWriter
{
private String colorModuleBg;
private String colorEnabledBg;
private String colorEdgeBefore;
private String colorEdgeAfter;
private String colorTransitiveBg;
private String colorCellBg;
private String colorHeaderBg;
private String colorModuleFont;
public ModuleGraphWriter()
{
colorModuleBg = "#B8FFB8";
colorEnabledBg = "#66FFCC";
colorEdgeAfter = "#00CC33";
colorEdgeAfter = "#33CC00";
colorTransitiveBg = "#66CC66";
colorCellBg = "#FFFFFF80";
colorHeaderBg = "#00000020";
colorModuleFont = "#888888";
}
public void config(Props props)
{
String prefix = "jetty.graph.";
colorModuleBg = getProperty(props, prefix + "color.module.bg", colorModuleBg);
colorEnabledBg = getProperty(props, prefix + "color.enabled.bg", colorEnabledBg);
colorEdgeBefore = getProperty(props, prefix + "color.edge.before", colorEdgeBefore);
colorEdgeAfter = getProperty(props, prefix + "color.edge.after", colorEdgeAfter);
colorTransitiveBg = getProperty(props, prefix + "color.transitive.bg", colorTransitiveBg);
colorCellBg = getProperty(props, prefix + "color.cell.bg", colorCellBg);
colorHeaderBg = getProperty(props, prefix + "color.header.bg", colorHeaderBg);
colorModuleFont = getProperty(props, prefix + "color.font", colorModuleFont);
}
private String getProperty(Props props, String key, String defVal)
{
String val = props.getString(key, defVal);
if (val == null)
{
return defVal;
}
val = val.trim();
if (val.length() <= 0)
{
return defVal;
}
return val;
}
public void write(Modules modules, Path outputFile) throws IOException
{
try (BufferedWriter writer = Files.newBufferedWriter(outputFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
PrintWriter out = new PrintWriter(writer))
{
writeHeaderMessage(out, outputFile);
out.println();
out.println("digraph modules {");
// Node Style
out.println(" node [color=gray, style=filled, shape=rectangle];");
out.println(" node [fontname=\"Verdana\", size=\"20,20\"];");
// Graph Style
out.println(" graph [");
out.println(" concentrate=false,");
out.println(" fontname=\"Verdana\",");
out.println(" fontsize = 20,");
out.println(" rankdir = LR,");
out.println(" ranksep = 1.5,");
out.println(" nodesep = .5,");
out.println(" style = bold,");
out.println(" labeljust = l,");
out.println(" label = \"Jetty Modules\",");
out.println(" ssize = \"20,40\"");
out.println(" ];");
List enabled = modules.getEnabled();
// Module Nodes
writeModules(out, modules, enabled);
// Module Relationships
writeRelationships(out, modules, enabled);
out.println("}");
out.println();
}
}
private void writeHeaderMessage(PrintWriter out, Path outputFile)
{
out.println("/*");
out.println(" * GraphViz Graph of Jetty Modules");
out.println(" * ");
out.println(" * Jetty: https://jetty.org/");
out.println(" * GraphViz: http://graphviz.org/");
out.println(" * ");
out.println(" * To Generate Graph image using graphviz:");
String filename = outputFile.getFileName().toString();
String basename = filename.substring(0, filename.indexOf('.'));
out.printf(" * $ dot -Tpng -Goverlap=false -o %s.png %s%n", basename, filename);
out.println(" */");
}
private void writeModuleDetailHeader(PrintWriter out, String header)
{
writeModuleDetailHeader(out, header, 1);
}
private void writeModuleDetailHeader(PrintWriter out, String header, int count)
{
out.printf(" ");
out.printf("", colorHeaderBg);
out.printf("%s%s ", header, count > 1 ? "s" : "");
out.println(" ");
}
private void writeModuleDetailLine(PrintWriter out, String line)
{
out.printf(" ");
StringBuilder escape = new StringBuilder();
for (char c : line.toCharArray())
{
switch (c)
{
case '<':
escape.append("<");
break;
case '>':
escape.append(">");
break;
default:
escape.append(c);
break;
}
}
out.printf("%s %n", colorCellBg, escape.toString());
}
private void writeModuleNode(PrintWriter out, Module module, boolean resolved)
{
String color = colorModuleBg;
if (module.isEnabled())
{
// specifically enabled by config
color = colorEnabledBg;
}
else if (resolved)
{
// enabled by transitive reasons
color = colorTransitiveBg;
}
out.printf(" \"%s\" [ color=\"%s\" label=<", module.getName(), color);
out.printf("%n");
out.printf(" %s %n", module.getName());
if (module.isEnabled())
{
writeModuleDetailHeader(out, "ENABLED");
for (String selection : module.getEnableSources())
{
writeModuleDetailLine(out, "via: " + selection);
}
}
else if (resolved)
{
writeModuleDetailHeader(out, "TRANSITIVE");
}
if (!module.getXmls().isEmpty())
{
List xmls = module.getXmls();
writeModuleDetailHeader(out, "XML", xmls.size());
for (String xml : xmls)
{
writeModuleDetailLine(out, xml);
}
}
if (!module.getLibs().isEmpty())
{
List libs = module.getLibs();
writeModuleDetailHeader(out, "LIB", libs.size());
for (String lib : libs)
{
writeModuleDetailLine(out, lib);
}
}
if (!module.getIniTemplate().isEmpty())
{
List inis = module.getIniTemplate();
writeModuleDetailHeader(out, "INI Template", inis.size());
}
out.printf("
>];%n");
}
private void writeModules(PrintWriter out, Modules allmodules, List enabled)
{
out.println();
out.println(" /* Modules */");
out.println();
out.println(" node [ labeljust = l ];");
for (Module module : allmodules)
{
boolean resolved = enabled.contains(module);
writeModuleNode(out, module, resolved);
}
}
private void writeRelationships(PrintWriter out, Iterable modules, List enabled)
{
for (Module module : modules)
{
for (String depends : module.getDepends())
{
depends = Module.normalizeModuleName(depends);
out.printf(" \"%s\" -> \"%s\";%n", module.getName(), depends);
}
for (String optional : module.getAfter())
{
out.printf(" \"%s\" -> \"%s\" [ color=\"%s\" ];%n", module.getName(), optional, colorEdgeAfter);
}
for (String before : module.getBefore())
{
out.printf(" \"%s\" -> \"%s\" [ color=\"%s\" ];%n", before, module.getName(), colorEdgeBefore);
}
}
}
}