org.cloudsmith.geppetto.graph.catalog.CatalogGraphProducer.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudsmith.geppetto.graph.catalog.CatalogGraphProducer.java

Source

/**
 * Copyright (c) 2011 Cloudsmith Inc. and other contributors, as listed below.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *   Cloudsmith
 * 
 */
package org.cloudsmith.geppetto.graph.catalog;

import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.cloudsmith.geppetto.catalog.Catalog;
import org.cloudsmith.geppetto.catalog.CatalogEdge;
import org.cloudsmith.geppetto.catalog.CatalogResource;
import org.cloudsmith.geppetto.catalog.CatalogResourceParameter;
import org.cloudsmith.graph.ICancel;
import org.cloudsmith.graph.elements.Edge;
import org.cloudsmith.graph.elements.RootGraph;
import org.cloudsmith.graph.elements.Vertex;
import org.cloudsmith.graph.graphcss.GraphCSS;
import org.cloudsmith.graph.graphcss.StyleSet;
import org.cloudsmith.graph.style.Span;
import org.cloudsmith.graph.style.labels.LabelRow;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Produces a Catalog graph in DOT format.
 * 
 */
public class CatalogGraphProducer extends AbstractCatalogGraphProducer implements CatalogGraphStyles {

    private Vertex createVertexFor(CatalogResource resource, IPath root) {
        Vertex v = new Vertex("", STYLE_Resource);
        v.setStyles(labelStyleForResource(resource, root));
        return v;
    }

    private StyleSet labelStyleForResource(CatalogResource r, final IPath root) {

        // Produce a sorted list of parameters (that skips parameters that are really dependencies)
        List<LabelRow> labelRows = Lists.newArrayList();
        CatalogResourceParameter[] sortedProperties = Iterables.toArray(
                Iterables.filter(getParameterIterable(r), regularParameterPredicate),
                CatalogResourceParameter.class);

        Arrays.sort(sortedProperties, new Comparator<CatalogResourceParameter>() {

            @Override
            public int compare(CatalogResourceParameter o1, CatalogResourceParameter o2) {
                return o1.getName().compareTo(o2.getName());
            }

        });

        // Add a labelRow for the type[id]
        StringBuilder builder = new StringBuilder();
        builder.append(r.getType());
        builder.append("[");
        builder.append(r.getTitle());
        builder.append("]");

        int width = 0;
        boolean hasParameters = sortedProperties.length > 0;
        boolean hasFooter = r.getFile() != null;
        if (hasParameters || hasFooter)
            labelRows.add(getStyles().labelRow("RowSeparator",
                    getStyles().labelCell("SpacingCell", "", Span.colSpan(3))));

        labelRows.add(getStyles().labelRow(STYLE_ResourceTitleRow, //
                getStyles().labelCell(STYLE_ResourceTitleCell, builder.toString(), Span.colSpan(3))));
        width += builder.length();

        // Rendering of separator line fails in graphviz 2.28 with an error
        // labelRows.add(getStyles().rowSeparator());
        if (hasParameters || hasFooter) {
            labelRows.add(getStyles().labelRow("RowSeparator",
                    getStyles().labelCell("SpacingCell", "", Span.colSpan(3))));
            labelRows.add(
                    getStyles().labelRow("RowSeparator", getStyles().labelCell("HRCell", "", Span.colSpan(3))));
            labelRows.add(getStyles().labelRow("RowSeparator",
                    getStyles().labelCell("SpacingCell", "", Span.colSpan(3))));
        }
        // parameters
        for (CatalogResourceParameter a : sortedProperties) {
            final String aName = a.getName();

            // output file contents as "DATA" as we can't fit the entire contents into a cell.
            List<String> values = "content".equals(aName) ? Lists.newArrayList("DATA") : a.getValue();
            builder = new StringBuilder();
            for (String v : values) {
                builder.append(v);
                builder.append(" ");
            }
            // remove trailing space
            builder.deleteCharAt(builder.length() - 1);
            String value = builder.toString();

            labelRows.add(getStyles().labelRow(STYLE_ResourcePropertyRow, //
                    getStyles().labelCell(STYLE_ResourcePropertyName, a.getName()), //
                    getStyles().labelCell(STYLE_ResourcePropertyValue, DOUBLE_RIGHT_ARROW + value, Span.colSpan(2)) //
            ));

            int tmpWidth = a.getName().length() + value.length() + 2;
            if (tmpWidth > width)
                width = tmpWidth;
        }

        // A footer with filename[line]
        // (is not always present)
        if (hasFooter) {
            builder = new StringBuilder();
            // shorten the text by making it relative to root if possible
            if (root != null)
                builder.append(new Path(r.getFile()).makeRelativeTo(root).toString());
            else
                builder.append(r.getFile());
            if (r.getLine() != null) {
                builder.append("[");
                builder.append(r.getLine());
                builder.append("]");
            }
            String tooltip = builder.toString();
            if (builder.length() > width) {
                builder.delete(0, builder.length() - width);
                builder.insert(0, "[...]");
            }

            if (hasParameters)
                labelRows.add(getStyles().labelRow("RowSeparator",
                        getStyles().labelCell("SpacingCell", "", Span.colSpan(3))));
            int line = -1;
            try {
                line = Integer.valueOf(r.getLine());
            } catch (NumberFormatException e) {
                line = -1;
            }

            labelRows.add(getStyles().labelRow(STYLE_ResourceFileInfoRow, //
                    getStyles().labelCell(STYLE_ResourceFileInfoCell, builder.toString(), Span.colSpan(3))
                            .withStyles(//
                                    getStyles().tooltip(tooltip), //
                                    getStyles().href(
                                            getHrefProducer().hrefToManifest(new Path(r.getFile()), root, line)) //
                    )) //
            );
        } else if (hasParameters) {
            // add a bit of padding at the bottom if there is no footer
            labelRows.add(getStyles().labelRow("RowSeparator",
                    getStyles().labelCell("SpacingCell", "", Span.colSpan(3))));
        }

        return StyleSet.withStyle(//
                getStyles().labelFormat(//
                        getStyles().labelTable(STYLE_ResourceTable, //
                                labelRows.toArray(new LabelRow[labelRows.size()]))));

    }

