public static void main(String[] args) throws Exception {
    Builder processingGraphBuilder = Builder.newBuilder();

    /**
     * A supplier streamlet of random GameScore objects is cloned into two
     * separate streamlets.
     */
    List<Streamlet<GameScore>> splitGameScoreStreamlet = processingGraphBuilder
        .newSource(GameScore::new)
        .clone(2);

    /**
     * Elements in the first cloned streamlet go to the database sink.
     */
    splitGameScoreStreamlet.get(0)
        .toSink(new DatabaseSink());

    /**
     * Elements in the second cloned streamlet go to the logging sink.
     */
    splitGameScoreStreamlet.get(1)
        .toSink(new FormattedLogSink());

    Config config = Config.defaultConfig();

    // Fetches the topology name from the first command-line argument
    String topologyName = StreamletUtils.getTopologyName(args);

    // Finally, the processing graph and configuration are passed to the Runner, which converts
    // the graph into a Heron topology that can be run in a Heron cluster.
    new Runner().run(topologyName, config, processingGraphBuilder);
  }
public static void main ( String [ ] args ) throws Exception { Builder processingGraphBuilder = Builder . newBuilder ( ) ; List < Streamlet < GameScore > > splitGameScoreStreamlet = processingGraphBuilder . newSource ( GameScore :: new ) . clone ( 2 ) ; splitGameScoreStreamlet . get ( 0 ) . toSink ( new DatabaseSink ( ) ) ; splitGameScoreStreamlet . get ( 1 ) . toSink ( new FormattedLogSink ( ) ) ; Config config = Config . defaultConfig ( ) ; String topologyName = StreamletUtils . getTopologyName ( args ) ; new Runner ( ) . run ( topologyName , config , processingGraphBuilder ) ; }
All Heron topologies require a main function that defines the topology's behavior
at runtime