com.esri.geoevent.test.performance.ui.OrchestratorController.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.geoevent.test.performance.ui.OrchestratorController.java

Source

/*
 Copyright 1995-2015 Esri
    
 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.
    
 For additional information, contact:
 Environmental Systems Research Institute, Inc.
 Attn: Contracts Dept
 380 New York Street
 Redlands, California, USA 92373
    
 email: contracts@esri.com
 */
package com.esri.geoevent.test.performance.ui;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.InputEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.lang3.StringUtils;

import com.esri.geoevent.test.performance.Mode;
import com.esri.geoevent.test.performance.OrchestratorRunner;
import com.esri.geoevent.test.performance.RunningException;
import com.esri.geoevent.test.performance.RunningState;
import com.esri.geoevent.test.performance.RunningStateListener;
import com.esri.geoevent.test.performance.jaxb.Fixture;
import com.esri.geoevent.test.performance.jaxb.Fixtures;
import com.esri.geoevent.test.performance.jaxb.Report;

public class OrchestratorController implements Initializable, RunningStateListener {

    //UI Elements

    @FXML
    public Label titleLabel;

    // menus
    @FXML
    public MenuBar menuBar;
    @FXML
    public Menu fileMenu;
    @FXML
    public MenuItem fileOpenMenuItem;
    @FXML
    public MenuItem fileSaveMenuItem;
    @FXML
    public Menu optionsMenu;
    @FXML
    public MenuItem optionsReportMenuItem;
    @FXML
    public MenuItem optionsLoggerMenuItem;
    @FXML
    public Menu helpMenu;
    @FXML
    public MenuItem helpAboutMenuItem;

    // fixtures
    @FXML
    public TabPane fixtureTabPane;
    @FXML
    public Button addFixtureBtn;
    @FXML
    public Button startBtn;
    @FXML
    public Label statusLabel;

    // member vars
    private Fixtures fixtures = new Fixtures();
    private Stage stage;
    private boolean isRunning;
    private OrchestratorRunner executor = null;
    private StringBuffer outputBuffer = new StringBuffer();

    // statics
    private static final String START_IMAGE_SOURCE = "images/play.png";
    private static final String STOP_IMAGE_SOURCE = "images/stop.png";

    public static final String DEFAULT_FIXTURES_FILE = "fixtures.xml";

    /**
     * Set up some defaults
     */
    public OrchestratorController() {
        this.fixtures = new Fixtures();
        this.fixtures.setDefaultFixture(new Fixture("Default"));
        this.fixtures.setReport(new Report());
        this.fixtures.setFixtures(new ArrayList<Fixture>());
    }

    /**
     * Sets the stage of this controller.
     *
     * @param stage dialogStage
     */
    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        titleLabel.setText(Mode.Orchestrator.toString());
        fileMenu.setText(UIMessages.getMessage("UI_FILE_MENU_LABEL"));
        fileOpenMenuItem.setText(UIMessages.getMessage("UI_FILE_OPEN_MENU_ITEM_LABEL"));
        fileSaveMenuItem.setText(UIMessages.getMessage("UI_FILE_SAVE_MENU_ITEM_LABEL"));
        optionsMenu.setText(UIMessages.getMessage("UI_OPTIONS_MENU_LABEL"));
        optionsLoggerMenuItem.setText(UIMessages.getMessage("UI_OPTIONS_LOGGER_MENU_ITEM_LABEL"));
        optionsReportMenuItem.setText(UIMessages.getMessage("UI_OPTIONS_REPORT_MENU_ITEM_LABEL"));
        helpMenu.setText(UIMessages.getMessage("UI_HELP_MENU_LABEL"));
        helpAboutMenuItem.setText(UIMessages.getMessage("UI_HELP_ABOUT_MENU_ITEM_LABEL"));
        addFixtureBtn.setTooltip(new Tooltip(UIMessages.getMessage("UI_ADD_FIXTURE_DESC")));
        startBtn.setText(UIMessages.getMessage("UI_START_BTN_LABEL"));
        startBtn.setTooltip(new Tooltip(UIMessages.getMessage("UI_START_BTN_DESC")));
        //TODO: We need use this to show status messages
        statusLabel.setText("This is where the status changes will be placed.");