    /**
     * Produces a graph in DOT format for the given catalog on the given output stream.
     * 
     * @param cancel
     *        enables cancellation of long running job
     * @param catalog
     *        the catalog for which a graph is produced
     * @param out
     *        where output in DOT format should be written
     * @param root
     *        the path to the root of file references in catalogs
     * @param moduleData
     *        Name -> 0* MetadataInfo representing one version of a module with given name
     */
    public void produceGraph(ICancel cancel, Catalog catalog, String catalogName, OutputStream out, IPath root) {
        if (cancel == null || catalog == null || out == null)
            throw new IllegalArgumentException("one or more parameters are null");

        RootGraph g = produceRootGraph(cancel, catalog, catalogName, root);
        GraphCSS instanceRules = getInstanceRules();
        instanceRules.addAll(getTheme().getInstanceRules());
        getDotRenderer().write(cancel, out, g, getTheme().getDefaultRules(), instanceRules);
    }

    /**
     * Produces the graph data structure (RootGraph, Vertexes, Edges).
     * 
     */
    private RootGraph produceRootGraph(ICancel cancel, Catalog catalog, String catalogName, final IPath root) {

        RootGraph g = new RootGraph(catalogName, "RootGraph", "root");

        // Iterate the catalog
        // What to do with these? Are they of any value?
        // catalog.getClasses(); // list of classnames
        // catalog.getTags(); // don't know if these have any value...

        Map<String, Vertex> vertexMap = Maps.newHashMap();
        Map<CatalogResource, Vertex> resourceVertexMap = Maps.newHashMap();

        for (CatalogResource r : catalog.getResources()) {
            StringBuilder builder = new StringBuilder();
            builder.append(r.getType().toLowerCase());
            builder.append("[");
            builder.append(r.getTitle().toLowerCase());
            builder.append("]");

            Vertex v = createVertexFor(r, root);
            g.addVertex(v);
            vertexMap.put(builder.toString(), v);
            resourceVertexMap.put(r, v);
        }

        for (CatalogResource r : catalog.getResources()) {
            final Vertex source = resourceVertexMap.get(r);
            for (CatalogResourceParameter p : Iterables.filter(getParameterIterable(r),
                    Predicates.not(regularParameterPredicate))) {
                String aName = p.getName();
                String style = null;
                if ("subscribe".equals(aName))
                    style = CatalogGraphStyles.STYLE_SubscribeEdge;
                else if ("before".equals(aName))
                    style = CatalogGraphStyles.STYLE_BeforeEdge;
                else if ("notify".equals(aName))
                    style = CatalogGraphStyles.STYLE_NotifyEdge;
                else
                    style = CatalogGraphStyles.STYLE_RequireEdge;
                for (String ref : p.getValue()) {
                    Vertex target = vertexMap.get(ref.toLowerCase());
                    if (target == null) {
                        target = createVertexForMissingResource(ref);
                        vertexMap.put(ref.toLowerCase(), target); // keep it if there are more references
                        g.addVertex(target);
                    }
                    Edge edge = new Edge(aName, style, source, target);
                    g.addEdge(edge);
                }
            }
        }
        for (CatalogEdge e : catalog.getEdges()) {
            Vertex source = vertexMap.get(e.getSource().toLowerCase());
            Vertex target = vertexMap.get(e.getTarget().toLowerCase());
            Edge edge = new Edge("", STYLE_ResourceEdge, source, target);
            g.addEdge(edge);
        }

        return g;
    }
}