Package com.netflix.governator.guice

Source Code of com.netflix.governator.guice.Grapher

/*
* Copyright 2013, 2014 Netflix, Inc.
*
*    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.netflix.governator.guice;

import com.google.common.io.Closeables;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.grapher.GrapherModule;
import com.google.inject.grapher.InjectorGrapher;
import com.google.inject.grapher.graphviz.GraphvizModule;
import com.google.inject.grapher.graphviz.GraphvizRenderer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;

/**
* An object that can generate a graph showing a Guice Dependency Injection graph.
*
* @see <a href="http://www.graphviz.org/">GraphViz</a>
* @see <a href="http://code.google.com/p/google-guice/wiki/Grapher">Guice Grapher</a>
* @see <a href="http://code.google.com/p/jrfonseca/wiki/XDot">XDot, an interactive viewer for Dot files</a>
*/
public class Grapher
{
    private final Injector injector;
    private final Key<?>[] roots;

    /*
     * Constructors
     */

    /**
     * Creates a new Grapher.
     *
     * @param injector the Injector whose dependency graph will be generated
     */
    @Inject
    public Grapher(Injector injector) {
        this.injector = injector;
        this.roots = null;
    }

    /**
     * Creates a new Grapher.
     *
     * @param injector the Injector whose dependency graph will be generated
     * @param keys {@code Key}s for the roots of the graph
     */
    public Grapher(Injector injector, Key<?>... keys) {
        this.injector = injector;
        this.roots = keys;
    }

    /**
     * Creates a new Grapher.
     *
     * @param injector the Injector whose dependency graph will be generated
     * @param classes {@code Class}es for the roots of the graph
     */
    public Grapher(Injector injector, Class<?>... classes) {
        this.injector = injector;
        this.roots = new Key<?>[classes.length];
        for (int i = 0; i < classes.length; i++) {
            roots[i] = Key.get(classes[i]);
        }
    }

    /**
     * Creates a new Grapher.
     *
     * @param injector the Injector whose dependency graph will be generated
     * @param packages names of {@code Package}s for the roots of the graph
     */
    public Grapher(Injector injector, String... packages) {
        this.injector = injector;
        // Scan all the injection bindings to find the root keys
        Set<Key<?>> keys = new HashSet<Key<?>>();
        for (Key<?> k : injector.getAllBindings().keySet()) {
            Package classPackage = k.getTypeLiteral().getRawType().getPackage();
            if (classPackage == null) {
                continue;
            }
            String packageName = classPackage.getName();
            for (String p : packages) {
                if (packageName.startsWith(p)) {
                    keys.add(k);
                    break;
                }
            }
        }
        this.roots = keys.toArray(new Key<?>[keys.size()]);
    }

    /*
     * Graphing methods
     */

    /**
     * Writes the "Dot" graph to a new temp file.
     *
     * @return the name of the newly created file
     */
    public String toFile() throws Exception {
        File file = File.createTempFile("GuiceDependencies_", ".dot");
        toFile(file);
        return file.getCanonicalPath();
    }

    /**
     * Writes the "Dot" graph to a given file.
     *
     * @param file file to write to
     */
    public void toFile(File file) throws Exception {
        PrintWriter out = new PrintWriter(file, "UTF-8");
        try {
            out.write(graph());
        }
        finally {
            Closeables.close(out, true);
        }
    }

    /**
     * Returns a String containing the "Dot" graph definition.
     *
     * @return the "Dot" graph definition
     */
    public String graph() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintWriter out = new PrintWriter(baos);
        Injector localInjector = Guice.createInjector(new GrapherModule(), new GraphvizModule());
        GraphvizRenderer renderer = localInjector.getInstance(GraphvizRenderer.class);
        renderer.setOut(out).setRankdir("TB");
        InjectorGrapher g = localInjector.getInstance(InjectorGrapher.class).of(injector);
        if (roots != null) {
            g.rootedAt(roots);
        }
        g.graph();
        return fixupGraph(baos.toString("UTF-8"));
    }

    /*
     * Work-arounds for bugs in the Grapher package
     * See http://stackoverflow.com/questions/9301007/is-there-any-way-to-get-guice-grapher-to-work
     */

    private String fixupGraph(String s) {
        s = fixGrapherBug(s);
        s = hideClassPaths(s);
        return s;
    }

    private String hideClassPaths(String s) {
      s = s.replaceAll("\\w[a-z\\d_\\.]+\\.([A-Z][A-Za-z\\d_\\$]*)", "$1");
      s = s.replaceAll("value=[\\w-]+", "random");
      return s;
   }

    private String fixGrapherBug(String s) {
      s = s.replaceAll("style=invis", "style=solid");
      s = s.replaceAll("margin=(\\S+), ", "margin=\"$1\", ");
      return s;
   }

} // Grapher
TOP

Related Classes of com.netflix.governator.guice.Grapher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.