/*
* 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.tamaya.examples.distributed;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.json.Json;
import io.vertx.core.spi.cluster.ClusterManager;
import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import org.apache.tamaya.ConfigurationProvider;
import org.apache.tamaya.core.propertysource.EnvironmentPropertySource;
import org.apache.tamaya.core.propertysource.SystemPropertySource;
import org.apache.tamaya.functions.ConfigurationFunctions;
import org.apache.tamaya.hazelcast.HazelcastPropertySource;
import org.apache.tamaya.inject.ConfigurationInjection;
import org.apache.tamaya.inject.api.Config;
import org.apache.tamaya.spi.*;
import java.time.LocalDateTime;
import java.util.logging.Logger;
/**
* Created by atsticks on 12.11.16.
*/
public class Display extends Application{
private static final Logger LOG = Logger.getLogger(Display.class.getSimpleName());
public static final String DISPLAY_SHOW_TOPIC = "Display::show";
public static final String DISPLAY_REGISTER_TOPIC = "Display::register";
public static final String CONTENT_FIELD = "content";
@Config(defaultValue="UNKNOWN DISPLAY")
private String displayName;
private Scene scene;
private Group root = new Group();
private Stage stage;
private TextField titleField = new TextField("title");
private TextField configFilterField = new TextField("");
private TextArea contentField = new TextArea("scene");
private TextArea monitorField = new TextArea("monitor");
private DisplayContent displayContent = new DisplayContent();
private DisplayRegistration registration;
private StringBuffer monitorBuffer = new StringBuffer();
private Vertx vertx;
private static HazelcastPropertySource hazelCastPropertySource;
public Display(){
LOG.info("\n-----------------------------------\n" +
"Starting Display...\n" +
"-----------------------------------");
LOG.info("--- Starting Vertx cluster...");
// Reusing the hazelcast instance already in place for vertx...
ClusterManager mgr = new HazelcastClusterManager(
hazelCastPropertySource.getHazelcastInstance());
VertxOptions vertxOptions = new VertxOptions().setClusterManager(mgr);
Vertx.clusteredVertx(vertxOptions, h -> {
vertx = h.result();
});
LOG.info("--- Waiting for Vertx cluster...");
while(vertx==null){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
titleField.getStyleClass().add("title");
contentField.getStyleClass().add("content");
monitorField.getStyleClass().add("monitor");
titleField.setId("title");
titleField.setEditable(false);
contentField.setId("scene");
contentField.setEditable(false);
}
@Override
public void start(Stage stage) throws Exception {
this.stage = stage;
LOG.info("--- Configuring application...");
ConfigurationInjection.getConfigurationInjector()
.configure(this);
LOG.info("--- Registering display...");
registerDisplay();
LOG.info("--- Starting stage...");
initStage(stage);
registerListeners();
LOG.info("--- Showing stage...");
stage.show();
LOG.info("\n---------------\n" +
"Display started\n" +
"---------------");
}
private void registerDisplay() {
registration = new DisplayRegistration(displayName);
logToMonitor("Display started at " + LocalDateTime.now() +
"\n id = " + registration.getId() +
"\n name = " + registration.getDisplayName());
// Register in the shared map every 10 seconds, with a TTL of 20 seconds...
vertx.eventBus().publish(DISPLAY_REGISTER_TOPIC, Json.encode(registration));
vertx.periodicStream(10000).handler(time -> {
registration = registration.update();
vertx.eventBus().publish(DISPLAY_REGISTER_TOPIC, Json.encode(registration));
vertx.sharedData().getClusterWideMap("displays", h -> {
h.result().put(registration.getId(), registration, 20000L, null);
});
});
}
private void registerListeners() {
// registering update hook
vertx.eventBus().consumer(DISPLAY_SHOW_TOPIC, h -> {
DisplayContent content = Json.decodeValue((String)h.body(), DisplayContent.class);
logToMonitor("NEW CONTENT: " + content.toString());
if(registration.getId().equals(content.displayId)) {
logToMonitor("Applying content: " + content + "...");
titleField.setText(content.title);
contentField.setText(content.content.get(CONTENT_FIELD));
if(content.displayName!=null) {
this.registration.setDisplayName(
content.displayName
);
Platform.runLater(() -> {
this.stage.setTitle(content.displayName);
});
}
logToMonitor("SUCCESS.");
}
});
vertx.eventBus().consumer(DISPLAY_REGISTER_TOPIC, h -> {
DisplayRegistration registration = Json.decodeValue((String)h.body(), DisplayRegistration.class);
logToMonitor("NEW DISPLAY: " + registration.toString());
});
}
private void initStage(Stage stage) {
stage.setTitle(registration.getDisplayName());
scene = new Scene(root, Color.WHITE);
scene.getStylesheets().add("/stylesheet.css");
BorderPane layout = new BorderPane();
layout.getStyleClass().add("main-layout");
layout.setPrefSize(600, 400);
// layout.setTop(createWinTitle());
Node displayPanel = createDisplayNode();
Node monitorPanel = createMonitorNode();
TabPane tabPane = new TabPane();
tabPane.getStylesheets().add("main-tabs");
Tab tab0 = new Tab("Display", displayPanel);
tab0.setClosable(false);
Tab tab1 = new Tab("Monitor", monitorPanel);
tab1.setClosable(false);
tabPane.getTabs().add(0, tab0);
tabPane.getTabs().add(1, tab1);
layout.setCenter(tabPane);
layout.setBottom(createStatusPane());
scene.setRoot(layout);
stage.setScene(scene);
}
private Node createStatusPane() {
return new Label();
}
private Node createMonitorNode() {
VBox vbox = new VBox();
ScrollPane monitorPane = new ScrollPane(monitorField);
monitorPane.setFitToHeight(true);
monitorPane.setFitToWidth(true);
monitorField.setPrefSize(2000,2000);
vbox.getChildren().addAll(monitorPane);
return vbox;
}
private Node createDisplayNode() {
VBox vbox = new VBox();
ScrollPane contentPane = new ScrollPane(contentField);
contentPane.setFitToHeight(true);
contentPane.setFitToWidth(true);
titleField.setText("- Nothing to show -");
contentField.setText("- Nothing to show -");
vbox.getChildren().addAll(titleField, contentPane, createButtonPane());
return vbox;
}
private Pane createButtonPane() {
HBox buttonLayout = new HBox();
buttonLayout.getStyleClass().add("button-pane");
Button showConfig = new Button("Show Config");
showConfig.setId("showConfig-button");
showConfig.onActionProperty().set(h -> {
if("Hide Config".equals(showConfig.getText())){
monitorField.setText(monitorBuffer.toString());
showConfig.setText("Show Config");
}else {
showConfig();
showConfig.setText("Hide Config");
}
});
configFilterField.onActionProperty().set(h -> {
showConfig();
});
configFilterField.setId("configFilter-field");
buttonLayout.getChildren().addAll(showConfig, configFilterField);
return buttonLayout;
}
private void showConfig() {
String filter = configFilterField.getText();
String configAsText = null;
if(filter!=null && !filter.trim().isEmpty()){
configAsText = ConfigurationProvider.getConfiguration()
.with(ConfigurationFunctions.section(filter))
.query(ConfigurationFunctions.textInfo());
}else{
configAsText = ConfigurationProvider.getConfiguration()
.query(ConfigurationFunctions.textInfo());
}
monitorField.setText(configAsText);
}
public static void main(String[] args) {
// Programmatically setup our configuration
hazelCastPropertySource = new HazelcastPropertySource();
ConfigurationContext ctx = ConfigurationProvider.getConfigurationContextBuilder()
.addPropertySources(
new EnvironmentPropertySource(),
new SystemPropertySource(),
hazelCastPropertySource
)
.addDefaultPropertyConverters()
.build();
ConfigurationProvider.setConfiguration(
ConfigurationProvider.createConfiguration(ctx));
// Launch the app
Application.launch(Display.class);
}
public void logToMonitor(String message){
if(!message.endsWith("\n")){
monitorBuffer.append(message + '\n');
}else{
monitorBuffer.append(message);
}
synchronized (monitorField) {
monitorField.setText(monitorBuffer.toString());
}
}
}