1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package org.graalvm.graphio;
  25 
  26 import java.io.File;
  27 import java.io.FileOutputStream;
  28 import java.io.IOException;
  29 import java.nio.channels.FileChannel;
  30 import java.nio.channels.WritableByteChannel;
  31 import java.util.Collection;
  32 import java.util.LinkedHashSet;
  33 import java.util.Map;
  34 import java.util.Set;
  35 
  36 final class GraphSnippets {
  37     static GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> acmeGraphStructure() {
  38         // @formatter:off
  39         // BEGIN: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
  40         class AcmeGraphStructure implements
  41         GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> {
  42 
  43             @Override
  44             public AcmeGraph graph(AcmeGraph currentGraph, Object obj) {
  45                 return obj instanceof AcmeGraph ? (AcmeGraph) obj : null;
  46             }
  47 
  48             @Override
  49             public Iterable<? extends AcmeNode> nodes(AcmeGraph graph) {
  50                 return graph.allNodes();
  51             }
  52 
  53             @Override
  54             public int nodesCount(AcmeGraph graph) {
  55                 return graph.allNodes().size();
  56             }
  57 
  58             @Override
  59             public int nodeId(AcmeNode node) {
  60                 return node.id;
  61             }
  62 
  63             @Override
  64             public boolean nodeHasPredecessor(AcmeNode node) {
  65                 return node.id > 0;
  66             }
  67 
  68             @Override
  69             public void nodeProperties(
  70                 AcmeGraph graph, AcmeNode node, Map<String, ? super Object> properties
  71             ) {
  72                 properties.put("id", node.id);
  73             }
  74 
  75             @Override
  76             public AcmeNodeType nodeClass(Object obj) {
  77                 return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null;
  78             }
  79 
  80             @Override
  81             public AcmeNode node(Object obj) {
  82                 return obj instanceof AcmeNode ? (AcmeNode) obj : null;
  83             }
  84 
  85             @Override
  86             public AcmeNodeType classForNode(AcmeNode node) {
  87                 // we have only one type of nodes
  88                 return AcmeNodeType.STANDARD;
  89             }
  90 
  91 
  92             @Override
  93             public String nameTemplate(AcmeNodeType nodeClass) {
  94                 return "Acme ({p#id})";
  95             }
  96 
  97             @Override
  98             public Object nodeClassType(AcmeNodeType nodeClass) {
  99                 return nodeClass.getClass();
 100             }
 101 
 102             @Override
 103             public AcmePorts portInputs(AcmeNodeType nodeClass) {
 104                 return AcmePorts.INPUT;
 105             }
 106 
 107             @Override
 108             public AcmePorts portOutputs(AcmeNodeType nodeClass) {
 109                 return AcmePorts.OUTPUT;
 110             }
 111 
 112             @Override
 113             public int portSize(AcmePorts port) {
 114                 return port == AcmePorts.OUTPUT ? 1 : 0;
 115             }
 116 
 117             @Override
 118             public boolean edgeDirect(AcmePorts port, int index) {
 119                 return false;
 120             }
 121 
 122             @Override
 123             public String edgeName(AcmePorts port, int index) {
 124                 return port.name();
 125             }
 126 
 127             @Override
 128             public Object edgeType(AcmePorts port, int index) {
 129                 return port;
 130             }
 131 
 132             @Override
 133             public Collection<? extends AcmeNode> edgeNodes(
 134                 AcmeGraph graph, AcmeNode node, AcmePorts port, int index
 135             ) {
 136                 if (port == AcmePorts.OUTPUT) {
 137                     return node.outgoing.targets;
 138                 }
 139                 return null;
 140             }
 141         }
 142 
 143         // END: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
 144 
 145         return new AcmeGraphStructure();
 146     }
 147 
 148     // BEGIN: org.graalvm.graphio.GraphSnippets#buildOutput
 149     static GraphOutput<AcmeGraph, ?> buildOutput(WritableByteChannel channel)
 150     throws IOException {
 151         return GraphOutput.newBuilder(acmeGraphStructure()).
 152             // use the latest version; currently 5.0
 153             protocolVersion(5, 0).
 154             build(channel);
 155     }
 156     // END: org.graalvm.graphio.GraphSnippets#buildOutput
 157 
 158     // BEGIN: org.graalvm.graphio.GraphSnippets#buildAll
 159     static GraphOutput<AcmeGraph, ?> buildAll(WritableByteChannel channel)
 160     throws IOException {
 161         GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = acmeBlocks();
 162         GraphElements<AcmeMethod, AcmeField,
 163             AcmeSignature, AcmeCodePosition> graphElements = acmeElements();
 164         GraphTypes graphTypes = acmeTypes();
 165 
 166         return GraphOutput.newBuilder(acmeGraphStructure()).
 167             protocolVersion(5, 0).
 168             blocks(graphBlocks).
 169             elements(graphElements).
 170             types(graphTypes).
 171             build(channel);
 172     }
 173     // END: org.graalvm.graphio.GraphSnippets#buildAll
 174 
 175     private static GraphTypes acmeTypes() {
 176         GraphTypes graphTypes = null;
 177         // in real world don't return null
 178         return graphTypes;
 179     }
 180 
 181     private static GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> acmeElements() {
 182         GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> graphElements = null;
 183         // in real world don't return null
 184         return graphElements;
 185     }
 186 
 187     private static GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> acmeBlocks() {
 188         GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = null;
 189         // in real world don't return null
 190         return graphBlocks;
 191     }
 192 
 193     private static class AcmeGraph {
 194         final AcmeNode root;
 195 
 196         AcmeGraph(AcmeNode root) {
 197             this.root = root;
 198         }
 199 
 200         Set<AcmeNode> allNodes() {
 201             return allNodes(root, new LinkedHashSet<>());
 202         }
 203 
 204         private static Set<AcmeNode> allNodes(AcmeNode node, Set<AcmeNode> collectTo) {
 205             if (collectTo.add(node)) {
 206                 for (AcmeNode target : node.outgoing.targets) {
 207                     allNodes(target, collectTo);
 208                 }
 209             }
 210             return collectTo;
 211         }
 212     }
 213 
 214     private static class AcmeNode {
 215         final int id;
 216         final AcmeEdges outgoing;
 217 
 218         AcmeNode(int id) {
 219             this.id = id;
 220             this.outgoing = new AcmeEdges();
 221         }
 222 
 223         void linkTo(AcmeNode target) {
 224             outgoing.targets.add(target);
 225         }
 226     }
 227 
 228     private enum AcmeNodeType {
 229         STANDARD
 230     }
 231 
 232     private enum AcmePorts {
 233         INPUT,
 234         OUTPUT;
 235     }
 236 
 237     private static class AcmeEdges {
 238         final Set<AcmeNode> targets;
 239 
 240         AcmeEdges() {
 241             this.targets = new LinkedHashSet<>();
 242         }
 243     }
 244 
 245     private static class AcmeBlocks {
 246     }
 247 
 248     private static class AcmeMethod {
 249     }
 250 
 251     private static class AcmeField {
 252     }
 253 
 254     private static class AcmeSignature {
 255     }
 256 
 257     private static class AcmeCodePosition {
 258     }
 259 
 260     // BEGIN: org.graalvm.graphio.GraphSnippets#dump
 261     static void dump(File toFile) throws IOException {
 262         try (
 263             FileChannel ch = new FileOutputStream(toFile).getChannel();
 264             GraphOutput<AcmeGraph, ?> output = buildOutput(ch);
 265         ) {
 266             AcmeNode root = new AcmeNode(0);
 267             AcmeNode n1 = new AcmeNode(1);
 268             AcmeNode n2 = new AcmeNode(2);
 269             AcmeNode n3 = new AcmeNode(3);
 270 
 271             root.linkTo(n1);
 272             root.linkTo(n2);
 273             n1.linkTo(n3);
 274             n2.linkTo(n3);
 275 
 276             AcmeGraph diamondGraph = new AcmeGraph(root);
 277 
 278             output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null);
 279             output.print(diamondGraph, null, 0, "Diamond graph #%d", 1);
 280             output.endGroup();
 281         }
 282     }
 283     // END: org.graalvm.graphio.GraphSnippets#dump
 284 
 285 }