org.apache.heron.scheduler.dryrun.UpdateTableDryRunRenderer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.heron.scheduler.dryrun.UpdateTableDryRunRenderer.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.heron.scheduler.dryrun;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Optional;
import com.google.common.collect.Sets;

import org.apache.heron.spi.common.Config;
import org.apache.heron.spi.common.Context;
import org.apache.heron.spi.packing.PackingPlan;

import static org.apache.heron.scheduler.dryrun.FormatterUtils.ContainerChange;
import static org.apache.heron.scheduler.dryrun.FormatterUtils.Row;
import static org.apache.heron.scheduler.dryrun.FormatterUtils.TextColor;
import static org.apache.heron.scheduler.dryrun.FormatterUtils.TextStyle;

/**
 * Dry-run renderer that renders update dry-run response in table format
 */
public class UpdateTableDryRunRenderer implements DryRunRender {

    private class ContainersDiffView {
        private final Optional<PackingPlan.ContainerPlan> oldPlan;
        private final Optional<PackingPlan.ContainerPlan> newPlan;

        ContainersDiffView(Optional<PackingPlan.ContainerPlan> oldPlan,
                Optional<PackingPlan.ContainerPlan> newPlan) {
            this.oldPlan = oldPlan;
            this.newPlan = newPlan;
        }

        public Optional<PackingPlan.ContainerPlan> getOldPlan() {
            return oldPlan;
        }

        public Optional<PackingPlan.ContainerPlan> getNewPlan() {
            return newPlan;
        }
    }

    private Map<Integer, ContainersDiffView> getContainerDiffViews(PackingPlan oldPackingPlan,
            PackingPlan newPackingPlan) {
        Map<Integer, ContainersDiffView> diffView = new HashMap<>();
        for (PackingPlan.ContainerPlan plan : oldPackingPlan.getContainers()) {
            int id = plan.getId();
            diffView.put(id,
                    new ContainersDiffView(oldPackingPlan.getContainer(id), newPackingPlan.getContainer(id)));
        }
        for (PackingPlan.ContainerPlan plan : newPackingPlan.getContainers()) {
            int id = plan.getId();
            if (!diffView.containsKey(id)) {
                diffView.put(id,
                        new ContainersDiffView(oldPackingPlan.getContainer(id), newPackingPlan.getContainer(id)));
            }
        }
        return diffView;
    }

    private final Config config;
    private final PackingPlan oldPlan;
    private final PackingPlan newPlan;
    private final FormatterUtils formatter;

    public UpdateTableDryRunRenderer(UpdateDryRunResponse response, boolean rich) {
        this.config = response.getConfig();
        this.oldPlan = response.getOldPackingPlan();
        this.newPlan = response.getPackingPlan();
        this.formatter = new FormatterUtils(rich);
    }

