TAMAYA-195: Added hazelcast support (small multi VM JavaFX Demo).
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/57df9012 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/57df9012 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/57df9012 Branch: refs/heads/master Commit: 57df9012d1ef6e736b925a41df2c2c60fe460110 Parents: fcf2730 Author: anatole <[email protected]> Authored: Sun Nov 13 23:27:18 2016 +0100 Committer: anatole <[email protected]> Committed: Sun Nov 13 23:27:18 2016 +0100 ---------------------------------------------------------------------- examples/11-distributed/pom.xml | 85 ++++++ .../distributed/ContentManagerPanel.java | 122 ++++++++ .../tamaya/examples/distributed/Display.java | 293 +++++++++++++++++++ .../examples/distributed/DisplayContent.java | 59 ++++ .../examples/distributed/DisplayManager.java | 276 +++++++++++++++++ .../distributed/DisplayRegistration.java | 123 ++++++++ .../org.apache.tamaya.spi.PropertySource | 19 ++ .../src/main/resources/stylesheet.css | 38 +++ .../distributed/DisplayContentTest.java | 48 +++ .../distributed/DisplayRegistrationTest.java | 70 +++++ 10 files changed, 1133 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/pom.xml ---------------------------------------------------------------------- diff --git a/examples/11-distributed/pom.xml b/examples/11-distributed/pom.xml new file mode 100644 index 0000000..5c5b8d3 --- /dev/null +++ b/examples/11-distributed/pom.xml @@ -0,0 +1,85 @@ +<!-- + ~ 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-examples</artifactId> + <version>0.3-incubating-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>tamaya-example-distributed</artifactId> + <groupId>org.apache.tamaya.examples</groupId> + <name>Apache Tamaya Example: Distributed Configuration</name> + <description>This project contains a simple example based on JavaFX and Vertx.</description> + <packaging>jar</packaging> + + <properties> + <jdkVersion>1.8</jdkVersion> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.tamaya</groupId> + <artifactId>tamaya-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-core</artifactId> + <version>3.2.0</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-mutable-config</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-hazelcast</artifactId> + <version>3.3.3</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-hazelcast</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>java-hamcrest</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + +</project> http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/ContentManagerPanel.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/ContentManagerPanel.java b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/ContentManagerPanel.java new file mode 100644 index 0000000..9ac7aeb --- /dev/null +++ b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/ContentManagerPanel.java @@ -0,0 +1,122 @@ +/* + * 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 com.sun.deploy.uitoolkit.impl.fx.ui.FXAppContext; +import io.vertx.core.Vertx; +import io.vertx.core.json.Json; +import javafx.application.Platform; +import javafx.embed.swing.SwingFXUtils; +import javafx.geometry.Orientation; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.ConfigurationProvider; +import org.apache.tamaya.functions.ConfigurationFunctions; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * Created by atsticks on 13.11.16. + */ +class ContentManagerPanel extends VBox{ + + private ChoiceBox selector = new ChoiceBox(); + private TextField titleField = new TextField(); + private TextArea contentField = new TextArea(); + private TextField displayNameField = new TextField(); + private Button sendButton = new Button("Update Content"); + private Configuration config; + private Vertx vertx; + + public ContentManagerPanel(Vertx vertx){ + this.vertx = vertx; + displayNameField.setMinHeight(30.0); + displayNameField.setMinWidth(200.0); + displayNameField.setId("displayNameField"); + titleField.setMinHeight(30.0); + titleField.setMinWidth(200.0); + titleField.setId("title"); + titleField.setFont(Font.font("Arial", FontWeight.BOLD, 24)); + titleField.setStyle("-fx-text-fill: #EFEFEF; -fx-background-color: black;"); + contentField.setId("scene"); + contentField.setFont(Font.font("Arial", FontWeight.LIGHT, 18)); + getChildren().addAll(selector, new Label("Title"), titleField, new Label("content"), contentField, + new Label("Display Name"), displayNameField, new Separator(Orientation.VERTICAL), sendButton); + sendButton.setOnAction(h -> { + String selection = (String)selector.getSelectionModel().getSelectedItem(); + if(selection!=null){ + String uuid = selection.split("::")[1]; + DisplayContent content = new DisplayContent(); + content.content.put(Display.CONTENT_FIELD, contentField.getText()); + content.title = titleField.getText(); + content.displayId = uuid; + content.displayName = displayNameField.getText(); + vertx.eventBus().publish(Display.DISPLAY_SHOW_TOPIC, Json.encode(content)); + } + }); + selector.setOnAction(h -> { + String selection = (String)selector.getSelectionModel().getSelectedItem(); + if(selection!=null) { + displayNameField.setText(selection.split("::")[0]); + } + }); + updateList(); + vertx.periodicStream(5000).handler(h -> { + updateList(); + }); + } + + public void updateList(){ + config = ConfigurationProvider.getConfiguration() + .with(ConfigurationFunctions.section("displays.", true)); + // resulting config: + // ----------------- + // UUID.displayName + // UUID.content.title + // UUID.content.content + // UUID.timestamp + final Set<String> keys = new TreeSet<>(); + for(Map.Entry<String,String> en:config.getProperties().entrySet()){ + if(en.getKey().endsWith(".displayName")){ + String uuid = en.getKey().substring(0,36); + keys.add(en.getValue()+"::"+uuid); + } + } + Platform.runLater(() -> { + final Set<String> exKeys = new HashSet<String>(selector.getItems()); + for(Object item:exKeys){ + if(!keys.contains(item)){ + selector.getItems().remove(item); + } + } + for(String item:keys){ + if(!selector.getItems().contains(item)){ + selector.getItems().add(item); + } + } + }); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/Display.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/Display.java b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/Display.java new file mode 100644 index 0000000..fb95a07 --- /dev/null +++ b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/Display.java @@ -0,0 +1,293 @@ +/* + * 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()); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayContent.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayContent.java b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayContent.java new file mode 100644 index 0000000..18ba302 --- /dev/null +++ b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayContent.java @@ -0,0 +1,59 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Created by atsticks on 13.11.16. + */ +public class DisplayContent { + public String displayId; + public String title = "UNKNOWN"; + public Map<String,String> content = new HashMap<>(); + public long timestamp = System.currentTimeMillis(); + public String displayName; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DisplayContent)) return false; + DisplayContent that = (DisplayContent) o; + return timestamp == that.timestamp && + Objects.equals(displayId, that.displayId) && + Objects.equals(title, that.title); + } + + @Override + public int hashCode() { + return Objects.hash(displayId, title, timestamp); + } + + @Override + public String toString() { + return "DisplayContent{" + + "displayId='" + displayId + '\'' + + ", title='" + title + '\'' + + ", content=" + content + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayManager.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayManager.java b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayManager.java new file mode 100644 index 0000000..efd200b --- /dev/null +++ b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayManager.java @@ -0,0 +1,276 @@ +/* + * 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.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.scene.text.Font; +import javafx.scene.text.FontWeight; +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.mutableconfig.MutableConfiguration; +import org.apache.tamaya.mutableconfig.MutableConfigurationProvider; +import org.apache.tamaya.spi.ConfigurationContext; + +import java.util.logging.Logger; + +/** + * Created by atsticks on 12.11.16. + */ +public class DisplayManager extends Application{ + + private static final Logger LOG = Logger.getLogger(DisplayManager.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"; + + private Scene scene; + + private Group root = new Group(); + + private TextField configFilterField = new TextField(""); + + private TextArea configField = new TextArea(); + + private TextArea monitorField = new TextArea("Nothing to monitor yet."); + + private StringBuffer monitorBuffer = new StringBuffer(); + + private Vertx vertx; + + private static HazelcastPropertySource hazelCastPropertySource; + + public DisplayManager(){ + LOG.info("\n-----------------------------------\n" + + "Starting DisplayDisplayManager...\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(); + } + } + monitorField.getStyleClass().add("monitor"); + configField.getStyleClass().add("config"); + } + + @Override + public void start(Stage stage) throws Exception { + LOG.info("--- Configuring application..."); + ConfigurationInjection.getConfigurationInjector() + .configure(this); + LOG.info("--- Starting stage..."); + initStage(stage); + registerListeners(); + LOG.info("--- Showing stage..."); + stage.show(); + LOG.info("\n----------------------\n" + + "DisplayManager started\n" + + "----------------------"); + } + + 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()); + logToMonitor("Updating config for content: " + content + "..."); + MutableConfiguration config = MutableConfigurationProvider.createMutableConfiguration(); + String id = content.displayId; + config.put("displays."+id+".title", content.title); + config.put("displays."+id+".timestamp", String.valueOf(content.timestamp)); + config.put("displays."+id+".content.content", content.content.get(CONTENT_FIELD)); + config.store(); + logToMonitor("UPDATED."); + }); + vertx.eventBus().consumer(DISPLAY_REGISTER_TOPIC, h -> { + DisplayRegistration registration = Json.decodeValue((String)h.body(), DisplayRegistration.class); + if(registration.isUpdate()){ + logToMonitor("UDT DISPLAY: " + registration.getId()); + }else{ + logToMonitor("NEW DISPLAY: " + registration.toString()); + } + MutableConfiguration config = MutableConfigurationProvider.createMutableConfiguration(); + String id = registration.getId(); + config.put("displays."+id+".displayName", registration.getDisplayName()); + config.put("_displays."+id+".displayName.ttl", "10000"); + if(registration.getHost()!=null) { + config.put("displays." + id + ".host", registration.getHost()); + config.put("_displays." + id + ".host.ttl", "10000"); + } + config.put("displays."+id+".displayModel", registration.getDisplayModel()); + config.put("_displays."+id+".displayModel.ttl", "10000"); + config.store(); + logToMonitor("UPDATED."); + }); + } + + private void initStage(Stage stage) { + stage.setTitle("Display Manager"); + scene = new Scene(root, Color.RED); + scene.getStylesheets().add("/stylesheet.css"); + + BorderPane layout = new BorderPane(); + layout.getStyleClass().add("main-layout"); +// layout.setPrefSize(600, 400); +// layout.setTop(createWinTitle()); + + Node configPanel = createConfigNode(); + Node monitorPanel = createMonitorNode(); + + TabPane tabPane = new TabPane(); + tabPane.getStylesheets().add("main-tabs"); + Tab tab0 = new Tab("Monitor", monitorPanel); + tab0.setClosable(false); + Tab tab1 = new Tab("Configuration", configPanel); + tab1.setClosable(false); + Tab tab2 = new Tab("Content Manager", new ContentManagerPanel(vertx)); + tab2.setClosable(false); + tabPane.getTabs().add(0, tab0); + tabPane.getTabs().add(1, tab1); + tabPane.getTabs().add(2, tab2); + 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 createConfigNode() { + VBox vbox = new VBox(); + ScrollPane contentPane = new ScrollPane(configField); + contentPane.setFitToHeight(true); + contentPane.setFitToWidth(true); + configField.setPrefSize(2000,2000); + vbox.getChildren().addAll(contentPane, createButtonPane()); + return vbox; + } + + private Node createWinTitle() { + Label winTitle = new Label(); + winTitle.setMinHeight(30.0); + winTitle.setMinWidth(200.0); + winTitle.setId("wintitle"); + winTitle.setText("Tamaya Config Demo - DisplayManager"); + return winTitle; + } + + private Pane createButtonPane() { + HBox buttonLayout = new HBox(); + buttonLayout.getStyleClass().add("button-pane"); + Button refreshConfig = new Button("Refresh Config"); + refreshConfig.setId("refreshConfig-button"); + refreshConfig.onActionProperty().set(h -> { + showConfig(); + }); + configFilterField.onActionProperty().set(h -> { + showConfig(); + }); + configFilterField.setId("configFilter-field"); + buttonLayout.getChildren().addAll(refreshConfig, 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()); + } + configField.setText(configAsText); + } + + public void logToMonitor(String message){ + if(!message.endsWith("\n")){ + monitorBuffer.append(message + '\n'); + }else{ + monitorBuffer.append(message); + } + synchronized (monitorField) { + monitorField.setText(monitorBuffer.toString()); + } + } + + 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(DisplayManager.class); + } + + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayRegistration.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayRegistration.java b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayRegistration.java new file mode 100644 index 0000000..a2a181e --- /dev/null +++ b/examples/11-distributed/src/main/java/org/apache/tamaya/examples/distributed/DisplayRegistration.java @@ -0,0 +1,123 @@ +/* + * 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 java.io.Serializable; +import java.net.InetAddress; +import java.util.Objects; +import java.util.UUID; + +/** + * Created by atsticks on 13.11.16. + */ +public class DisplayRegistration implements Serializable{ + + private static final long serialVersionUID = 1L; + + private String id; + private String displayName; + private String host; + private String displayModel; + private boolean update; + private long timestamp = System.currentTimeMillis(); + + private DisplayRegistration(){} + + public DisplayRegistration(String displayName) { + this.displayName = Objects.requireNonNull(displayName); + this.displayModel = "fxDemo"; + + this.id = UUID.randomUUID().toString(); + } + + public DisplayRegistration(String displayName, String displayModel) { + this.displayModel = Objects.requireNonNull(displayModel); + this.displayName = Objects.requireNonNull(displayName); + this.id = UUID.randomUUID().toString(); + InetAddress adr = null; + try{ + adr = InetAddress.getLocalHost(); + this.host = adr.getCanonicalHostName(); + } + catch(Exception e){ + this.host = adr.getHostName(); + } + } + + public boolean isUpdate(){ + return this.update; + } + + public String getDisplayModel() { + return displayModel; + } + + public String getDisplayName() { + return displayName; + } + + public String getHost() { + return host; + } + + public String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) {return true;} + if (!(o instanceof DisplayRegistration)) {return false;} + DisplayRegistration that = (DisplayRegistration) o; + return Objects.equals(getId(), that.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(getId()); + } + + @Override + public String toString() { + return "DisplayRegistration{" + + "\n id='" + id + '\'' + + "\n displayName='" + displayName + '\'' + + "\n host='" + host + '\'' + + "\n displayModel='" + displayModel + '\'' + + "\n timestamp='" + timestamp + '\'' + + "\n update='" + update + '\'' + + "\n}"; + } + + public DisplayRegistration update() { + DisplayRegistration reg = new DisplayRegistration(); + reg.displayModel = this.displayModel; + reg.displayName = this.displayName; + reg.host = this.host; + reg.id = this.id; + reg.update = true; + reg.timestamp = System.currentTimeMillis(); + return reg; + } + + public void setDisplayName(String displayName) { + this.displayName = Objects.requireNonNull(displayName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource b/examples/11-distributed/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource new file mode 100644 index 0000000..a2a4042 --- /dev/null +++ b/examples/11-distributed/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertySource @@ -0,0 +1,19 @@ +# +# 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 current 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. +# +#org.apache.tamaya.examples.remote.client.RemotePropertySource \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/main/resources/stylesheet.css ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/main/resources/stylesheet.css b/examples/11-distributed/src/main/resources/stylesheet.css new file mode 100644 index 0000000..2eb6c4f --- /dev/null +++ b/examples/11-distributed/src/main/resources/stylesheet.css @@ -0,0 +1,38 @@ +.text{ + -fx-font: bold 12pt "Arial"; + -fx-background-color: light-grey; +} +.button{ + -fx-font: bold 12pt "Arial"; + -fx-text-fill: rgb(49, 89, 23); + -fx-border-color: rgb(49, 89, 23); + -fx-border-radius: 5; + -fx-padding: 3 6 6 6; +} +#wintitle{ + -fx-font: bold 36pt "Arial"; + -fx-text-fill: #FFBDBD; + -fx-background-color: black; +} +.main-layout{ + -fx-width: 100%; + -fx-height: 100%; +} +.title{ + -fx-font: bold 24pt "Arial"; + -fx-text-fill: #EFEFEF; + -fx-background-color: light-grey; + -fx-text-fill: rgb(49, 89, 23); + -fx-border-color: rgb(49, 89, 23); + -fx-border-size: 0; + -fx-border-radius: 3; + -fx-padding: 3 6 6 6; + -fx-min-height: 40; + -fx-min-width: 200; +} +.content{ + -fx-font: bold 18pt "Arial"; +} +.monitor{ + -fx-font: bold 16pt "Courier New"; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayContentTest.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayContentTest.java b/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayContentTest.java new file mode 100644 index 0000000..bf92e88 --- /dev/null +++ b/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayContentTest.java @@ -0,0 +1,48 @@ +/* + * 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.json.Json; + +import static org.junit.Assert.*; + +/** + * Created by atsticks on 13.11.16. + */ +public class DisplayContentTest { + + @org.junit.Test + public void testToString() throws Exception { + + } + + @org.junit.Test + public void testJson() throws Exception { + DisplayContent content = new DisplayContent(); + content.displayId = "1234"; + content.title = "myTitle"; + content.content.put("content", "myContent"); + String val = Json.encode(content); + DisplayContent decoded = Json.decodeValue(val, DisplayContent.class); + assertNotNull(decoded); + assertEquals(content, decoded); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/57df9012/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayRegistrationTest.java ---------------------------------------------------------------------- diff --git a/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayRegistrationTest.java b/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayRegistrationTest.java new file mode 100644 index 0000000..c23728d --- /dev/null +++ b/examples/11-distributed/src/test/java/org/apache/tamaya/examples/distributed/DisplayRegistrationTest.java @@ -0,0 +1,70 @@ +/* + * 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.json.Json; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by atsticks on 13.11.16. + */ +public class DisplayRegistrationTest { + @Test + public void getDisplayModel() throws Exception { + + } + + @Test + public void getDisplayName() throws Exception { + + } + + @Test + public void getHost() throws Exception { + + } + + @Test + public void getId() throws Exception { + + } + + @Test + public void testEquals() throws Exception { + + } + + @Test + public void testToString() throws Exception { + + } + + @org.junit.Test + public void testJson() throws Exception { + DisplayRegistration reg = new DisplayRegistration("myDisplay", "VT100"); + String val = Json.encode(reg); + DisplayRegistration decoded = Json.decodeValue(val, DisplayRegistration.class); + assertNotNull(decoded); + assertEquals(reg, decoded); + } + +} \ No newline at end of file