        // setup
        setupTabs();
        redirectSystemOutAndErrToTextArea();
    }

    /**
     * Handle action related to input (in this case specifically only responds
     * to keyboard event CTRL-A).
     *
     * @param event Input event.
     */
    @FXML
    public void handleKeyInput(final InputEvent event) {
        if (event instanceof KeyEvent) {
            final KeyEvent keyEvent = (KeyEvent) event;
            if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.A) {
                provideAboutFunctionality();
            } else if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.R) {
                showReportOptionsDialog();
            } else if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.O) {
                openFixturesFile();
            } else if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.S) {
                saveFixturesFile();
            } else if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.L) {
                showLoggerDialog();
            }
        }
    }

    /**
     * Handle action related to "About" menu item.
     *
     * @param event Event on "About" menu item.
     */
    @FXML
    public void handleAboutAction(final ActionEvent event) {
        provideAboutFunctionality();
    }

    /**
     * Opens a dialog to display the current output.
     *
     * @param event ActionEvent
     */
    @FXML
    public void handleLoggerOptionsAction(final ActionEvent event) {
        showLoggerDialog();
    }

    /**
     * Opens a dialog to edit the report options. If the user clicks OK, the
     * changes are saved into the main configuration.
     *
     * @param event ActionEvent
     */
    @FXML
    public void handleReportOptionsAction(final ActionEvent event) {
        showReportOptionsDialog();
    }

    /**
     * Opens a file chooser dialog to load a fixtures.xml configuration file.
     *
     * @param event {@link ActionEvent}
     */
    @FXML
    public void handleOpenAction(final ActionEvent event) {
        openFixturesFile();
    }

    /**
     * Saves the current configuration as an xml file.
     *
     * @param event {@link ActionEvent}
     */
    @FXML
    public void handleSaveAction(final ActionEvent event) {
        saveFixturesFile();
    }

    /**
     * Adds a new fixture to the TabPane and to the fixtures model
     *
     * @param event ActionEvent
     */
    @FXML
    public void addFixture(final ActionEvent event) {
        Fixture defaultFixture = fixtures.getDefaultFixture();
        Fixture newFixture = new Fixture("NewFixture" + (fixtures.getFixtures().size() + 1));
        newFixture.apply(defaultFixture);
        fixtures.getFixtures().add(newFixture);
        addFixtureTab(newFixture, false);
    }

    /**
     * This is the main method which is used to start the simulation test
     *
     * @param event {@link ActionEvent} not used.
     */
    @FXML
    public void startTest(final ActionEvent event) {
        toggleRunningState(!isRunning);
    }

    /**
     * Helper method to toggle the UI running state
     */
    private void toggleRunningState(boolean newRunningState) {
        isRunning = newRunningState;
        if (isRunning) {
            // start the executor
            try {
                this.executor = new OrchestratorRunner(fixtures);
                this.executor.start();
                this.executor.setRunningStateListener(this);
            } catch (RunningException error) {
                //TODO: error handling
                error.printStackTrace();
            }

            // toggle the ui
            startBtn.setText(UIMessages.getMessage("UI_STOP_BTN_LABEL"));
            startBtn.setTooltip(new Tooltip(UIMessages.getMessage("UI_STOP_BTN_DESC")));
            startBtn.setGraphic(
                    new ImageView(new Image(FixtureController.class.getResourceAsStream(STOP_IMAGE_SOURCE))));
        } else {
            // stop execution
            if (this.executor != null) {
                if (this.executor.isRunning()) {
                    this.executor.stop();
                } else {
                    this.executor = null;
                }
            }

            startBtn.setText(UIMessages.getMessage("UI_START_BTN_LABEL"));
            startBtn.setTooltip(new Tooltip(UIMessages.getMessage("UI_START_BTN_DESC")));
            startBtn.setGraphic(
                    new ImageView(new Image(FixtureController.class.getResourceAsStream(START_IMAGE_SOURCE))));
        }
    }

    /**
     * Displays a file chooser to select a file to open
     */
    private void openFixturesFile() {
        File currentDir = Paths.get("").toAbsolutePath().toFile();
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle(UIMessages.getMessage("UI_OPEN_FILE_CHOOSER_TITLE"));
        fileChooser.setInitialDirectory(currentDir);
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("XML", "*.xml"));
        fileChooser.setInitialFileName(DEFAULT_FIXTURES_FILE);
        File file = fileChooser.showOpenDialog(stage);
        if (file != null) {
            try {
                loadFile(file);
                setupTabs();
            } catch (Exception error) {
                //TODO: Improve error handling and reporting
                error.printStackTrace();
            }
        }
    }

    /**
     * Helper method to load a file and unmarshall it using JAXB
     *
     * @param file File to load
     * @throws JAXBException if there is a unmarshalling problem
     */
    private void loadFile(File file) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(Fixtures.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        StreamSource xml = new StreamSource(file.getAbsolutePath());
        this.fixtures = (Fixtures) unmarshaller.unmarshal(xml);
    }

    /**
     * Displays a file chooser to select a file location to save the
     * configuration file.
     */
    private void saveFixturesFile() {
        File currentDir = Paths.get("").toAbsolutePath().toFile();
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle(UIMessages.getMessage("UI_SAVE_FILE_CHOOSER_TITLE"));
        fileChooser.setInitialDirectory(currentDir);
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("XML", "*.xml"));
        fileChooser.setInitialFileName(DEFAULT_FIXTURES_FILE);
        File file = fileChooser.showSaveDialog(stage);
        if (file != null) {
            try {
                saveFile(file);
            } catch (Exception error) {
                //TODO: Improve error handling and reporting
                error.printStackTrace();
            }
        }
    }

    /**
     * Saves the current fixtures file to disk.
     *
     * @param file File where to save the configuration file.
     * @throws JAXBException
     * @throws XMLStreamException
     * @throws IOException
     */
    private void saveFile(File file) throws JAXBException, XMLStreamException, IOException {
        JAXBContext jaxbContext = JAXBContext.newInstance(Fixtures.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        FileWriter fileWriter = new FileWriter(file);
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        XMLStreamWriter xmlWritter = factory.createXMLStreamWriter(fileWriter);
        marshaller.marshal(fixtures, xmlWritter);
        fileWriter.flush();
        fileWriter.close();
    }

    /**
     * Shows the report options dialog
     */
    private void showReportOptionsDialog() {
        try {
            // Load the fxml file and create a new stage for the popup
            FXMLLoader loader = new FXMLLoader(getClass().getResource("ReportOptions.fxml"));
            AnchorPane page = (AnchorPane) loader.load();
            Stage dialogStage = new Stage();
            dialogStage.setTitle(UIMessages.getMessage("UI_REPORT_OPTIONS_TITLE"));
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            dialogStage.initOwner(stage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            // Set the person into the controller
            ReportOptionsController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setReport(this.fixtures.getReport()); //TODO: we need to clone our Report Object Here

            // Show the dialog and wait until the user closes it
            dialogStage.showAndWait();
            if (controller.isOkClicked()) {
                this.fixtures.setReport(controller.getReport());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Shows the confirmation dialog
     */
    private boolean showConfirmationDialog(String msg) {
        try {
            // Load the fxml file and create a new stage for the popup
            FXMLLoader loader = new FXMLLoader(getClass().getResource("ConfirmationDialog.fxml"));
            Parent page = (Parent) loader.load();
            Stage dialogStage = new Stage();
            dialogStage.setTitle(UIMessages.getMessage("UI_CLOSE_TAB_TITLE"));
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            dialogStage.initOwner(stage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            // Set the person into the controller
            ConfirmationDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setConfirmationMsg(msg);

            // Show the dialog and wait until the user closes it
            dialogStage.showAndWait();
            return controller.isOkClicked();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Perform functionality associated with "About" menu selection or CTRL-A.
     */
    private void provideAboutFunctionality() {
        try {
            // Load the fxml file and create a new stage for the popup
            FXMLLoader loader = new FXMLLoader(getClass().getResource("AboutDialog.fxml"));
            Parent page = (Parent) loader.load();
            Stage dialogStage = new Stage();
            dialogStage.setTitle(UIMessages.getMessage("UI_HELP_ABOUT_MENU_ITEM_LABEL"));
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            dialogStage.initOwner(stage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            // Set the person into the controller
            AboutDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);

            // Show the dialog and wait until the user closes it
            dialogStage.showAndWait();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Perform functionality associated with "About" menu selection or CTRL-A.
     */
    private void showLoggerDialog() {
        try {
            // Load the fxml file and create a new stage for the popup
            FXMLLoader loader = new FXMLLoader(getClass().getResource("LoggerDialog.fxml"));
            Parent page = (Parent) loader.load();
            Stage dialogStage = new Stage();
            dialogStage.setTitle(UIMessages.getMessage("UI_LOGGER_BOX_LABEL"));
            dialogStage.initModality(Modality.NONE);
            dialogStage.initOwner(stage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            // Set the person into the controller
            LoggerDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setOutputBuffer(outputBuffer.toString());
            controller.onClearLoggerEvent(() -> outputBuffer = new StringBuffer());

            // Show the dialog
            dialogStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void setupTabs() {
        //clear them all out
        fixtureTabPane.getTabs().clear();

        // setup the tabs
        if (fixtures.getDefaultFixture() != null) {
            if (StringUtils.isEmpty(fixtures.getDefaultFixture().getName())) {
                fixtures.getDefaultFixture().setName("Default");
            }
            addFixtureTab(fixtures.getDefaultFixture(), true);
        }
        if (fixtures.getFixtures() != null) {
            for (Fixture fixture : fixtures.getFixtures()) {
                fixture.apply(fixtures.getDefaultFixture());
                addFixtureTab(fixture, false);
            }
        }
    }

    private void addFixtureTab(final Fixture fixture, boolean isDefault) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Fixture.fxml"));
            Parent fixtureTab = (Parent) loader.load();

            FixtureController controller = loader.getController();
            controller.setFixture(fixture);
            controller.setIsDefault(isDefault);

            Tab newTab = new Tab(fixture.getName());
            newTab.setContent(fixtureTab);
            newTab.closableProperty().setValue(!isDefault);
            newTab.setOnCloseRequest(event -> {
                boolean isOkClicked = showConfirmationDialog(
                        UIMessages.getMessage("UI_CLOSE_TAB_LABEL", fixture.getName()));
                if (!isOkClicked) {
                    event.consume();
                } else {
                    fixtures.getFixtures().remove(fixture);
                }
            });
            fixtureTabPane.getTabs().add(newTab);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Running State Listener - this is used so we get notified when the
     * orchestration is complete
     */
    @Override
    public void onStateChange(RunningState newState) {
        switch (newState.getType()) {
        case STOPPED:
            toggleRunningState(false);
            break;

        default:
            break;
        }
    }

    private void redirectSystemOutAndErrToTextArea() {
        OutputStream out = new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                Platform.runLater(() -> outputBuffer.append(String.valueOf((char) b)));
            }
        };
        System.setOut(new PrintStream(out, true));
        OutputStream err = new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                Platform.runLater(() -> outputBuffer.append(String.valueOf((char) b)));
            }
        };
        System.setErr(new PrintStream(err, true));
    }
}