    private String renderContainerDiffView(int containerId, ContainersDiffView diffView) {
        StringBuilder builder = new StringBuilder();
        Optional<PackingPlan.ContainerPlan> oldPackingPlan = diffView.getOldPlan();
        Optional<PackingPlan.ContainerPlan> newPackingPlan = diffView.getNewPlan();
        String header = String.format("%s ", formatter.renderContainerName(containerId));
        builder.append(header);
        // Container exists in both old and new packing plan
        if (oldPackingPlan.isPresent() && newPackingPlan.isPresent()) {
            PackingPlan.ContainerPlan newContainerPlan = newPackingPlan.get();
            PackingPlan.ContainerPlan oldContainerPlan = oldPackingPlan.get();
            // Container plan did not change
            if (newContainerPlan.equals(oldContainerPlan)) {
                builder.append(formatter.renderContainerChange(ContainerChange.UNAFFECTED) + "\n");
                String resourceUsage = formatter.renderResourceUsage(newContainerPlan.getRequiredResource());
                List<Row> rows = new ArrayList<>();
                for (PackingPlan.InstancePlan plan : newContainerPlan.getInstances()) {
                    rows.add(formatter.rowOfInstancePlan(plan, TextColor.DEFAULT, TextStyle.DEFAULT));
                }
                String containerTable = formatter.renderOneContainer(rows);
                builder.append(resourceUsage + "\n");
                builder.append(containerTable);
            } else {
                // Container plan has changed
                String resourceUsage = formatter.renderResourceUsageChange(oldContainerPlan.getRequiredResource(),
                        newContainerPlan.getRequiredResource());
                Set<PackingPlan.InstancePlan> oldInstancePlans = oldContainerPlan.getInstances();
                Set<PackingPlan.InstancePlan> newInstancePlans = newContainerPlan.getInstances();
                Set<PackingPlan.InstancePlan> unchangedPlans = Sets.intersection(oldInstancePlans, newInstancePlans)
                        .immutableCopy();
                Set<PackingPlan.InstancePlan> newPlans = Sets.difference(newInstancePlans, oldInstancePlans);
                Set<PackingPlan.InstancePlan> removedPlans = Sets.difference(oldInstancePlans, newInstancePlans);
                List<Row> rows = new ArrayList<>();
                for (PackingPlan.InstancePlan plan : unchangedPlans) {
                    rows.add(formatter.rowOfInstancePlan(plan, TextColor.DEFAULT, TextStyle.DEFAULT));
                }
                for (PackingPlan.InstancePlan plan : newPlans) {
                    rows.add(formatter.rowOfInstancePlan(plan, TextColor.GREEN, TextStyle.DEFAULT));
                }
                for (PackingPlan.InstancePlan plan : removedPlans) {
                    rows.add(formatter.rowOfInstancePlan(plan, TextColor.RED, TextStyle.STRIKETHROUGH));
                }
                builder.append(formatter.renderContainerChange(ContainerChange.MODIFIED) + "\n");
                builder.append(resourceUsage + "\n");
                String containerTable = formatter.renderOneContainer(rows);
                builder.append(containerTable);
            }
        } else if (oldPackingPlan.isPresent()) {
            // Container has been removed
            PackingPlan.ContainerPlan oldContainerPlan = oldPackingPlan.get();
            List<Row> rows = new ArrayList<>();
            for (PackingPlan.InstancePlan plan : oldContainerPlan.getInstances()) {
                rows.add(formatter.rowOfInstancePlan(plan, TextColor.RED, TextStyle.STRIKETHROUGH));
            }
            builder.append(formatter.renderContainerChange(ContainerChange.REMOVED) + "\n");
            builder.append(formatter.renderResourceUsage(oldContainerPlan.getRequiredResource()) + "\n");
            builder.append(formatter.renderOneContainer(rows));
        } else if (newPackingPlan.isPresent()) {
            // New container has been added
            PackingPlan.ContainerPlan newContainerPlan = newPackingPlan.get();
            List<Row> rows = new ArrayList<>();
            for (PackingPlan.InstancePlan plan : newContainerPlan.getInstances()) {
                rows.add(formatter.rowOfInstancePlan(plan, TextColor.GREEN, TextStyle.DEFAULT));
            }
            builder.append(formatter.renderContainerChange(ContainerChange.NEW) + "\n");
            builder.append(formatter.renderResourceUsage(newContainerPlan.getRequiredResource()) + "\n");
            builder.append(formatter.renderOneContainer(rows));
        } else {
            throw new RuntimeException(
                    "Unexpected error: either new container plan or old container plan has to exist");
        }
        return builder.toString();
    }

    public String render() {
        Map<Integer, ContainersDiffView> diffViews = getContainerDiffViews(oldPlan, newPlan);
        int numContainers = newPlan.getContainers().size();
        StringBuilder builder = new StringBuilder();
        builder.append(String.format("Total number of containers: %d", numContainers) + "\n");
        builder.append(String.format("Using repacking class: %s", Context.repackingClass(config)) + "\n");
        List<String> containerTables = new ArrayList<>();
        for (Integer id : diffViews.keySet()) {
            containerTables.add(renderContainerDiffView(id, diffViews.get(id)));
        }
        builder.append(String.join("\n", containerTables));
        return builder.toString();
    }
}