diff --git a/.classpath b/.classpath
index 8473db1..0369b72 100644
--- a/.classpath
+++ b/.classpath
@@ -1,8 +1,11 @@
+
+
+
diff --git a/LightspeedJarLoader.zip b/LightspeedJarLoader.zip
new file mode 100644
index 0000000..3b893aa
Binary files /dev/null and b/LightspeedJarLoader.zip differ
diff --git a/data/lightspeed.sql b/data/lightspeed.sql
index eddc082..463e589 100644
--- a/data/lightspeed.sql
+++ b/data/lightspeed.sql
@@ -19,8 +19,7 @@ CREATE TABLE IF NOT EXISTS builds (
test_total INTEGER,
test_failures INTEGER,
test_errors INTEGER,
- test_skipped INTEGER,
- jar TEXT
+ test_skipped INTEGER
);
CREATE TABLE IF NOT EXISTS deployments (
diff --git a/fxml/BuildDataPane.css b/fxml/BuildDataPane.css
deleted file mode 100644
index 3e9698b..0000000
--- a/fxml/BuildDataPane.css
+++ /dev/null
@@ -1,40 +0,0 @@
-
-#idText {
- -fx-font-weight: bold;
-}
-
-.Text {
- -fx-padding: 5 0 5 0;
-}
-
-.table-view {
- -fx-focus-color: transparent;
- -fx-min-height: 50px;
-}
-
-.column-header {
- -fx-text-fill: white;
- -fx-font-size: 10pt;
- -fx-cell-size: 30px;
-}
-
-.table-cell {
- -fx-alignment: CENTER-LEFT;
- -fx-font-size: 10pt;
- -fx-fill: white;
-}
-
-.table-row-cell {
- -fx-cell-size: 30px;
-}
-
-.table-row-cell:filled:selected {
- -fx-background: -fx-control-inner-background ;
- -fx-background-color: -fx-table-cell-border-color, -fx-background ;
- -fx-background-insets: 0, 0 0 1 0 ;
- -fx-table-cell-border-color: derive(-fx-color, 5%);
-}
-
-.table-row-cell:odd:filled:selected {
- -fx-background: -fx-control-inner-background-alt ;
-}
diff --git a/fxml/BuildDataPane.fxml b/fxml/BuildDataPane.fxml
deleted file mode 100644
index b03162b..0000000
--- a/fxml/BuildDataPane.fxml
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fxml/CreateServerPane.css b/fxml/CreateServerPane.css
deleted file mode 100644
index c5f3123..0000000
--- a/fxml/CreateServerPane.css
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#idText {
- -fx-font-weight: bold;
-}
-
-.Text {
- -fx-padding: 5 0 5 0;
-}
diff --git a/fxml/CreateServerPane.fxml b/fxml/CreateServerPane.fxml
deleted file mode 100644
index 7239c36..0000000
--- a/fxml/CreateServerPane.fxml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fxml/DeploymentDataPane.css b/fxml/DeploymentDataPane.css
deleted file mode 100644
index c5f3123..0000000
--- a/fxml/DeploymentDataPane.css
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#idText {
- -fx-font-weight: bold;
-}
-
-.Text {
- -fx-padding: 5 0 5 0;
-}
diff --git a/fxml/DeploymentDataPane.fxml b/fxml/DeploymentDataPane.fxml
deleted file mode 100644
index 0f544e7..0000000
--- a/fxml/DeploymentDataPane.fxml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fxml/PrimaryView.css b/fxml/PrimaryView.css
index 55ebf6c..e3ab984 100644
--- a/fxml/PrimaryView.css
+++ b/fxml/PrimaryView.css
@@ -1,37 +1,56 @@
-.text-field {
- -fx-font-size: 10pt;
+#primaryViewContainer {
+ -fx-background-color: #000000;
+ -fx-text-fill: #FFFFFF;
}
-.text-view {
- -fx-font-size: 10pt;
+#commonPanel {
+ -fx-border-color: #000000;
+ -fx-border-width: 0 0 1 0;
+ -fx-border-style: solid;
}
-.table-view {
+#primaryTabGeneral {
+ -fx-text-fill: #FFFFFF;
+}
+
+.tab-pane .tab-header-area .tab-header-background {
+ -fx-opacity: 0.0;
+}
+
+.tab-pane {
+ -fx-tab-min-width: 150.0px;
+ -fx-text-fill: #FFFFFF;
+}
+
+.tab-header-area {
+ -fx-border-color: #3c3c3c;
+ -fx-border-width: 0 0 1 0;
+ -fx-border-style: solid;
+}
+
+.tab {
+ -fx-background-insets: 0.0 1.0 0.0 1.0, 0.0, 0.0;
+}
+
+.tab-pane .tab {
+ -fx-background-color: #e6e6e6;
-fx-focus-color: transparent;
+ -fx-faint-focus-color: transparent;
}
-.column-header {
- -fx-text-fill: white;
- -fx-font-size: 12pt;
+.tab-pane .tab:selected {
+ -fx-background-color: #3c3c3c;
+ -fx-border-width: 0 0 0 0;
}
-.table-cell {
- -fx-alignment: CENTER-LEFT;
- -fx-font-size: 12pt;
- -fx-fill: white;
+.tab .tab-label {
+ -fx-alignment: CENTER;
+ -fx-text-fill: #000000;
+ -fx-font-size: 12.0px;
+ -fx-font-weight: bold;
}
-.table-row-cell {
- -fx-cell-size: 50px;
-}
-
-.table-row-cell:filled:selected {
- -fx-background: -fx-control-inner-background ;
- -fx-background-color: -fx-table-cell-border-color, -fx-background ;
- -fx-background-insets: 0, 0 0 1 0 ;
- -fx-table-cell-border-color: derive(-fx-color, 5%);
-}
-
-.table-row-cell:odd:filled:selected {
- -fx-background: -fx-control-inner-background-alt ;
+.tab:selected .tab-label {
+ -fx-alignment: CENTER;
+ -fx-text-fill: #00af00;
}
diff --git a/fxml/PrimaryView.fxml b/fxml/PrimaryView.fxml
index a7102ed..f67622a 100644
--- a/fxml/PrimaryView.fxml
+++ b/fxml/PrimaryView.fxml
@@ -1,41 +1,39 @@
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fxml/primary_tabs/Build.css b/fxml/primary_tabs/Build.css
new file mode 100644
index 0000000..276b8e9
--- /dev/null
+++ b/fxml/primary_tabs/Build.css
@@ -0,0 +1,11 @@
+.white-label {
+ -fx-text-fill: #FFFFFF;
+}
+
+.red-label {
+ -fx-text-fill: #ff1e1e;
+}
+
+.green-label {
+ -fx-text-fill: #04ff00;
+}
diff --git a/fxml/primary_tabs/Build.fxml b/fxml/primary_tabs/Build.fxml
new file mode 100644
index 0000000..147b264
--- /dev/null
+++ b/fxml/primary_tabs/Build.fxml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fxml/primary_tabs/Deployment.css b/fxml/primary_tabs/Deployment.css
new file mode 100644
index 0000000..02e2aad
--- /dev/null
+++ b/fxml/primary_tabs/Deployment.css
@@ -0,0 +1,24 @@
+.white-label {
+ -fx-text-fill: #FFFFFF;
+}
+
+.red-label {
+ -fx-text-fill: #ff1e1e;
+}
+
+.green-label {
+ -fx-text-fill: #04ff00;
+}
+
+.log-wrapper {
+ -fx-background: #3F4042;
+ -fx-background-color: #3F4042;
+ -fx-border-color: white;
+ -fx-border-width: 1 0 1 0;
+}
+
+.log {
+ -fx-text-fill: #FFFFFF;
+ -fx-alignment: top-left;
+ -fx-text-alignment: left;
+}
diff --git a/fxml/primary_tabs/Deployment.fxml b/fxml/primary_tabs/Deployment.fxml
new file mode 100644
index 0000000..923b9b7
--- /dev/null
+++ b/fxml/primary_tabs/Deployment.fxml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fxml/primary_tabs/General.css b/fxml/primary_tabs/General.css
new file mode 100644
index 0000000..276b8e9
--- /dev/null
+++ b/fxml/primary_tabs/General.css
@@ -0,0 +1,11 @@
+.white-label {
+ -fx-text-fill: #FFFFFF;
+}
+
+.red-label {
+ -fx-text-fill: #ff1e1e;
+}
+
+.green-label {
+ -fx-text-fill: #04ff00;
+}
diff --git a/fxml/primary_tabs/General.fxml b/fxml/primary_tabs/General.fxml
new file mode 100644
index 0000000..fd3149c
--- /dev/null
+++ b/fxml/primary_tabs/General.fxml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hamcrest-core-1.3.jar b/hamcrest-core-1.3.jar
new file mode 100644
index 0000000..9d5fe16
Binary files /dev/null and b/hamcrest-core-1.3.jar differ
diff --git a/junit-4.12.jar b/junit-4.12.jar
new file mode 100644
index 0000000..3a7fc26
Binary files /dev/null and b/junit-4.12.jar differ
diff --git a/lib/rt.jar b/lib/rt.jar
new file mode 100755
index 0000000..7ac1a74
Binary files /dev/null and b/lib/rt.jar differ
diff --git a/src/com/projectswg/CombinedLightspeed.java b/src/com/projectswg/CombinedLightspeed.java
new file mode 100644
index 0000000..6cfde99
--- /dev/null
+++ b/src/com/projectswg/CombinedLightspeed.java
@@ -0,0 +1,69 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg;
+
+import java.io.File;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.swing.JFileChooser;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+
+public class CombinedLightspeed {
+
+ public static void main(String [] args) {
+ SharedServerData server = getServer();
+ if (server == null)
+ return;
+ AtomicBoolean running = new AtomicBoolean(true);
+ int port = LightweightLightspeed.runConcurrent(server, running);
+ LightspeedFrontendGUI.main(new String[]{"--address=localhost", "--port=" + port});
+ running.set(false);
+ }
+
+ private static SharedServerData getServer() {
+ try {
+ if (System.getProperty("os.name").toLowerCase().contains("win"))
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
+ e.printStackTrace();
+ }
+ JFileChooser chooser = new JFileChooser(new File("/home/josh/devel/ProjectSWG/swg_workspace/Holocore"));
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ chooser.setAcceptAllFileFilterUsed(false);
+ if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION)
+ return null;
+ SharedServerData server = new SharedServerData("LIGHTSPEED");
+ server.setDirectory(chooser.getSelectedFile().getAbsolutePath());
+ return server;
+ }
+
+}
diff --git a/src/com/projectswg/Lightspeed.java b/src/com/projectswg/Lightspeed.java
index 94874e9..8e20a89 100644
--- a/src/com/projectswg/Lightspeed.java
+++ b/src/com/projectswg/Lightspeed.java
@@ -29,6 +29,7 @@ package com.projectswg;
import java.util.concurrent.atomic.AtomicBoolean;
+import com.projectswg.common.info.HeavyweightDataManager;
import com.projectswg.common.info.Log;
import com.projectswg.lightspeed.LightspeedManager;
@@ -37,17 +38,15 @@ public class Lightspeed {
public static void main(String [] args) {
Thread mainThread = Thread.currentThread();
AtomicBoolean running = new AtomicBoolean(true);
+ LightspeedManager.setDataManager(new HeavyweightDataManager());
+ LightspeedManager.getDataManager().initialize();
LightspeedManager lightspeed = new LightspeedManager();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
running.set(false);
mainThread.interrupt();
- try {
- mainThread.join();
- } catch (Exception e) {
- System.err.println("Main thread join() interrupted");
- }
}, "lightspeed-shutdown-hook"));
runLightspeed(lightspeed, running);
+ LightspeedManager.getDataManager().terminate();
}
private static void runLightspeed(LightspeedManager lightspeed, AtomicBoolean running) {
diff --git a/src/com/projectswg/LightweightLightspeed.java b/src/com/projectswg/LightweightLightspeed.java
new file mode 100644
index 0000000..f58d0cf
--- /dev/null
+++ b/src/com/projectswg/LightweightLightspeed.java
@@ -0,0 +1,127 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.projectswg.common.info.Config;
+import com.projectswg.common.info.ConfigFile;
+import com.projectswg.common.info.LightweightDataManager;
+import com.projectswg.common.info.Log;
+import com.projectswg.lightspeed.LightspeedManager;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+
+public class LightweightLightspeed {
+
+ public static int runConcurrent(SharedServerData server, AtomicBoolean running) {
+ Thread mainThread = Thread.currentThread();
+ LightspeedManager.setDataManager(createDataManager(0, server));
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ running.set(false);
+ mainThread.interrupt();
+ try {
+ mainThread.join();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ LightspeedManager.getDataManager().terminate();
+ }, "lightspeed-shutdown-hook"));
+ return runLightspeedConcurrent(running);
+ }
+
+ public static void run(int port, SharedServerData server) {
+ Thread mainThread = Thread.currentThread();
+ AtomicBoolean running = new AtomicBoolean(true);
+ LightspeedManager.setDataManager(createDataManager(port, server));
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ running.set(false);
+ mainThread.interrupt();
+ }, "lightspeed-shutdown-hook"));
+ runLightspeed(running);
+ LightspeedManager.getDataManager().terminate();
+ }
+
+ private static LightweightDataManager createDataManager(int port, SharedServerData server) {
+ LightweightDataManager dataManager = new LightweightDataManager();
+ dataManager.initialize();
+ Config lightspeed = dataManager.getConfig(ConfigFile.LIGHTSPEED);
+ lightspeed.setProperty("PORT", port);
+ dataManager.getBackendData().insertServer(server);
+ return dataManager;
+ }
+
+ private static void runLightspeed(AtomicBoolean running) {
+ LightspeedManager lightspeed = new LightspeedManager();
+ Log.i("Lightspeed", "Initializing...");
+ lightspeed.initialize();
+ Log.i("Lightspeed", "Initialized.");
+ Log.i("Lightspeed", "Starting...");
+ lightspeed.start();
+ Log.i("Lightspeed", "Started.");
+ while (lightspeed.isOperational() && running.get()) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ Log.i("Lightspeed", "Stopping...");
+ lightspeed.stop();
+ Log.i("Lightspeed", "Stopped.");
+ Log.i("Lightspeed", "Terminating...");
+ lightspeed.terminate();
+ Log.i("Lightspeed", "Terminated.");
+ }
+
+ private static int runLightspeedConcurrent(AtomicBoolean running) {
+ LightspeedManager lightspeed = new LightspeedManager();
+ Log.i("Lightspeed", "Initializing...");
+ lightspeed.initialize();
+ Log.i("Lightspeed", "Initialized.");
+ Log.i("Lightspeed", "Starting...");
+ lightspeed.start();
+ Log.i("Lightspeed", "Started.");
+ new Thread(() -> {
+ while (lightspeed.isOperational() && running.get()) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ Log.i("Lightspeed", "Stopping...");
+ lightspeed.stop();
+ Log.i("Lightspeed", "Stopped.");
+ Log.i("Lightspeed", "Terminating...");
+ lightspeed.terminate();
+ Log.i("Lightspeed", "Terminated.");
+ }).start();
+ return lightspeed.getCommunicationPort();
+ }
+
+}
diff --git a/src/com/projectswg/common/control/Assert.java b/src/com/projectswg/common/control/Assert.java
new file mode 100644
index 0000000..e5d9344
--- /dev/null
+++ b/src/com/projectswg/common/control/Assert.java
@@ -0,0 +1,89 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.control;
+
+public class Assert {
+
+ private static volatile AssertLevel level = AssertLevel.ASSERT;
+
+ public static void setLevel(AssertLevel level) {
+ Assert.level = level;
+ }
+
+ public static boolean debug() {
+ return level != AssertLevel.IGNORE;
+ }
+
+ public static void notNull(Object o) {
+ if (debug() && o == null)
+ handle(new NullPointerException());
+ }
+
+ public static void test(boolean expr) {
+ if (debug() && !expr)
+ handle(new AssertionError());
+ }
+
+ public static void fail() {
+ if (debug())
+ handle(new AssertionError());
+ }
+
+ private static void handle(RuntimeException e) {
+ AssertLevel level = Assert.level;
+ switch (level) {
+ case WARN:
+ e.printStackTrace();
+ break;
+ case ASSERT:
+ throw e;
+ default:
+ break;
+ }
+ }
+
+ private static void handle(Error e) {
+ AssertLevel level = Assert.level;
+ switch (level) {
+ case WARN:
+ e.printStackTrace();
+ break;
+ case ASSERT:
+ throw e;
+ default:
+ break;
+ }
+ }
+
+ public enum AssertLevel {
+ IGNORE,
+ WARN,
+ ASSERT
+ }
+
+}
diff --git a/src/com/projectswg/common/control/IntentExecutor.java b/src/com/projectswg/common/control/IntentExecutor.java
new file mode 100644
index 0000000..eb4ffc2
--- /dev/null
+++ b/src/com/projectswg/common/control/IntentExecutor.java
@@ -0,0 +1,132 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.control;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class IntentExecutor {
+
+ private final Queue tasks;
+ private final AtomicBoolean shutdown;
+ private final Signal taskSignal;
+
+ public IntentExecutor(int threadCount, String namePattern) {
+ tasks = new ArrayDeque<>();
+ shutdown = new AtomicBoolean(false);
+ taskSignal = new Signal();
+ for (int i = 0; i < threadCount; ++i) {
+ new IntentThread(String.format(namePattern, i));
+ }
+ }
+
+ public void execute(Runnable r) {
+ synchronized (tasks) {
+ tasks.add(r);
+ }
+ taskSignal.signal();
+ }
+
+ public int size() {
+ synchronized (tasks) {
+ return tasks.size();
+ }
+ }
+
+ public void shutdown() {
+ shutdown.set(true);
+ taskSignal.signalAll();
+ }
+
+ public void awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+// timeout = unit.toMillis(timeout);
+ while (size() > 0 && timeout >= 0) {
+ Thread.sleep(1);
+ timeout--;
+ }
+ }
+
+ private class IntentThread implements Runnable {
+
+ private final Thread thread;
+
+ public IntentThread(String name) {
+ thread = new Thread(this, name);
+ thread.start();
+ }
+
+ public void run() {
+ while (true) {
+ Runnable r;
+ synchronized (tasks) {
+ r = tasks.poll();
+ if (r == null) {
+ if (shutdown.get())
+ break;
+ taskSignal.await();
+ continue;
+ }
+ }
+ r.run();
+ }
+ }
+
+ }
+
+ private static class Signal {
+
+ private final Object mutex = new Object();
+
+ public void signal() {
+ synchronized (mutex) {
+ mutex.notify();
+ }
+ }
+
+ public void signalAll() {
+ synchronized (mutex) {
+ mutex.notifyAll();
+ }
+ }
+
+ public boolean await() {
+ synchronized (mutex) {
+ try {
+ mutex.wait();
+ return true;
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/src/com/projectswg/common/control/IntentManager.java b/src/com/projectswg/common/control/IntentManager.java
index 4510634..02edc84 100644
--- a/src/com/projectswg/common/control/IntentManager.java
+++ b/src/com/projectswg/common/control/IntentManager.java
@@ -53,7 +53,7 @@ public class IntentManager {
private IntentManager() {
intentRegistrations = new HashMap>();
- intentQueue = new IntentQueue();
+ intentQueue = new IntentQueue<>();
initialize();
broadcastRunnable = () -> {
Intent i;
@@ -65,16 +65,18 @@ public class IntentManager {
};
}
- protected void initialize() {
+ public void initialize() {
if (!initialized) {
- final int broadcastThreadCount = Runtime.getRuntime().availableProcessors() * 10;
+ intentRegistrations.clear();
+ intentQueue.clear();
+ final int broadcastThreadCount = 4;
broadcastThreads = Executors.newFixedThreadPool(broadcastThreadCount, ThreadUtilities.newThreadFactory("intent-processor-%d"));
initialized = true;
terminated = false;
}
}
- protected void terminate() {
+ public void terminate() {
if (!terminated) {
broadcastThreads.shutdown();
initialized = false;
@@ -107,7 +109,7 @@ public class IntentManager {
}
}
- protected void unregisterForIntent(String intentType, IntentReceiver r) {
+ public void unregisterForIntent(String intentType, IntentReceiver r) {
if (r == null)
return;
synchronized (intentRegistrations) {
diff --git a/src/com/projectswg/common/control/IntentQueue.java b/src/com/projectswg/common/control/IntentQueue.java
index c68baf4..515d1fa 100644
--- a/src/com/projectswg/common/control/IntentQueue.java
+++ b/src/com/projectswg/common/control/IntentQueue.java
@@ -32,7 +32,7 @@ import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.Queue;
-class IntentQueue implements Queue {
+class IntentQueue implements Queue {
private final Node head;
private int size;
@@ -59,7 +59,7 @@ class IntentQueue implements Queue {
public boolean contains(Object o) {
Node n = head;
while (n.left != head) {
- if (n.left.intent == o)
+ if (n.left.value == o)
return true;
}
return false;
@@ -85,7 +85,7 @@ class IntentQueue implements Queue {
modificationCount++;
Node n = head;
while (n.left != head) {
- if (n.left.intent == o) {
+ if (n.left.value == o) {
n.left = n.left.left;
n.left.right = n;
}
@@ -102,9 +102,9 @@ class IntentQueue implements Queue {
}
@Override
- public boolean addAll(Collection extends Intent> c) {
+ public boolean addAll(Collection extends E> c) {
boolean added = false;
- for (Intent i : c)
+ for (E i : c)
added = add(i) || added;
return added;
}
@@ -122,7 +122,7 @@ class IntentQueue implements Queue {
boolean changed = false;
Node n = head;
while (n.left != head) {
- if (!c.contains(n.left.intent)) {
+ if (!c.contains(n.left.value)) {
n.left.left.right = n;
n.left = n.left.left;
}
@@ -139,7 +139,7 @@ class IntentQueue implements Queue {
}
@Override
- public boolean add(Intent e) {
+ public boolean add(E e) {
head.right.left = new Node(e, head, head.right);
head.right = head.right.left;
modificationCount++;
@@ -148,16 +148,16 @@ class IntentQueue implements Queue {
}
@Override
- public boolean offer(Intent e) {
+ public boolean offer(E e) {
return add(e);
}
@Override
- public Intent remove() {
+ public E remove() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty!");
modificationCount++;
- Intent i = head.left.intent;
+ E i = head.left.value;
head.left = head.left.left;
head.left.right = head;
size--;
@@ -165,11 +165,11 @@ class IntentQueue implements Queue {
}
@Override
- public Intent poll() {
+ public E poll() {
if (isEmpty())
return null;
modificationCount++;
- Intent i = head.left.intent;
+ E i = head.left.value;
head.left = head.left.left;
head.left.right = head;
size--;
@@ -177,20 +177,20 @@ class IntentQueue implements Queue {
}
@Override
- public Intent element() {
+ public E element() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty!");
- return head.left.intent;
+ return head.left.value;
}
@Override
- public Intent peek() {
+ public E peek() {
if (isEmpty())
return null;
- return head.left.intent;
+ return head.left.value;
}
- private class Iterator implements java.util.Iterator {
+ private class Iterator implements java.util.Iterator {
private final int modificationCount;
private Node currentNode;
@@ -208,24 +208,24 @@ class IntentQueue implements Queue {
}
@Override
- public Intent next() {
+ public E next() {
if (!hasNext())
throw new NoSuchElementException("Iterator has reached the end of the queue!");
- Intent i = currentNode.left.intent;
+ E i = currentNode.left.value;
currentNode = currentNode.left;
return i;
}
}
- private static class Node {
+ private class Node {
- public final Intent intent;
+ public final E value;
public Node left;
public Node right;
- public Node(Intent intent, Node left, Node right) {
- this.intent = intent;
+ public Node(E value, Node left, Node right) {
+ this.value = value;
this.left = left;
this.right = right;
}
diff --git a/src/com/projectswg/common/control/Service.java b/src/com/projectswg/common/control/Service.java
index 71004ec..6506165 100644
--- a/src/com/projectswg/common/control/Service.java
+++ b/src/com/projectswg/common/control/Service.java
@@ -38,6 +38,8 @@ import com.projectswg.common.info.Log;
*/
public abstract class Service implements IntentReceiver {
+ private static DataManager dataManager = null;
+
public Service() {
IntentManager.getInstance().initialize();
}
@@ -48,7 +50,7 @@ public abstract class Service implements IntentReceiver {
* @return TRUE if initialization was successful, FALSE otherwise
*/
public boolean initialize() {
- return DataManager.getInstance().isInitialized();
+ return true;
}
/**
@@ -57,7 +59,7 @@ public abstract class Service implements IntentReceiver {
* @return TRUE if starting was successful, FALSE otherwise
*/
public boolean start() {
- return DataManager.getInstance().isInitialized();
+ return true;
}
/**
@@ -76,7 +78,6 @@ public abstract class Service implements IntentReceiver {
* @return TRUE if termination was successful, FALSE otherwise
*/
public boolean terminate() {
- DataManager.terminate();
IntentManager.getInstance().terminate();
return true;
}
@@ -120,11 +121,19 @@ public abstract class Service implements IntentReceiver {
* config failed to load
*/
public final Config getConfig(ConfigFile file) {
- return DataManager.getInstance().getConfig(file);
+ return dataManager.getConfig(file);
}
public BackendData getBackendData() {
- return DataManager.getInstance().getBackendData();
+ return dataManager.getBackendData();
+ }
+
+ public static void setDataManager(DataManager dataManager) {
+ Service.dataManager = dataManager;
+ }
+
+ public static DataManager getDataManager() {
+ return dataManager;
}
}
diff --git a/src/com/projectswg/common/data/BackendData.java b/src/com/projectswg/common/data/BackendData.java
index eb29c13..6ba1929 100644
--- a/src/com/projectswg/common/data/BackendData.java
+++ b/src/com/projectswg/common/data/BackendData.java
@@ -27,263 +27,19 @@
***********************************************************************************/
package com.projectswg.common.data;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import com.projectswg.common.info.RelationalDatabase;
-import com.projectswg.common.info.RelationalServerFactory;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
-public class BackendData {
+public interface BackendData {
- private final WeakMap serverMap;
- private final WeakMap buildMap;
- private final WeakMap deploymentMap;
-
- public BackendData() {
- serverMap = new WeakMap<>();
- buildMap = new WeakMap<>();
- deploymentMap = new WeakMap<>();
- loadServers();
- }
-
- public void insertServer(SharedServerData server) {
- synchronized (serverMap) {
- if (serverMap.put(server.getName(), server) != null)
- return;
- }
- try (ServerTable serverTable = new ServerTable()) {
- serverTable.insertServer(new SQLServerData(server.getName(), server.getDirectory(), server.getJvmArguments()));
- }
- }
-
- public void insertBuild(SharedBuildData build) {
- synchronized (buildMap) {
- if (buildMap.put(build.getId(), build) != null)
- return;
- }
- try (BuildHistoryTable buildTable = new BuildHistoryTable()) {
- buildTable.insertBuildHistory(new SQLBuildData(build));
- }
- }
-
- public void insertDeployment(SharedDeploymentData deployment) {
- synchronized (deploymentMap) {
- if (deploymentMap.put(deployment.getId(), deployment) != null)
- return;
- }
- try (DeploymentTable deploymentTable = new DeploymentTable()) {
- deploymentTable.insertDeployment(new SQLDeploymentData(deployment));
- }
- }
-
- public void removeServer(String serverId) {
- synchronized (serverMap) {
- serverMap.remove(serverId);
- }
- try (ServerTable serverTable = new ServerTable()) {
- serverTable.deleteServer(serverId);
- }
- }
-
- public List getServerList() {
- List servers = new ArrayList<>(serverMap.size());
- synchronized (serverMap) {
- for (Entry e : serverMap.entrySet()) {
- servers.add(e.getValue());
- }
- }
- return servers;
- }
-
- public SharedServerData getServer(String serverId) {
- synchronized (serverMap) {
- SharedServerData server = serverMap.get(serverId);
- if (server != null)
- return server;
- server = fetchServer(serverId);
- serverMap.put(serverId, server);
- return server;
- }
- }
-
- public SharedBuildData getBuild(long buildId) {
- synchronized (buildMap) {
- SharedBuildData build = buildMap.get(buildId);
- if (build != null)
- return build;
- build = fetchBuild(buildId);
- buildMap.put(buildId, build);
- return build;
- }
- }
-
- private void loadServers() {
- synchronized (serverMap) {
- try (RelationalDatabase db = RelationalServerFactory.getServerDatabase("lightspeed.db")) {
- try (ServerTable serverTable = new ServerTable(db)) {
- for (String serverId : serverTable.getServerStrings()) {
- SharedServerData server = fetchServer(serverId);
- serverMap.put(server.getName(), server);
- }
- }
- }
- }
- }
-
- private SharedServerData fetchServer(String serverId) {
- try (RelationalDatabase db = RelationalServerFactory.getServerDatabase("lightspeed.db")) {
- try (ServerTable serverTable = new ServerTable(db)) {
- SharedServerData server = createServerFromInfo(serverTable.getServerById(serverId));
- fetchBuildHistory(db, server);
- return server;
- }
- }
- }
-
- private void fetchBuildHistory(RelationalDatabase db, SharedServerData server) {
- try (BuildHistoryTable buildTable = new BuildHistoryTable(db)) {
- for (SQLBuildData info : buildTable.getBuildHistory(server.getName())) {
- SharedBuildData build = createBuildFromInfo(server, info);
- synchronized (buildMap) {
- buildMap.put(build.getId(), build);
- }
- fetchDeploymentHistory(db, build);
- server.addBuild(build);
- }
- }
- }
-
- private SharedBuildData fetchBuild(long buildId) {
- try (RelationalDatabase db = RelationalServerFactory.getServerDatabase("lightspeed.db")) {
- try (BuildHistoryTable buildTable = new BuildHistoryTable(db)) {
- SQLBuildData info = buildTable.getBuildById(buildId);
- SharedServerData server = getServer(info.getServerId());
- SharedBuildData build = createBuildFromInfo(server, info);
- fetchDeploymentHistory(db, build);
- return build;
- }
- }
- }
-
- private void fetchDeploymentHistory(RelationalDatabase db, SharedBuildData build) {
- try (DeploymentTable deploymentTable = new DeploymentTable(db)) {
- for (SQLDeploymentData info : deploymentTable.getDeployments(build.getId())) {
- SharedDeploymentData deployment = createDeploymentFromInfo(build, info);
- build.addDeployment(deployment);
- synchronized (deploymentMap) {
- deploymentMap.put(deployment.getId(), deployment);
- }
- }
- }
- }
-
- private SharedServerData createServerFromInfo(SQLServerData info) {
- SharedServerData server = new SharedServerData(info.getId());
- server.setDirectory(info.getDir());
- server.setJvmArguments(info.getJvmArgs());
- return server;
- }
-
- private SharedBuildData createBuildFromInfo(SharedServerData server, SQLBuildData info) {
- SharedBuildData build = new SharedBuildData(info.getId(), server);
- build.setTime(info.getCompletedTime());
- build.setBuildString(info.getBuildString());
- build.setTestString(info.getTestString());
- build.setCompileTime(info.getCompileTime());
- build.setOffline(info.isOffline());
- build.setBuildSuccess(info.isBuildSuccess());
- build.setTestSuccess(info.isTestSuccess());
- build.setCancelled(info.isCancelled());
- build.setTestDetails(info.getTestDetails());
- build.setJar(info.getJar());
- return build;
- }
-
- private SharedDeploymentData createDeploymentFromInfo(SharedBuildData build, SQLDeploymentData info) {
- SharedDeploymentData deployment = new SharedDeploymentData(info.getId(), build);
- deployment.setStartTime(info.getStartTime());
- deployment.setEndTime(info.getEndTime());
- return deployment;
- }
-
- private static class WeakMap {
-
- private final Map> map;
-
- public WeakMap() {
- map = new HashMap<>();
- }
-
- public V get(K key) {
- WeakReference ref = map.get(key);
- return (ref == null) ? null : ref.get();
- }
-
- public V put(K key, V val) {
- WeakReference ref = map.put(key, new WeakReference<>(val));
- if (ref == null)
- return null;
- return ref.get();
- }
-
- public boolean remove(K key) {
- return map.remove(key) != null;
- }
-
- public Set> entrySet() {
- Set>> entries = map.entrySet();
- Set> ret = new HashSet<>();
- for (Entry> entry : entries) {
- if (entry.getValue() != null) {
- V val = entry.getValue().get();
- if (val != null)
- ret.add(new WeakEntry<>(entry.getKey(), val));
- }
- }
- return ret;
- }
-
- public int size() {
- return map.size();
- }
-
- }
-
- private static class WeakEntry implements Map.Entry {
-
- private final K key;
- private V value;
-
- public WeakEntry(K key, V value) {
- this.key = key;
- this.value = value;
- }
-
- @Override
- public K getKey() {
- return key;
- }
-
- @Override
- public V getValue() {
- return value;
- }
-
- @Override
- public V setValue(V value) {
- V old = this.value;
- this.value = value;
- return old;
- }
- }
+ SharedServerData getServer(String serverId);
+ List getServerList();
+ void insertServer(SharedServerData server);
+ void insertBuild(SharedBuildData build);
+ void insertDeployment(SharedDeploymentData deployment);
+ void removeServer(String serverId);
}
diff --git a/src/com/projectswg/common/data/BuildHistoryTable.java b/src/com/projectswg/common/data/BuildHistoryTable.java
index 6226078..3252f7b 100644
--- a/src/com/projectswg/common/data/BuildHistoryTable.java
+++ b/src/com/projectswg/common/data/BuildHistoryTable.java
@@ -27,7 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data;
-import java.io.File;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -43,8 +42,8 @@ import com.projectswg.common.info.RelationalServerFactory;
class BuildHistoryTable implements AutoCloseable {
private static final int STANDARD_HISTORY_SIZE = 25;
- private static final String ALL_COLUMNS = "id, time, server_id, build_string, test_string, compile_time, offline, build_success, test_success, cancelled, test_total, test_failures, test_errors, test_skipped, jar";
- private static final String INSERT_BUILD_HISTORY_SQL = "INSERT INTO builds ("+ALL_COLUMNS+") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ private static final String ALL_COLUMNS = "id, time, server_id, build_string, test_string, compile_time, build_success, test_success, cancelled, test_total, test_failures";
+ private static final String INSERT_BUILD_HISTORY_SQL = "INSERT INTO builds ("+ALL_COLUMNS+") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String GET_BUILD_HISTORY_SQL = "SELECT "+ALL_COLUMNS+" FROM builds WHERE server_id = ? ORDER BY time DESC LIMIT "+STANDARD_HISTORY_SIZE;
private static final String GET_BUILD_BY_ID_SQL = "SELECT "+ALL_COLUMNS+" FROM builds WHERE id = ?";
@@ -113,16 +112,10 @@ class BuildHistoryTable implements AutoCloseable {
builder.setBuildString(set.getString("build_string"));
builder.setTestString(set.getString("test_string"));
builder.setCompileTime(set.getDouble("compile_time"));
- builder.setOffline(set.getBoolean("offline"));
builder.setBuildSuccess(set.getBoolean("build_success"));
builder.setTestSuccess(set.getBoolean("test_success"));
builder.setCancelled(set.getBoolean("cancelled"));
- builder.setTestDetails(new TestDetails(set.getInt("test_total"), set.getInt("test_failures"), set.getInt("test_errors"), set.getInt("test_skipped")));
- String jarPath = set.getString("jar");
- if (jarPath.isEmpty())
- builder.setJar(null);
- else
- builder.setJar(new File(jarPath));
+ builder.setTestDetails(new TestDetails(set.getInt("test_total"), set.getInt("test_failures")));
return builder.build();
}
@@ -135,26 +128,17 @@ class BuildHistoryTable implements AutoCloseable {
insertBuildHistoryStatement.setString(4, build.getBuildString());
insertBuildHistoryStatement.setString(5, build.getTestString());
insertBuildHistoryStatement.setDouble(6, build.getCompileTime());
- insertBuildHistoryStatement.setInt(7, build.isOffline() ? 1 : 0);
- insertBuildHistoryStatement.setInt(8, build.isBuildSuccess() ? 1 : 0);
- insertBuildHistoryStatement.setInt(9, build.isTestSuccess() ? 1 : 0);
- insertBuildHistoryStatement.setInt(10, build.isCancelled() ? 1 : 0);
+ insertBuildHistoryStatement.setInt(7, build.isBuildSuccess() ? 1 : 0);
+ insertBuildHistoryStatement.setInt(8, build.isTestSuccess() ? 1 : 0);
+ insertBuildHistoryStatement.setInt(9, build.isCancelled() ? 1 : 0);
TestDetails test = build.getTestDetails();
if (test != null) {
- insertBuildHistoryStatement.setInt(11, test.getTotal());
- insertBuildHistoryStatement.setInt(12, test.getFailures());
- insertBuildHistoryStatement.setInt(13, test.getErrors());
- insertBuildHistoryStatement.setInt(14, test.getSkipped());
+ insertBuildHistoryStatement.setInt(10, test.getTotal());
+ insertBuildHistoryStatement.setInt(11, test.getFailures());
} else {
+ insertBuildHistoryStatement.setInt(10, 0);
insertBuildHistoryStatement.setInt(11, 0);
- insertBuildHistoryStatement.setInt(12, 0);
- insertBuildHistoryStatement.setInt(13, 0);
- insertBuildHistoryStatement.setInt(14, 0);
}
- if (build.getJar() == null)
- insertBuildHistoryStatement.setString(15, "");
- else
- insertBuildHistoryStatement.setString(15, build.getJar().getAbsolutePath());
insertBuildHistoryStatement.executeUpdate();
}
} catch (SQLException e) {
diff --git a/src/com/projectswg/common/data/HeavyweightBackendData.java b/src/com/projectswg/common/data/HeavyweightBackendData.java
new file mode 100644
index 0000000..3004c4d
--- /dev/null
+++ b/src/com/projectswg/common/data/HeavyweightBackendData.java
@@ -0,0 +1,164 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.projectswg.common.info.RelationalDatabase;
+import com.projectswg.common.info.RelationalServerFactory;
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+
+public class HeavyweightBackendData implements BackendData {
+
+ private final Map serverMap;
+
+ public HeavyweightBackendData() {
+ this.serverMap = new HashMap<>();
+ loadServers();
+ }
+
+ public void insertServer(SharedServerData server) {
+ synchronized (serverMap) {
+ if (serverMap.put(server.getName(), server) != null)
+ return;
+ }
+ try (ServerTable serverTable = new ServerTable()) {
+ serverTable.insertServer(new SQLServerData(server.getName(), server.getDirectory(), server.getJvmArguments()));
+ }
+ }
+
+ public void insertBuild(SharedBuildData build) {
+ try (BuildHistoryTable buildTable = new BuildHistoryTable()) {
+ buildTable.insertBuildHistory(new SQLBuildData(build));
+ }
+ }
+
+ public void insertDeployment(SharedDeploymentData deployment) {
+ try (DeploymentTable deploymentTable = new DeploymentTable()) {
+ deploymentTable.insertDeployment(new SQLDeploymentData(deployment));
+ }
+ }
+
+ public void removeServer(String serverId) {
+ synchronized (serverMap) {
+ serverMap.remove(serverId);
+ }
+ try (ServerTable serverTable = new ServerTable()) {
+ serverTable.deleteServer(serverId);
+ }
+ }
+
+ public List getServerList() {
+ List servers = new ArrayList<>(serverMap.size());
+ synchronized (serverMap) {
+ for (Entry e : serverMap.entrySet()) {
+ servers.add(e.getValue());
+ }
+ }
+ return servers;
+ }
+
+ public SharedServerData getServer(String serverId) {
+ synchronized (serverMap) {
+ SharedServerData server = serverMap.get(serverId);
+ if (server == null)
+ return server;
+ try (RelationalDatabase db = RelationalServerFactory.getServerDatabase("lightspeed.db")) {
+ fetchBuildHistory(db, server);
+ }
+ return server;
+ }
+ }
+
+ private void loadServers() {
+ synchronized (serverMap) {
+ try (RelationalDatabase db = RelationalServerFactory.getServerDatabase("lightspeed.db")) {
+ try (ServerTable serverTable = new ServerTable(db)) {
+ for (String serverId : serverTable.getServerStrings()) {
+ SharedServerData server = createServerFromInfo(serverTable.getServerById(serverId));
+ fetchBuildHistory(db, server);
+ serverMap.put(serverId, server);
+ }
+ }
+ }
+ }
+ }
+
+ private void fetchBuildHistory(RelationalDatabase db, SharedServerData server) {
+ try (BuildHistoryTable buildTable = new BuildHistoryTable(db)) {
+ for (SQLBuildData info : buildTable.getBuildHistory(server.getName())) {
+ SharedBuildData build = createBuildFromInfo(server, info);
+ fetchDeploymentHistory(db, server, build);
+ server.addBuild(build);
+ }
+ }
+ }
+
+ private void fetchDeploymentHistory(RelationalDatabase db, SharedServerData server, SharedBuildData build) {
+ try (DeploymentTable deploymentTable = new DeploymentTable(db)) {
+ for (SQLDeploymentData info : deploymentTable.getDeployments(server.getName())) {
+ SharedDeploymentData deployment = createDeploymentFromInfo(build, info);
+ server.addDeployment(deployment);
+ }
+ }
+ }
+
+ private SharedServerData createServerFromInfo(SQLServerData info) {
+ SharedServerData server = new SharedServerData(info.getId());
+ server.setDirectory(info.getDir());
+ server.setJvmArguments(info.getJvmArgs());
+ return server;
+ }
+
+ private SharedBuildData createBuildFromInfo(SharedServerData server, SQLBuildData info) {
+ SharedBuildData build = new SharedBuildData(info.getId(), server);
+ build.setTime(info.getCompletedTime());
+ build.setBuildString(info.getBuildString());
+ build.setTestString(info.getTestString());
+ build.setCompileTime(info.getCompileTime());
+ build.setBuildSuccess(info.isBuildSuccess());
+ build.setTestSuccess(info.isTestSuccess());
+ build.setCancelled(info.isCancelled());
+ build.setTestDetails(info.getTestDetails());
+ return build;
+ }
+
+ private SharedDeploymentData createDeploymentFromInfo(SharedBuildData build, SQLDeploymentData info) {
+ SharedDeploymentData deployment = new SharedDeploymentData(info.getId(), build);
+ deployment.setStartTime(info.getStartTime());
+ deployment.setEndTime(info.getEndTime());
+ return deployment;
+ }
+
+}
diff --git a/src/com/projectswg/common/data/LightweightBackendData.java b/src/com/projectswg/common/data/LightweightBackendData.java
new file mode 100644
index 0000000..ef081c6
--- /dev/null
+++ b/src/com/projectswg/common/data/LightweightBackendData.java
@@ -0,0 +1,77 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+
+public class LightweightBackendData implements BackendData {
+
+ private final Map serverMap;
+
+ public LightweightBackendData() {
+ serverMap = new HashMap<>();
+ }
+
+ @Override
+ public SharedServerData getServer(String serverId) {
+ return serverMap.get(serverId);
+ }
+
+ @Override
+ public List getServerList() {
+ return new ArrayList<>(serverMap.values());
+ }
+
+ @Override
+ public void insertServer(SharedServerData server) {
+ serverMap.put(server.getName(), server);
+ }
+
+ @Override
+ public void insertBuild(SharedBuildData build) {
+
+ }
+
+ @Override
+ public void insertDeployment(SharedDeploymentData deployment) {
+
+ }
+
+ @Override
+ public void removeServer(String serverId) {
+ serverMap.remove(serverId);
+ }
+
+}
diff --git a/src/com/projectswg/common/data/SQLBuildData.java b/src/com/projectswg/common/data/SQLBuildData.java
index e098977..7136f69 100644
--- a/src/com/projectswg/common/data/SQLBuildData.java
+++ b/src/com/projectswg/common/data/SQLBuildData.java
@@ -27,8 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data;
-import java.io.File;
-
import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed.build.ServerBuildData;
import com.projectswg.lightspeed.build.InstallationState;
@@ -44,26 +42,22 @@ class SQLBuildData {
private String testString;
private long completedTime;
private double compileTime;
- private boolean offline;
private boolean buildSuccess;
private boolean testSuccess;
private boolean cancelled;
private TestDetails testDetails;
- private File jar;
- public SQLBuildData(long id, String serverId, ServerBuildData installation, File jar) {
+ public SQLBuildData(long id, String serverId, ServerBuildData installation) {
this.id = id;
this.serverId = serverId;
this.buildString = installation.getBuildString();
this.testString = installation.getTestString();
this.completedTime = installation.getCompletedTime();
this.compileTime = installation.getCompileTime();
- this.offline = installation.isOffline();
this.buildSuccess = installation.isBuildSuccess();
this.testSuccess = installation.isTestSuccess();
this.cancelled = installation.getState() == InstallationState.CANCELLED;
this.testDetails = installation.getTestDetails();
- this.jar = jar;
}
public SQLBuildData(SharedBuildData build) {
@@ -73,12 +67,10 @@ class SQLBuildData {
this.testString = build.getTestString();
this.completedTime = build.getTime();
this.compileTime = build.getCompileTime();
- this.offline = build.isOffline();
this.buildSuccess = build.isBuildSuccess();
this.testSuccess = build.isTestSuccess();
this.cancelled = build.isCancelled();
this.testDetails = build.getTestDetails();
- this.jar = build.getJar();
}
public SQLBuildData(JSONObject json) {
@@ -88,12 +80,10 @@ class SQLBuildData {
this.testString = json.getString("test_string");
this.completedTime = TimeUtilities.getTimeFromStringUtc(json.getString("completed_time"));
this.compileTime = json.getDouble("compile_time");
- this.offline = false;
this.buildSuccess = json.getBoolean("build_success");
this.testSuccess = json.getBoolean("test_success");
this.cancelled = json.getBoolean("cancelled");
- this.testDetails = new TestDetails(json.getInt("test_total"), json.getInt("test_failures"), json.getInt("test_errors"), json.getInt("test_skipped"));
- this.jar = null;
+ this.testDetails = new TestDetails(json.getInt("test_total"), json.getInt("test_failures"));
}
private SQLBuildData() {
@@ -103,12 +93,10 @@ class SQLBuildData {
this.testString = "";
this.completedTime = 0;
this.compileTime = 0;
- this.offline = false;
this.buildSuccess = false;
this.testSuccess = false;
this.cancelled = false;
this.testDetails = null;
- this.jar = null;
}
public JSONObject createJSON() {
@@ -124,8 +112,6 @@ class SQLBuildData {
json.put("cancelled", cancelled);
json.put("test_total", testDetails.getTotal());
json.put("test_failures", testDetails.getFailures());
- json.put("test_errors", testDetails.getErrors());
- json.put("test_skipped", testDetails.getSkipped());
return json;
}
@@ -153,10 +139,6 @@ class SQLBuildData {
return compileTime;
}
- public boolean isOffline() {
- return offline;
- }
-
public boolean isBuildSuccess() {
return buildSuccess;
}
@@ -173,10 +155,6 @@ class SQLBuildData {
return testDetails;
}
- public File getJar() {
- return jar;
- }
-
public String toString() {
return String.format("BuildInformation[id=%d, server=%s, compile_time=%.3fms, build/test=%b/%b, cancelled=%b, test=%s]",
id, serverId, compileTime, buildSuccess, testSuccess, cancelled, testDetails.toString());
@@ -192,12 +170,10 @@ class SQLBuildData {
public BuildInformationBuilder setTestString(String str) { build.testString = str; return this; }
public BuildInformationBuilder setCompletedTime(long time) { build.completedTime = time; return this; }
public BuildInformationBuilder setCompileTime(double time) { build.compileTime = time; return this; }
- public BuildInformationBuilder setOffline(boolean offline) { build.offline = offline; return this; }
public BuildInformationBuilder setBuildSuccess(boolean buildSuccess) { build.buildSuccess = buildSuccess; return this; }
public BuildInformationBuilder setTestSuccess(boolean testSuccess) { build.testSuccess = testSuccess; return this; }
public BuildInformationBuilder setCancelled(boolean cancelled) { build.cancelled = cancelled; return this; }
public BuildInformationBuilder setTestDetails(TestDetails testDetails) { build.testDetails = testDetails; return this; }
- public BuildInformationBuilder setJar(File jar) { build.jar = jar; return this; }
public SQLBuildData build() {
SQLBuildData ret = build;
build = new SQLBuildData();
diff --git a/src/com/projectswg/common/data/TestDetails.java b/src/com/projectswg/common/data/TestDetails.java
index a644a84..7ba3cf5 100644
--- a/src/com/projectswg/common/data/TestDetails.java
+++ b/src/com/projectswg/common/data/TestDetails.java
@@ -27,35 +27,14 @@
***********************************************************************************/
package com.projectswg.common.data;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
public class TestDetails {
private final int total;
private final int failures;
- private final int errors;
- private final int skipped;
- public TestDetails(int total, int failures, int errors, int skipped) {
+ public TestDetails(int total, int failures) {
this.total = total;
this.failures = failures;
- this.errors = errors;
- this.skipped = skipped;
- }
-
- public static TestDetails create(String testLine) {
- Pattern r = Pattern.compile("Tests run: (\\d+), Failures: (\\d+), Errors: (\\d+), Skipped: (\\d+)");
- Matcher m = r.matcher(testLine);
- if (!m.find()) {
- System.err.println("Failed to find test results!");
- return null;
- }
- if (m.groupCount() != 4) {
- System.err.println("Failed to parse test results!");
- return null;
- }
- return new TestDetails(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)), Integer.parseInt(m.group(3)), Integer.parseInt(m.group(4)));
}
public int getTotal() {
@@ -66,16 +45,8 @@ public class TestDetails {
return failures;
}
- public int getErrors() {
- return errors;
- }
-
- public int getSkipped() {
- return skipped;
- }
-
public String toString() {
- return String.format("Test[%d total, %d fail, %d errors, %d skipped", total, failures, errors, skipped);
+ return String.format("Test[%d total, %d failed]", total, failures);
}
}
diff --git a/src/com/projectswg/common/info/DataManager.java b/src/com/projectswg/common/info/DataManager.java
index b404cc6..1a38d58 100644
--- a/src/com/projectswg/common/info/DataManager.java
+++ b/src/com/projectswg/common/info/DataManager.java
@@ -27,73 +27,9 @@
***********************************************************************************/
package com.projectswg.common.info;
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-
import com.projectswg.common.data.BackendData;
-public class DataManager {
-
- private static final Object INSTANCE_LOCK = new Object();
- private static DataManager instance = null;
-
- private final AtomicBoolean initialized;
- private final BackendData backendData;
- private Map config;
-
- private DataManager() {
- backendData = new BackendData();
- initialized = new AtomicBoolean(false);
- }
-
- private synchronized void initialize() {
- if (initialized.getAndSet(true))
- return;
- initializeConfig();
- if (getConfig(ConfigFile.LIGHTSPEED).getBoolean("ENABLE-LOGGING", true))
- Log.start();
- }
-
- private synchronized void shutdown() {
- initialized.set(false);
- }
-
- private synchronized void initializeConfig() {
- config = new ConcurrentHashMap();
- for (ConfigFile file : ConfigFile.values()) {
- File f = new File(file.getFilename());
- if (!createFilesAndDirectories(f)) {
- Log.w("DataManager", "ConfigFile could not be loaded! " + file.getFilename());
- } else {
- config.put(file, new Config(f));
- }
- }
- }
-
- private boolean createFilesAndDirectories(File file) {
- if (file.exists())
- return true;
- try {
- String parentName = file.getParent();
- if (parentName != null && !parentName.isEmpty()) {
- File parent = new File(file.getParent());
- if (!parent.exists() && !parent.mkdirs())
- Log.e(getClass().getSimpleName(), "Failed to create parent directories for ODB: " + file.getCanonicalPath());
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- try {
- if (!file.createNewFile())
- Log.e(getClass().getSimpleName(), "Failed to create new ODB: " + file.getCanonicalPath());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return file.exists();
- }
+public interface DataManager {
/**
* Gets the config object associated with a certain file, or NULL if the file failed to load on
@@ -102,38 +38,11 @@ public class DataManager {
* @param file the file to get the config for
* @return the config object associated with the file, or NULL if the config failed to load
*/
- public Config getConfig(ConfigFile file) {
- Config c = config.get(file);
- if (c == null)
- return new Config(file.getFilename());
- return c;
- }
+ public Config getConfig(ConfigFile file);
- public BackendData getBackendData() {
- return backendData;
- }
+ public BackendData getBackendData();
- public boolean isInitialized() {
- return initialized.get();
- }
-
- public static DataManager getInstance() {
- synchronized (INSTANCE_LOCK) {
- if (instance == null) {
- instance = new DataManager();
- instance.initialize();
- }
- return instance;
- }
- }
-
- public static void terminate() {
- synchronized (INSTANCE_LOCK) {
- if (instance != null) {
- instance.shutdown();
- instance = null;
- }
- }
- }
+ void initialize();
+ void terminate();
}
diff --git a/src/com/projectswg/common/info/HeavyweightDataManager.java b/src/com/projectswg/common/info/HeavyweightDataManager.java
new file mode 100644
index 0000000..63b1a03
--- /dev/null
+++ b/src/com/projectswg/common/info/HeavyweightDataManager.java
@@ -0,0 +1,121 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.info;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.projectswg.common.data.BackendData;
+import com.projectswg.common.data.HeavyweightBackendData;
+
+public class HeavyweightDataManager implements DataManager {
+
+ private final AtomicBoolean initialized;
+ private final BackendData backendData;
+ private Map config;
+
+ public HeavyweightDataManager() {
+ backendData = new HeavyweightBackendData();
+ initialized = new AtomicBoolean(false);
+ }
+
+ public synchronized void initialize() {
+ if (initialized.getAndSet(true))
+ return;
+ initializeConfig();
+ if (getConfig(ConfigFile.LIGHTSPEED).getBoolean("ENABLE-LOGGING", true))
+ Log.start();
+ }
+
+ public synchronized void terminate() {
+ if (!initialized.getAndSet(false))
+ return;
+ }
+
+ private synchronized void initializeConfig() {
+ config = new ConcurrentHashMap();
+ for (ConfigFile file : ConfigFile.values()) {
+ File f = new File(file.getFilename());
+ if (!createFilesAndDirectories(f)) {
+ Log.w("DataManager", "ConfigFile could not be loaded! " + file.getFilename());
+ } else {
+ config.put(file, new Config(f));
+ }
+ }
+ }
+
+ private boolean createFilesAndDirectories(File file) {
+ if (file.exists())
+ return true;
+ try {
+ String parentName = file.getParent();
+ if (parentName != null && !parentName.isEmpty()) {
+ File parent = new File(file.getParent());
+ if (!parent.exists() && !parent.mkdirs())
+ Log.e(getClass().getSimpleName(), "Failed to create parent directories for config: " + file.getCanonicalPath());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ if (!file.createNewFile())
+ Log.e(getClass().getSimpleName(), "Failed to create new config: " + file.getCanonicalPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return file.exists();
+ }
+
+ /**
+ * Gets the config object associated with a certain file, or NULL if the file failed to load on
+ * startup
+ *
+ * @param file the file to get the config for
+ * @return the config object associated with the file, or NULL if the config failed to load
+ */
+ @Override
+ public Config getConfig(ConfigFile file) {
+ Config c = config.get(file);
+ if (c == null)
+ return new Config(file.getFilename());
+ return c;
+ }
+
+ @Override
+ public BackendData getBackendData() {
+ return backendData;
+ }
+
+ public boolean isInitialized() {
+ return initialized.get();
+ }
+
+}
diff --git a/src/com/projectswg/common/info/LightweightConfig.java b/src/com/projectswg/common/info/LightweightConfig.java
new file mode 100644
index 0000000..ee62fdb
--- /dev/null
+++ b/src/com/projectswg/common/info/LightweightConfig.java
@@ -0,0 +1,55 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.common.info;
+
+import java.io.File;
+import java.util.Map;
+
+public class LightweightConfig extends Config {
+
+ public LightweightConfig(String filename) {
+ super(filename);
+ }
+
+ /**
+ * Initilizes the Config and loads the data in the file
+ * @param file the file to load
+ */
+ public LightweightConfig(File file) {
+ super(file);
+ }
+
+ public Map load() {
+ return null;
+ }
+
+ public boolean save() {
+ return true;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/DeploymentDataPane.java b/src/com/projectswg/common/info/LightweightDataManager.java
similarity index 65%
rename from src/com/projectswg/lightspeed_frontend/gui/DeploymentDataPane.java
rename to src/com/projectswg/common/info/LightweightDataManager.java
index 7b26686..7017eb3 100644
--- a/src/com/projectswg/lightspeed_frontend/gui/DeploymentDataPane.java
+++ b/src/com/projectswg/common/info/LightweightDataManager.java
@@ -25,54 +25,58 @@
* along with Holocore. If not, see . *
* *
***********************************************************************************/
-package com.projectswg.lightspeed_frontend.gui;
+package com.projectswg.common.info;
-import java.net.URL;
-import java.util.ResourceBundle;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
-import javafx.fxml.FXML;
-import javafx.fxml.Initializable;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.Pane;
-import javafx.scene.text.Text;
+import com.projectswg.common.data.BackendData;
+import com.projectswg.common.data.LightweightBackendData;
-import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
-import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
-
-public class DeploymentDataPane extends GridPane implements Initializable {
+public class LightweightDataManager implements DataManager {
private final AtomicBoolean initialized;
- private SharedDeploymentData deployment;
+ private final BackendData backendData;
+ private final Map configs;
- @FXML
- private Text idText;
- @FXML
- private Text serverText;
-
- public DeploymentDataPane(Pane root, SharedDeploymentData deployment) {
- this.initialized = new AtomicBoolean(false);
- setDeploymentData(deployment);
- FrontendFXMLLoader.load(this, "fxml/DeploymentDataPane.fxml");
+ public LightweightDataManager() {
+ backendData = new LightweightBackendData();
+ initialized = new AtomicBoolean(false);
+ configs = new HashMap<>();
}
- public void setDeploymentData(SharedDeploymentData deployment) {
- this.deployment = deployment;
- updateUI();
+ public synchronized void initialize() {
+ if (initialized.getAndSet(true))
+ return;
+ setupConfigs();
+ Log.start();
+ }
+
+ public synchronized void terminate() {
+ if (!initialized.getAndSet(false))
+ return;
+ }
+
+ private void setupConfigs() {
+ configs.clear();
+ for (ConfigFile file : ConfigFile.values()) {
+ configs.put(file, new LightweightConfig(file.getFilename()));
+ }
}
@Override
- public void initialize(URL location, ResourceBundle resources) {
- initialized.set(true);
- updateUI();
+ public Config getConfig(ConfigFile file) {
+ return configs.get(file);
}
- private void updateUI() {
- SharedDeploymentData deployment = this.deployment; // Concurrency thing, move along
- if (!initialized.get() || deployment == null)
- return;
- idText.setText(Long.toString(deployment.getId()));
- serverText.setText(deployment.getServer().getName());
+ @Override
+ public BackendData getBackendData() {
+ return backendData;
+ }
+
+ public boolean isInitialized() {
+ return initialized.get();
}
}
diff --git a/src/com/projectswg/common/network/TCPServer.java b/src/com/projectswg/common/network/TCPServer.java
index b9fbd50..047b02e 100644
--- a/src/com/projectswg/common/network/TCPServer.java
+++ b/src/com/projectswg/common/network/TCPServer.java
@@ -43,8 +43,10 @@ import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.callback.CallbackManager;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.info.Log;
@@ -52,6 +54,7 @@ public class TCPServer {
private final CallbackManager callbackManager;
private final Map sockets;
+ private final AtomicBoolean running;
private final InetAddress addr;
private final int port;
private final int bufferSize;
@@ -65,6 +68,7 @@ public class TCPServer {
public TCPServer(InetAddress addr, int port, int bufferSize) {
this.callbackManager = new CallbackManager<>("tcpserver-"+port, 1);
this.sockets = new HashMap<>();
+ this.running = new AtomicBoolean(false);
this.addr = addr;
this.port = port;
this.bufferSize = bufferSize;
@@ -72,7 +76,15 @@ public class TCPServer {
listener = new TCPListener();
}
+ public int getPort() {
+ return channel.socket().getLocalPort();
+ }
+
public void bind() throws IOException {
+ if (running.getAndSet(true)) {
+ Assert.fail();
+ return;
+ }
callbackManager.start();
channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(addr, port));
@@ -85,6 +97,7 @@ public class TCPServer {
}
public SocketChannel connectTo(InetSocketAddress sock) throws IOException {
+ Assert.notNull(sock);
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
if (sc == null || (!sc.isConnected() && !sc.isConnectionPending())) {
@@ -97,10 +110,10 @@ public class TCPServer {
}
public boolean disconnect(SocketAddress sock) {
+ Assert.notNull(sock);
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
- if (sc == null)
- return false;
+ Assert.notNull(sc);
sockets.remove(sock);
try {
Socket s = sc.socket();
@@ -123,11 +136,14 @@ public class TCPServer {
}
public boolean close() {
+ if (!running.getAndSet(false)) {
+ Assert.fail();
+ return false;
+ }
callbackManager.stop();
listener.stop();
try {
- if (channel != null)
- channel.close();
+ channel.close();
return true;
} catch (IOException e) {
e.printStackTrace();
@@ -138,6 +154,9 @@ public class TCPServer {
public boolean send(InetSocketAddress sock, ByteBuffer data) {
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
+ Assert.notNull(sc);
+ Assert.test(sc.isConnected());
+ Assert.test(data.hasRemaining());
try {
if (sc != null && sc.isConnected()) {
while (data.hasRemaining())
diff --git a/src/com/projectswg/common/network/packets/post/PostDeployPacket.java b/src/com/projectswg/common/network/packets/post/PostDeployPacket.java
index 02cba99..7da1a42 100644
--- a/src/com/projectswg/common/network/packets/post/PostDeployPacket.java
+++ b/src/com/projectswg/common/network/packets/post/PostDeployPacket.java
@@ -34,20 +34,20 @@ import com.projectswg.common.network.packets.PacketType;
public class PostDeployPacket extends Packet {
- private final long buildId;
+ private final String serverId;
public PostDeployPacket(JSONObject json) {
super(json, PacketType.POST_DEPLOY);
- buildId = json.getLong("build_id");
+ serverId = json.getString("server_id");
}
- public long getBuildId() {
- return buildId;
+ public String getServerId() {
+ return serverId;
}
- public static PostDeployPacket create(long buildId) {
+ public static PostDeployPacket create(String serverId) {
JSONObject json = Packet.createPacketJson(PacketType.POST_DEPLOY);
- json.put("build_id", buildId);
+ json.put("server_id", serverId);
return new PostDeployPacket(json);
}
diff --git a/src/com/projectswg/common/network/packets/request/RequestDeploymentHistoryPacket.java b/src/com/projectswg/common/network/packets/request/RequestDeploymentHistoryPacket.java
index e25023a..4155ceb 100644
--- a/src/com/projectswg/common/network/packets/request/RequestDeploymentHistoryPacket.java
+++ b/src/com/projectswg/common/network/packets/request/RequestDeploymentHistoryPacket.java
@@ -33,20 +33,20 @@ import com.projectswg.common.network.packets.PacketType;
public class RequestDeploymentHistoryPacket extends RequestPacket {
- private final long buildId;
+ private final String serverId;
public RequestDeploymentHistoryPacket(JSONObject json) {
super(json, PacketType.REQUEST_DEPLOYMENT_HISTORY);
- buildId = json.getLong("build_id");
+ serverId = json.getString("server_id");
}
- public long getBuildId() {
- return buildId;
+ public String getServerId() {
+ return serverId;
}
- public static RequestDeploymentHistoryPacket create(long requestId, long buildId) {
+ public static RequestDeploymentHistoryPacket create(long requestId, String serverId) {
JSONObject json = RequestPacket.createRequestPacketJson(requestId, PacketType.REQUEST_DEPLOYMENT_HISTORY, PacketType.RESPONSE_DEPLOYMENT_HISTORY);
- json.put("build_id", buildId);
+ json.put("server_id", serverId);
return new RequestDeploymentHistoryPacket(json);
}
diff --git a/src/com/projectswg/common/network/packets/response/ResponseDeploymentHistoryPacket.java b/src/com/projectswg/common/network/packets/response/ResponseDeploymentHistoryPacket.java
index b6daf80..8c1ca24 100644
--- a/src/com/projectswg/common/network/packets/response/ResponseDeploymentHistoryPacket.java
+++ b/src/com/projectswg/common/network/packets/response/ResponseDeploymentHistoryPacket.java
@@ -39,54 +39,32 @@ import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
public class ResponseDeploymentHistoryPacket extends ResponsePacket {
- private final List deploymentHistory;
- private final long buildId;
- private final String serverId;
+ private final List deploymentHistory;
public ResponseDeploymentHistoryPacket(JSONObject json) {
super(json, PacketType.RESPONSE_DEPLOYMENT_HISTORY);
deploymentHistory = new ArrayList<>();
JSONArray buildHistoryArray = json.getArray("deployment_history");
- long buildId = 0;
- String serverId = null;
for (Object o : buildHistoryArray) {
if (o instanceof JSONObject) {
JSONObject obj = (JSONObject) o;
- deploymentHistory.add(new SharedDeploymentData(obj));
- if (obj.containsKey("build_id"))
- buildId = obj.getLong("build_id");
- if (obj.containsKey("server_id"))
- serverId = obj.getString("server_id");
+ long buildId = obj.getLong("build_id");
+ String serverId = obj.getString("server_id");
+ SharedDeploymentData deployment = new SharedDeploymentData(obj);
+ deploymentHistory.add(new DeploymentData(serverId, buildId, deployment));
}
}
- this.buildId = buildId;
- this.serverId = serverId;
}
- private ResponseDeploymentHistoryPacket(JSONObject json, List deploymentHistory) {
+ private ResponseDeploymentHistoryPacket(JSONObject json, List deploymentHistory) {
super(json, PacketType.RESPONSE_DEPLOYMENT_HISTORY);
this.deploymentHistory = deploymentHistory;
- if (!deploymentHistory.isEmpty()) {
- this.buildId = deploymentHistory.get(0).getBuild().getId();
- this.serverId = deploymentHistory.get(0).getServer().getName();
- } else {
- this.buildId = 0;
- this.serverId = null;
- }
}
- public List getDeploymentHistory() {
+ public List getDeploymentHistory() {
return Collections.unmodifiableList(deploymentHistory);
}
- public long getBuildId() {
- return buildId;
- }
-
- public String getServerId() {
- return serverId;
- }
-
public static ResponseDeploymentHistoryPacket create(long requestId, List deploymentHistory) {
JSONObject json = ResponsePacket.createResponsePacketJson(PacketType.RESPONSE_DEPLOYMENT_HISTORY, requestId);
JSONArray deploymentHistoryArray = new JSONArray();
@@ -94,7 +72,37 @@ public class ResponseDeploymentHistoryPacket extends ResponsePacket {
deploymentHistoryArray.add(info.createJSON());
}
json.put("deployment_history", deploymentHistoryArray);
- return new ResponseDeploymentHistoryPacket(json, new ArrayList<>(deploymentHistory));
+ List deployments = new ArrayList<>();
+ for (SharedDeploymentData deployment : deploymentHistory) {
+ deployments.add(new DeploymentData(deployment.getServer().getName(), deployment.getBuild().getId(), deployment));
+ }
+ return new ResponseDeploymentHistoryPacket(json, deployments);
+ }
+
+ public static class DeploymentData {
+
+ private String serverId;
+ private long buildId;
+ private SharedDeploymentData deployment;
+
+ public DeploymentData(String serverId, long buildId, SharedDeploymentData deployment) {
+ this.serverId = serverId;
+ this.buildId = buildId;
+ this.deployment = deployment;
+ }
+
+ public String getServerId() {
+ return serverId;
+ }
+
+ public long getBuildId() {
+ return buildId;
+ }
+
+ public SharedDeploymentData getDeployment() {
+ return deployment;
+ }
+
}
}
diff --git a/src/com/projectswg/lightspeed/CommunicationService.java b/src/com/projectswg/lightspeed/CommunicationService.java
index c99e112..31ad304 100644
--- a/src/com/projectswg/lightspeed/CommunicationService.java
+++ b/src/com/projectswg/lightspeed/CommunicationService.java
@@ -34,6 +34,7 @@ import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.control.Intent;
import com.projectswg.common.control.Service;
import com.projectswg.common.info.ConfigFile;
@@ -117,8 +118,7 @@ public class CommunicationService extends Service implements TCPCallback {
@Override
public void onConnectionDisconnect(Socket s, SocketAddress addr) {
- if (addr == null)
- return;
+ Assert.notNull(addr);
Log.i(this, "%s disconnected", addr);
synchronized (sessions) {
sessions.remove(addr);
@@ -128,8 +128,7 @@ public class CommunicationService extends Service implements TCPCallback {
@Override
public void onIncomingData(Socket s, byte[] data) {
SocketAddress addr = s.getRemoteSocketAddress();
- if (addr == null)
- return;
+ Assert.notNull(addr);
LightspeedSession session;
synchronized (sessions) {
session = sessions.get(addr);
@@ -138,4 +137,8 @@ public class CommunicationService extends Service implements TCPCallback {
session.onIncoming(data);
}
+ public int getPort() {
+ return server.getPort();
+ }
+
}
diff --git a/src/com/projectswg/lightspeed/DeploymentService.java b/src/com/projectswg/lightspeed/DeploymentService.java
index 76ff61e..61a3477 100644
--- a/src/com/projectswg/lightspeed/DeploymentService.java
+++ b/src/com/projectswg/lightspeed/DeploymentService.java
@@ -37,6 +37,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.control.Intent;
import com.projectswg.common.control.Service;
import com.projectswg.common.info.Log;
@@ -106,7 +107,7 @@ public class DeploymentService extends Service {
public void onIntentReceived(Intent i) {
if (i instanceof LaunchStarshipIntent) {
SharedBuildData build = ((LaunchStarshipIntent) i).getBuild();
- Log.i(this, "Deploying %s... JAR: %s", build.getServer().getName(), build.getJar());
+ Log.i(this, "Deploying %s", build.getServer().getName());
ServerDeploymentData deployment = new ServerDeploymentData(new SharedDeploymentData(deploymentId.incrementAndGet(), build));
launch(deployment);
} else if (i instanceof InboundPacketIntent) {
@@ -116,7 +117,7 @@ public class DeploymentService extends Service {
private void processInboundPacketIntent(InetSocketAddress address, Packet p) {
switch (p.getType()) {
- case POST_DEPLOY: launchStarship(((PostDeployPacket) p).getBuildId()); break;
+ case POST_DEPLOY: launchStarship(((PostDeployPacket) p).getServerId()); break;
case POST_STOP_DEPLOY: processStopDeployment((PostStopDeployPacket) p); break;
case REQUEST_DEPLOYMENT_STATUS: processRequestDeploymentStatus(address, ((RequestPacket) p).getRequestId()); break;
case REQUEST_DEPLOYMENT_HISTORY:processRequestDeploymentHistory(address, ((RequestDeploymentHistoryPacket) p)); break;
@@ -145,10 +146,12 @@ public class DeploymentService extends Service {
}
private void processRequestDeploymentHistory(InetSocketAddress address, RequestDeploymentHistoryPacket req) {
- List deployments = getBackendData().getBuild(req.getBuildId()).getDeployments();
+ SharedServerData server = getBackendData().getServer(req.getServerId());
+ Assert.notNull(server);
+ List deployments = server.getDeployments();
synchronized (this.deployments) {
for (ServerDeploymentData deployment : this.deployments.values()) {
- if (deployment.getBuild().getId() == req.getBuildId()) {
+ if (deployment.getServer().getName().equals(req.getServerId())) {
SharedDeploymentData data = new SharedDeploymentData(deployment.getId(), deployment.getBuild());
data.setStartTime(deployment.getStartTime());
data.setEndTime(deployment.getEndTime());
@@ -159,8 +162,9 @@ public class DeploymentService extends Service {
new OutboundPacketIntent(address, ResponseDeploymentHistoryPacket.create(req.getRequestId(), deployments)).broadcast();
}
- private void launchStarship(long buildId) {
- SharedBuildData build = getBackendData().getBuild(buildId);
+ private void launchStarship(String serverId) {
+ SharedServerData server = getBackendData().getServer(serverId);
+ SharedBuildData build = server.getLastBuild();
if (!launchStarshipChecks(build))
return;
new LaunchStarshipIntent(build).broadcast();
@@ -179,20 +183,13 @@ public class DeploymentService extends Service {
Log.e(this, "Unable to launch %s/%d - tests failed!", build.getServer().getName(), build.getId());
return false;
}
- if (build.getJar() == null) {
- Log.e(this, "Unable to launch %s/%d - no jar found!", build.getServer().getName(), build.getId());
- return false;
- }
return true;
}
private void launch(ServerDeploymentData deployment) {
+ Assert.notNull(deployment.getServer());
String serverId = deployment.getServer().getName();
- File jar = deployment.getBuild().getJar();
- if (jar == null) {
- Log.e(this, "Unable to deploy %s. JAR was not successfully created!", serverId);
- return;
- }
+ File jar = new File("data/releases/"+serverId+".jar");
if (isDeploying(serverId)) {
Log.e(this, "Unable to deploy %s. Already deploying!", serverId);
return;
diff --git a/src/com/projectswg/lightspeed/LightspeedManager.java b/src/com/projectswg/lightspeed/LightspeedManager.java
index 7db0b06..85b093d 100644
--- a/src/com/projectswg/lightspeed/LightspeedManager.java
+++ b/src/com/projectswg/lightspeed/LightspeedManager.java
@@ -49,4 +49,8 @@ public class LightspeedManager extends Manager {
addChildService(communicationService);
}
+ public int getCommunicationPort() {
+ return communicationService.getPort();
+ }
+
}
diff --git a/src/com/projectswg/lightspeed/StarshipProcess.java b/src/com/projectswg/lightspeed/StarshipProcess.java
index b78d956..cd9a317 100644
--- a/src/com/projectswg/lightspeed/StarshipProcess.java
+++ b/src/com/projectswg/lightspeed/StarshipProcess.java
@@ -33,6 +33,8 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
+import com.projectswg.common.control.Assert;
+
public class StarshipProcess {
private final Object processMutex;
@@ -128,7 +130,8 @@ public class StarshipProcess {
while (gobbler.readLine() != null)
; // gobble.
} catch (IOException e) {
-
+ if (Assert.debug())
+ e.printStackTrace();
}
}
diff --git a/src/com/projectswg/lightspeed/build/BuildMethod.java b/src/com/projectswg/lightspeed/build/BuildMethod.java
new file mode 100644
index 0000000..eafe275
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/BuildMethod.java
@@ -0,0 +1,34 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build;
+
+import com.projectswg.lightspeed.build.ServerBuildData.InstallationCallback;
+
+public interface BuildMethod {
+ ServerBuildData createJar(String repo, InstallationCallback callback);
+}
diff --git a/src/com/projectswg/lightspeed/build/BuildService.java b/src/com/projectswg/lightspeed/build/BuildService.java
index cc0c599..a9a60f2 100644
--- a/src/com/projectswg/lightspeed/build/BuildService.java
+++ b/src/com/projectswg/lightspeed/build/BuildService.java
@@ -31,6 +31,7 @@ import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -39,9 +40,9 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.control.Intent;
import com.projectswg.common.control.Service;
-import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.Log;
import com.projectswg.common.info.RelationalDatabase;
import com.projectswg.common.info.RelationalServerFactory;
@@ -64,12 +65,12 @@ import com.projectswg.lightspeed_frontend.data.SharedServerData;
public class BuildService extends Service {
- private final MavenInterface maven;
+ private final BuildMethod buildMethod;
private final AtomicLong buildId;
private final Map inprogress;
public BuildService() {
- maven = new MavenInterface(new File(getConfig(ConfigFile.LIGHTSPEED).getString("MAVEN", "/usr/bin/mvn")));
+ buildMethod = new JavaBuildMethod();
buildId = new AtomicLong(0);
inprogress = new HashMap<>();
@@ -83,6 +84,8 @@ public class BuildService extends Service {
ResultSet set = db.executeQuery("SELECT MAX(id) FROM builds");
if (set.next())
buildId.set(set.getLong(1));
+ else
+ Assert.fail();
} catch (SQLException e) {
e.printStackTrace();
}
@@ -98,7 +101,7 @@ public class BuildService extends Service {
private void onPrepareStarshipIntent(PrepareStarshipIntent psi) {
Log.i(this, "Building %s...", psi.getServer().getName());
- ServerBuildData installation = maven.createJar(psi.getServer().getDirectory(), new InstallationCallback() {
+ ServerBuildData installation = buildMethod.createJar(psi.getServer().getDirectory(), new InstallationCallback() {
public void onStateChanged(InstallationState oldState, InstallationState newState) { }
public void onCompleted() { BuildService.this.onCompleted(psi.getServer().getName()); }
public void onCancelled() { BuildService.this.onCancelled(psi.getServer().getName()); }
@@ -157,7 +160,7 @@ public class BuildService extends Service {
if (server == null)
builds = new ArrayList<>();
else
- builds = server.getBuildData();
+ builds = server.getBuilds();
new OutboundPacketIntent(address, ResponseBuildHistoryPacket.create(requestId, builds)).broadcast();
}
@@ -189,9 +192,10 @@ public class BuildService extends Service {
if (installation != null) {
Log.i(this, "Build cancelled: %s", serverId);
SharedServerData server = getBackendData().getServer(serverId);
- if (server == null)
- return;
- getBackendData().insertBuild(new SharedBuildData(buildId.incrementAndGet(), server, installation, null));
+ Assert.notNull(server);
+ getBackendData().insertBuild(new SharedBuildData(buildId.incrementAndGet(), server, installation));
+ } else {
+ Assert.fail();
}
}
@@ -202,12 +206,11 @@ public class BuildService extends Service {
Log.e(this, "Build Success - error while retrieving server information. Server: %s", serverId);
return;
}
- File jar = new File("data/releases/release-"+id+".jar");
- if (installation.getJar() != null)
- Files.copy(installation.getJar().toPath(), jar.toPath());
- else
- jar = null;
- SharedBuildData build = new SharedBuildData(buildId.incrementAndGet(), server, installation, jar);
+ if (installation.getJar() != null) {
+ File jar = new File("data/releases/"+serverId+".jar");
+ Files.copy(installation.getJar().toPath(), jar.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ SharedBuildData build = new SharedBuildData(buildId.incrementAndGet(), server, installation);
getBackendData().insertBuild(build);
processPostBuild(build);
} catch (IOException e) {
diff --git a/src/com/projectswg/lightspeed/build/InstallationState.java b/src/com/projectswg/lightspeed/build/InstallationState.java
index d1b4b35..36db5fd 100644
--- a/src/com/projectswg/lightspeed/build/InstallationState.java
+++ b/src/com/projectswg/lightspeed/build/InstallationState.java
@@ -33,6 +33,7 @@ public enum InstallationState {
BUILDING,
TESTING,
INSTALLING,
- DONE,
- CANCELLED
+ SUCCESS,
+ CANCELLED,
+ FAILED
}
diff --git a/src/com/projectswg/lightspeed/build/JavaBuildMethod.java b/src/com/projectswg/lightspeed/build/JavaBuildMethod.java
new file mode 100644
index 0000000..c80eebc
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/JavaBuildMethod.java
@@ -0,0 +1,119 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build;
+
+import java.io.File;
+
+import com.projectswg.common.data.TestDetails;
+import com.projectswg.common.utilities.TimeUtilities;
+import com.projectswg.lightspeed.build.ServerBuildData.InstallationCallback;
+import com.projectswg.lightspeed.build.java_builder.CustomJavaBuild;
+import com.projectswg.lightspeed.build.java_builder.CustomJavaException;
+import com.projectswg.lightspeed.build.java_builder.CustomJavaInstall;
+import com.projectswg.lightspeed.build.java_builder.CustomJavaTest;
+
+public class JavaBuildMethod implements BuildMethod {
+
+ private final CustomJavaBuild build;
+ private final CustomJavaTest test;
+ private final CustomJavaInstall install;
+
+ public JavaBuildMethod() {
+ build = new CustomJavaBuild(new File(getJdk() + "/bin/javac"));
+ test = new CustomJavaTest(new File(getJdk() + "/bin/java"));
+ install = new CustomJavaInstall(new File(getJdk() + "/bin/jar"));
+ }
+
+ @Override
+ public ServerBuildData createJar(String repo, InstallationCallback callback) {
+ String processedRepo = processRepositoryArgument(repo);
+ ServerBuildData buildData = new ServerBuildData(new File(repo));
+ new Thread(() -> {
+ createJar(processedRepo, buildData, callback);
+ }).start();
+ return buildData;
+ }
+
+ private String getJdk() {
+ String jrePath = System.getProperty("java.home");
+ return jrePath.substring(0, jrePath.indexOf('/', jrePath.indexOf("jdk")));
+ }
+
+ private String processRepositoryArgument(String repo) {
+ if (repo.endsWith("/"))
+ return repo.substring(0, repo.length()-1);
+ return repo;
+ }
+
+ private void createJar(String repo, ServerBuildData buildData, InstallationCallback callback) {
+ try {
+ updateState(buildData, callback, InstallationState.BUILDING);
+ build.compile(buildData, "main.ProjectSWG");
+ if (detectCancelled(buildData, callback))
+ return;
+
+ updateState(buildData, callback, InstallationState.TESTING);
+ TestDetails details = test.test(buildData);
+ if (details.getFailures() > 0)
+ throw new CustomJavaException("Test: Failed tests");
+ if (detectCancelled(buildData, callback))
+ return;
+
+ updateState(buildData, callback, InstallationState.INSTALLING);
+ install.createRawJar(buildData, "main.ProjectSWG");
+ buildData.setCompletedTime(TimeUtilities.getTime());
+ updateState(buildData, callback, InstallationState.SUCCESS);
+ } catch (CustomJavaException e) {
+ System.err.println(e.getMessage());
+ updateState(buildData, callback, InstallationState.FAILED);
+ } catch (Exception e) {
+ e.printStackTrace();
+ updateState(buildData, callback, InstallationState.FAILED);
+ }
+ }
+
+ private boolean detectCancelled(ServerBuildData buildData, InstallationCallback callback) {
+ if (buildData.getState() == InstallationState.CANCELLED) {
+ updateState(buildData, callback, InstallationState.CANCELLED);
+ return true;
+ }
+ return false;
+ }
+
+ private void updateState(ServerBuildData buildData, InstallationCallback callback, InstallationState newState) {
+ InstallationState oldState = buildData.getState();
+ buildData.setState(newState);
+ if (callback != null)
+ callback.onStateChanged(oldState, newState);
+ if (callback != null && newState == InstallationState.CANCELLED)
+ callback.onCancelled();
+ else if (callback != null && (newState == InstallationState.SUCCESS || newState == InstallationState.FAILED))
+ callback.onCompleted();
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/MavenInterface.java b/src/com/projectswg/lightspeed/build/MavenInterface.java
index 63796c8..85e8be0 100644
--- a/src/com/projectswg/lightspeed/build/MavenInterface.java
+++ b/src/com/projectswg/lightspeed/build/MavenInterface.java
@@ -36,7 +36,7 @@ import java.util.regex.Pattern;
import com.projectswg.lightspeed.build.ServerBuildData.InstallationCallback;
-public class MavenInterface {
+public class MavenInterface implements BuildMethod {
private final File maven;
private boolean offline;
@@ -63,7 +63,8 @@ public class MavenInterface {
}
public ServerBuildData createJar(String repo, InstallationCallback callback) {
- return ServerBuildData.install(maven, new File(repo), offline, callback);
+// return ServerBuildData.install(maven, new File(repo), offline, callback);
+ return null;
}
private boolean initializeMaven() {
diff --git a/src/com/projectswg/lightspeed/build/ServerBuildData.java b/src/com/projectswg/lightspeed/build/ServerBuildData.java
index 37eddf1..458cf42 100644
--- a/src/com/projectswg/lightspeed/build/ServerBuildData.java
+++ b/src/com/projectswg/lightspeed/build/ServerBuildData.java
@@ -27,24 +27,12 @@
***********************************************************************************/
package com.projectswg.lightspeed.build;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import com.projectswg.common.data.TestDetails;
-import com.projectswg.common.utilities.TimeUtilities;
public class ServerBuildData {
- private final AtomicBoolean cancelBuild;
private final File directory;
- private final boolean offline;
- private final InstallationCallback callback;
- private final Pattern jarPattern;
private InstallationState state;
private String build;
private String test;
@@ -55,41 +43,21 @@ public class ServerBuildData {
private boolean buildSuccess;
private boolean testSuccess;
- private ServerBuildData(File directory, boolean offline, InstallationCallback callback) {
+ public ServerBuildData(File directory) {
this.directory = directory;
- this.offline = offline;
- this.cancelBuild = new AtomicBoolean(false);
- this.callback = callback;
- this.jarPattern = Pattern.compile(".*Building jar: (.*-with-dependencies\\.jar).*");
this.state = InstallationState.IDLE;
+ this.build = "";
+ this.test = "";
+ this.jar = null;
+ this.testDetails = null;
+ this.completedTime = 0;
+ this.compileTime = 0;
+ this.buildSuccess = false;
+ this.testSuccess = false;
}
- public static ServerBuildData install(File maven, File directory, boolean offline, InstallationCallback callback) {
- ServerBuildData details = new ServerBuildData(directory, offline, callback);
- Thread t = new Thread(() -> details.install(maven));
- t.setName("InstallationDetails-install(dir="+directory.getAbsolutePath()+")");
- t.start();
- return details;
- }
-
- private void install(File maven) {
- if (state != InstallationState.IDLE)
- return;
- long start = System.nanoTime();
- clean(maven);
- build(maven);
- compileTime = (System.nanoTime()-start)/1E6;
- completedTime = TimeUtilities.getTime();
- if (cancelBuild.get()) {
- buildSuccess = false;
- testSuccess = false;
- updateState(InstallationState.CANCELLED);
- } else
- updateState(InstallationState.DONE);
- }
-
- public boolean isOffline() {
- return offline;
+ public File getDirectory() {
+ return directory;
}
public InstallationState getState() {
@@ -128,101 +96,44 @@ public class ServerBuildData {
return testSuccess;
}
- public boolean isSuccess() {
- return isBuildSuccess() && isTestSuccess();
+ public void setState(InstallationState state) {
+ this.state = state;
+ }
+
+ public void setBuildString(String build) {
+ this.build = build;
+ }
+
+ public void setTestString(String test) {
+ this.test = test;
+ }
+
+ public void setJar(File jar) {
+ this.jar = jar;
+ }
+
+ public void setTestDetails(TestDetails testDetails) {
+ this.testDetails = testDetails;
+ }
+
+ public void setCompletedTime(long completedTime) {
+ this.completedTime = completedTime;
+ }
+
+ public void setCompileTime(double compileTime) {
+ this.compileTime = compileTime;
+ }
+
+ public void setBuildSuccess(boolean buildSuccess) {
+ this.buildSuccess = buildSuccess;
+ }
+
+ public void setTestSuccess(boolean testSuccess) {
+ this.testSuccess = testSuccess;
}
- /**
- * Stops the build. Cannot be restarted
- */
public void cancel() {
- cancelBuild.set(true);
- }
-
- private boolean clean(File maven) {
- try {
- updateState(InstallationState.CLEANING);
- new ProcessBuilder(maven.getAbsolutePath(), "clean").directory(directory).redirectErrorStream(true).start().waitFor();
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
-
- }
- return false;
- }
-
- private void build(File maven) {
- String command = "package";
- if (offline)
- command += " -o";
- Process installProcess = null;
- try {
- updateState(InstallationState.BUILDING);
- installProcess = new ProcessBuilder(maven.getAbsolutePath(), command).directory(directory).redirectErrorStream(true).start();
- try (BufferedReader installReader = new BufferedReader(new InputStreamReader(installProcess.getInputStream()))) {
- String line;
- this.buildSuccess = true;
- this.testSuccess = true;
- while ((line = installReader.readLine()) != null && !cancelBuild.get()) {
- processLine(line);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (installProcess != null)
- installProcess.destroy();
- installProcess = null;
- }
-
- private void processLine(String line) {
- if (line.contains("BUILD FAILURE")) {
- buildSuccess = false;
- testSuccess = false;
- }
- if (line.equals(" T E S T S"))
- updateState(InstallationState.TESTING);
-
- switch (state) {
- case BUILDING: processBuildLine(line); break;
- case TESTING: processTestLine(line); break;
- case INSTALLING: processInstallLine(line); break;
- default: break;
- }
- }
-
- private void processBuildLine(String line) {
- build += line + '\n';
- }
-
- private void processTestLine(String line) {
- test += line + '\n';
- if (line.contains("Tests run")) {
- testDetails = TestDetails.create(line);
- if (testDetails == null || testDetails.getFailures() > 0)
- testSuccess = false;
- updateState(InstallationState.INSTALLING);
- }
- }
-
- private void processInstallLine(String line) {
- Matcher m = jarPattern.matcher(line);
- if (m.matches())
- jar = new File(m.group(1));
- }
-
- private void updateState(InstallationState state) {
- if (this.state != state) {
- InstallationState old = this.state;
- this.state = state;
- if (callback != null)
- callback.onStateChanged(old, state);
- if (state == InstallationState.DONE)
- callback.onCompleted();
- else if (state == InstallationState.CANCELLED)
- callback.onCancelled();
- }
+ this.state = InstallationState.CANCELLED;
}
public interface InstallationCallback {
diff --git a/src/com/projectswg/lightspeed/build/jar_loader/LJLConstants.java b/src/com/projectswg/lightspeed/build/jar_loader/LJLConstants.java
new file mode 100644
index 0000000..6a3a3f5
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/jar_loader/LJLConstants.java
@@ -0,0 +1,44 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.jar_loader;
+
+public class LJLConstants {
+
+ protected static final String REDIRECTED_CLASS_PATH_MANIFEST_NAME = "Rsrc-Class-Path";
+ protected static final String REDIRECTED_MAIN_CLASS_MANIFEST_NAME = "Rsrc-Main-Class";
+ protected static final String DEFAULT_REDIRECTED_CLASSPATH = "";
+ protected static final String MAIN_METHOD_NAME = "main";
+ protected static final String JAR_INTERNAL_URL_PROTOCOL_WITH_COLON = "jar:rsrc:";
+ protected static final String JAR_INTERNAL_SEPARATOR = "!/";
+ protected static final String INTERNAL_URL_PROTOCOL_WITH_COLON = "rsrc:";
+ protected static final String INTERNAL_URL_PROTOCOL = "rsrc";
+ protected static final String PATH_SEPARATOR = "/";
+ protected static final String CURRENT_DIR = "./";
+ protected static final String UTF8_ENCODING = "UTF-8";
+
+}
diff --git a/src/com/projectswg/lightspeed/build/jar_loader/LJLURLConnection.java b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLConnection.java
new file mode 100644
index 0000000..888904e
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLConnection.java
@@ -0,0 +1,59 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.jar_loader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+
+public class LJLURLConnection extends URLConnection {
+
+ private ClassLoader classLoader;
+
+ public LJLURLConnection(URL url, ClassLoader classLoader) {
+ super(url);
+ this.classLoader = classLoader;
+ }
+
+ public void connect() throws IOException {
+
+ }
+
+ public InputStream getInputStream() throws IOException {
+ String file = URLDecoder.decode(url.getFile(), LJLConstants.UTF8_ENCODING);
+ InputStream result = classLoader.getResourceAsStream(file);
+ if (result == null) {
+ throw new MalformedURLException("Could not open InputStream for URL '" + url + "'");
+ }
+ return result;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandler.java b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandler.java
new file mode 100644
index 0000000..e7da5f5
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandler.java
@@ -0,0 +1,58 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.jar_loader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLStreamHandler;
+
+public class LJLURLStreamHandler extends URLStreamHandler {
+
+ private ClassLoader classLoader;
+
+ public LJLURLStreamHandler(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ protected java.net.URLConnection openConnection(URL u) throws IOException {
+ return new LJLURLConnection(u, classLoader);
+ }
+
+ protected void parseURL(URL url, String spec, int start, int limit) {
+ String file;
+ if (spec.startsWith(LJLConstants.INTERNAL_URL_PROTOCOL_WITH_COLON))
+ file = spec.substring(5);
+ else if (url.getFile().equals(LJLConstants.CURRENT_DIR))
+ file = spec;
+ else if (url.getFile().endsWith(LJLConstants.PATH_SEPARATOR))
+ file = url.getFile() + spec;
+ else
+ file = spec;
+ setURL(url, LJLConstants.INTERNAL_URL_PROTOCOL, "", -1, null, null, file, null, null);
+ }
+}
diff --git a/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandlerFactory.java b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandlerFactory.java
new file mode 100644
index 0000000..a81f243
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/jar_loader/LJLURLStreamHandlerFactory.java
@@ -0,0 +1,48 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.jar_loader;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+
+public class LJLURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+ private final ClassLoader defaultLoader;
+
+ public LJLURLStreamHandlerFactory(ClassLoader cl) {
+ this.defaultLoader = cl;
+ }
+
+ @Override
+ public URLStreamHandler createURLStreamHandler(String protocol) {
+ if (protocol.equals(LJLConstants.INTERNAL_URL_PROTOCOL))
+ return new LJLURLStreamHandler(defaultLoader);
+ return null;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/jar_loader/LightspeedJarLoader.java b/src/com/projectswg/lightspeed/build/jar_loader/LightspeedJarLoader.java
new file mode 100644
index 0000000..5a43b51
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/jar_loader/LightspeedJarLoader.java
@@ -0,0 +1,93 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.jar_loader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+
+public class LightspeedJarLoader {
+
+ public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, IOException {
+ ManifestInfo mi = getManifestInfo();
+ URL.setURLStreamHandlerFactory(new LJLURLStreamHandlerFactory(Thread.currentThread().getContextClassLoader()));
+ URL[] rsrcUrls = new URL[mi.rsrcClassPath.length];
+ for (int i = 0; i < mi.rsrcClassPath.length; i++) {
+ String rsrcPath = mi.rsrcClassPath[i];
+ if (rsrcPath.endsWith(LJLConstants.PATH_SEPARATOR))
+ rsrcUrls[i] = new URL(LJLConstants.INTERNAL_URL_PROTOCOL_WITH_COLON + rsrcPath);
+ else
+ rsrcUrls[i] = new URL(LJLConstants.JAR_INTERNAL_URL_PROTOCOL_WITH_COLON + rsrcPath + LJLConstants.JAR_INTERNAL_SEPARATOR);
+ }
+ ClassLoader jceClassLoader = new URLClassLoader(rsrcUrls, null);
+ Thread.currentThread().setContextClassLoader(jceClassLoader);
+ Class> c = Class.forName(mi.rsrcMainClass, true, jceClassLoader);
+ Method main = c.getMethod(LJLConstants.MAIN_METHOD_NAME, new Class[] {args.getClass()});
+ main.invoke((Object) null, new Object[] {args});
+ }
+
+ private static ManifestInfo getManifestInfo() throws IOException {
+ Enumeration resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
+ while (resEnum.hasMoreElements()) {
+ try {
+ URL url = (URL) resEnum.nextElement();
+ InputStream is = url.openStream();
+ if (is != null) {
+ ManifestInfo result = new ManifestInfo();
+ Manifest manifest = new Manifest(is);
+ Attributes mainAttribs = manifest.getMainAttributes();
+ result.rsrcMainClass = mainAttribs.getValue(LJLConstants.REDIRECTED_MAIN_CLASS_MANIFEST_NAME);
+ String rsrcCP = mainAttribs.getValue(LJLConstants.REDIRECTED_CLASS_PATH_MANIFEST_NAME);
+ if (rsrcCP == null)
+ rsrcCP = LJLConstants.DEFAULT_REDIRECTED_CLASSPATH;
+ result.rsrcClassPath = rsrcCP.split(" ");
+ if ((result.rsrcMainClass != null) && !result.rsrcMainClass.trim().equals(""))
+ return result;
+ }
+ } catch (Exception e) {
+ // Silently ignore wrong manifests on classpath?
+ }
+ }
+ System.err.println("Missing attributes for JarRsrcLoader in Manifest (" + LJLConstants.REDIRECTED_MAIN_CLASS_MANIFEST_NAME + ", " + LJLConstants.REDIRECTED_CLASS_PATH_MANIFEST_NAME + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ return null;
+ }
+
+ private static class ManifestInfo {
+ String rsrcMainClass;
+ String[] rsrcClassPath;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/java_builder/CustomJavaBuild.java b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaBuild.java
new file mode 100644
index 0000000..4066f60
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaBuild.java
@@ -0,0 +1,76 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.java_builder;
+
+import java.io.File;
+
+import com.projectswg.lightspeed.build.ServerBuildData;
+
+public class CustomJavaBuild {
+
+ private static final String SRC_DIR = CustomJavaCommon.SRC_DIR;
+ private static final String TST_DIR = CustomJavaCommon.TST_DIR;
+ private static final String BIN_DIR = CustomJavaCommon.BIN_DIR;
+ private static final String LIB_DIR = CustomJavaCommon.LIB_DIR;
+ private static final String SEP = CustomJavaCommon.SEP;
+
+ private final File javac;
+
+ public CustomJavaBuild(File javac) {
+ this.javac = javac;
+ }
+
+ public void compile(ServerBuildData buildData, String file) throws CustomJavaException {
+ String repo = buildData.getDirectory().getAbsolutePath();
+ file = file.replace('.', File.separatorChar);
+ String [] command = {
+ javac.getAbsolutePath(),
+ "-d", repo + SEP + BIN_DIR,
+ "-classpath", CustomJavaCommon.getFiles(LIB_DIR + SEP, repo + SEP, ".jar", ':')+":.",
+ "-sourcepath", repo + SEP + SRC_DIR
+ };
+ String [] commands = CustomJavaCommon.merge(command, getFiles(repo));
+ StringBuilder builder = new StringBuilder();
+ long start = System.nanoTime();
+ int ret = CustomJavaCommon.execute(commands, new File(repo), builder, false);
+ buildData.setCompileTime((System.nanoTime()-start)/1E9);
+ buildData.setBuildString(builder.toString());
+ buildData.setBuildSuccess(ret == 0);
+ if (ret != 0)
+ throw new CustomJavaException("Build: Failed to compile project!");
+ }
+
+ private String [] getFiles(String repo) {
+ String fileSpaceSplit = "";
+ fileSpaceSplit += CustomJavaCommon.getFiles(SRC_DIR+SEP, repo+SEP, ".java", ' ');
+ fileSpaceSplit += ' ';
+ fileSpaceSplit += CustomJavaCommon.getFiles(TST_DIR+SEP, repo+SEP, ".java", ' ');
+ return fileSpaceSplit.split(" ");
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/java_builder/CustomJavaCommon.java b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaCommon.java
new file mode 100644
index 0000000..ca41713
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaCommon.java
@@ -0,0 +1,133 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.java_builder;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomJavaCommon {
+
+ protected static final String OUT_JAR = "bin/ProjectSWG.jar";
+ protected static final String SRC_DIR = "src";
+ protected static final String TST_DIR = "test";
+ protected static final String BIN_DIR = "bin";
+ protected static final String LIB_DIR = "lib";
+ protected static final String SEP = File.separator;
+
+ public static int execute(String [] command, File dir) {
+ return execute(command, dir, false);
+ }
+
+ public static int execute(String [] command, File dir, boolean output) {
+ return execute(command, dir, null, output);
+ }
+
+ public static int execute(String [] command, File dir, StringBuilder out, boolean output) {
+ try {
+ Process process = new ProcessBuilder(command).directory(dir).redirectErrorStream(true).start();
+ if (out == null)
+ ingestOutput(process.getInputStream(), output);
+ else
+ out.append(getOutput(process.getInputStream()));
+ return process.waitFor();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+
+ }
+ return -1;
+ }
+
+ public static String getOutput(InputStream is) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ StringBuilder builder = new StringBuilder();
+ String line;
+ try {
+ while ((line = reader.readLine()) != null) {
+ builder.append(line + '\n');
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return builder.toString();
+ }
+
+ public static void ingestOutput(InputStream is, boolean output) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String line;
+ try {
+ while ((line = reader.readLine()) != null) {
+ if (output)
+ System.out.println(line);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String [] merge(String [] left, String [] right) {
+ String [] ret = new String[left.length + right.length];
+ System.arraycopy(left, 0, ret, 0, left.length);
+ System.arraycopy(right, 0, ret, left.length, right.length);
+ return ret;
+ }
+
+ public static String getFiles(String repo, String base, String extension, char delim) {
+ return getJavaFiles(base+repo, extension, delim).replace(base, "");
+ }
+
+ public static String getJavaFiles(String repo, String extension, char delim) {
+ File dir = new File(repo);
+ String ret = "";
+ for (String file : getJavaFilesRecursive(extension, dir)) {
+ ret += file + delim;
+ }
+ if (ret.isEmpty())
+ return ret;
+ return ret.substring(0, ret.length()-1);
+ }
+
+ public static List getJavaFilesRecursive(String extension, File dir) {
+ List files = new ArrayList<>();
+ for (String subStr : dir.list()) {
+ File sub = new File(dir, subStr);
+ if (sub.isDirectory()) {
+ files.addAll(getJavaFilesRecursive(extension, sub));
+ } else if (sub.getName().endsWith(extension)) {
+ files.add(sub.getAbsolutePath());
+ }
+ }
+ return files;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/java_builder/CustomJavaException.java b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaException.java
new file mode 100644
index 0000000..ff730db
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaException.java
@@ -0,0 +1,38 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.java_builder;
+
+public class CustomJavaException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public CustomJavaException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/java_builder/CustomJavaInstall.java b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaInstall.java
new file mode 100644
index 0000000..7eec348
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaInstall.java
@@ -0,0 +1,167 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.java_builder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import com.projectswg.lightspeed.build.ServerBuildData;
+
+public class CustomJavaInstall {
+
+ private static final String OUT_JAR = CustomJavaCommon.OUT_JAR;
+ private static final String BIN_DIR = CustomJavaCommon.BIN_DIR;
+ private static final String LIB_DIR = CustomJavaCommon.LIB_DIR;
+ private static final String SEP = CustomJavaCommon.SEP;
+
+ private final File jar;
+
+ public CustomJavaInstall(File jar) {
+ this.jar = jar;
+ }
+
+ public void createRawJar(ServerBuildData buildData, String file) throws CustomJavaException {
+ String repo = buildData.getDirectory().getAbsolutePath();
+ File manifestFile = createManifest(repo, file);
+ String manifest = manifestFile.getAbsolutePath();
+ CustomJavaCommon.execute(getCommandLineArgs(repo, manifest), new File(repo));
+ manifestFile.delete();
+ installLoader(repo);
+ buildData.setJar(new File(repo, OUT_JAR));
+ }
+
+ private File createManifest(String repo, String file) throws CustomJavaException {
+ String manifest = "Rsrc-Main-Class: " + file + "\n";
+ manifest += "Rsrc-Class-Path: ./ " + CustomJavaCommon.getFiles(LIB_DIR + SEP, repo + SEP, ".jar", ' ') + "\n";
+ manifest += "Main-Class: com.projectswg.lightspeed.build.jar_loader.LightspeedJarLoader\n";
+ manifest += "Class-Path: .\n";
+ try {
+ File manifestFile = File.createTempFile("manifest", ".txt");
+ try (FileWriter fw = new FileWriter(manifestFile)) {
+ fw.write(manifest);
+ }
+ return manifestFile;
+ } catch (IOException e) {
+ throw new CustomJavaException("Install: Failed to create manifest. " + e.getClass().getSimpleName() + " " + e.getMessage());
+ }
+ }
+
+ private String [] getCommandLineArgs(String repo, String manifest) {
+ List classFiles = CustomJavaCommon.getJavaFilesRecursive(".class", new File(repo, BIN_DIR));
+ List libFiles = CustomJavaCommon.getJavaFilesRecursive(".jar", new File(repo, LIB_DIR));
+ String [] command = new String[4 + classFiles.size()*3 + libFiles.size()];
+ int i = 0;
+ command[i++] = jar.getAbsolutePath();
+ command[i++] = "cvfm";
+ command[i++] = OUT_JAR;
+ command[i++] = manifest;
+ for (String f : classFiles) {
+ command[i++] = "-C";
+ command[i++] = BIN_DIR;
+ command[i++] = f.substring(repo.length()+1+BIN_DIR.length()+1);
+ }
+ for (String f : libFiles) {
+ command[i++] = f.substring(repo.length()+1);
+ }
+ return command;
+ }
+
+ private boolean installLoader(String repo) throws CustomJavaException {
+ File dir = createTempDirectory();
+ unzip("./LightspeedJarLoader.zip", dir.getAbsolutePath()+"/");
+ CustomJavaCommon.execute(new String[]{jar.getAbsolutePath(), "uvf", OUT_JAR, "-C", dir.getAbsolutePath(), "."}, new File(repo));
+ deleteDirectory(dir);
+ return true;
+ }
+
+ private File createTempDirectory() throws CustomJavaException {
+ try {
+ return Files.createTempDirectory("LightspeedInstall").toFile();
+ } catch (IOException e) {
+ throw new CustomJavaException("Install: Failed to create temp directory");
+ }
+ }
+
+ private void unzip(String zipFilePath, String destDir) throws CustomJavaException {
+ byte[] buffer = new byte[4*1024];
+ try (FileInputStream fis = new FileInputStream(zipFilePath)) {
+ try (ZipInputStream zis = new ZipInputStream(fis)) {
+ ZipEntry ze = zis.getNextEntry();
+ while (ze != null) {
+ File newFile = new File(destDir + File.separator + ze.getName());
+ if (ze.isDirectory()) {
+ newFile.mkdirs();
+ } else {
+ new File(newFile.getParent()).mkdirs();
+ try (FileOutputStream fos = new FileOutputStream(newFile)) {
+ int len;
+ while ((len = zis.read(buffer)) > 0) {
+ fos.write(buffer, 0, len);
+ }
+ }
+ }
+ zis.closeEntry();
+ ze = zis.getNextEntry();
+ }
+ }
+ } catch (IOException e) {
+ throw new CustomJavaException("Install: Failed to unzip jar loader. " + e.getClass().getSimpleName() + " " + e.getMessage());
+ }
+ }
+
+ private void deleteDirectory(File dir) {
+ try {
+ Files.walkFileTree(dir.toPath(), new FileVisitor() {
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; }
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; }
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ file.toFile().delete();
+ return FileVisitResult.CONTINUE;
+ }
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ dir.toFile().delete();
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException e) {
+ // Ignore - this is a minor issue as the files will be deleted on system reboot
+ }
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed/build/java_builder/CustomJavaTest.java b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaTest.java
new file mode 100644
index 0000000..b598c66
--- /dev/null
+++ b/src/com/projectswg/lightspeed/build/java_builder/CustomJavaTest.java
@@ -0,0 +1,106 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.build.java_builder;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.projectswg.common.data.TestDetails;
+import com.projectswg.lightspeed.build.ServerBuildData;
+
+public class CustomJavaTest {
+
+ private static final Pattern JUNIT_OK_PATTERN = Pattern.compile("OK \\((\\d+) tests\\)");
+ private static final Pattern JUNIT_FAIL_PATTERN = Pattern.compile("Tests run: (\\d+), Failures: (\\d+)");
+
+ private static final String LIB_DIR = CustomJavaCommon.LIB_DIR;
+ private static final String SEP = CustomJavaCommon.SEP;
+
+ private final File java;
+
+ public CustomJavaTest(File java) {
+ this.java = java;
+ }
+
+ public TestDetails test(ServerBuildData buildData) {
+ StringBuilder outBuilder = new StringBuilder();
+ int ret = executeTest(buildData.getDirectory().getAbsolutePath(), outBuilder);
+ String out = outBuilder.toString();
+ TestDetails details = parseOutput(ret, out);
+ buildData.setTestDetails(details);
+ buildData.setTestString(out);
+ buildData.setTestSuccess(ret == 0);
+ return details;
+ }
+
+ private int executeTest(String repo, StringBuilder oldBuilder) {
+ String libs = repo+"/bin:"+CustomJavaCommon.getFiles(LIB_DIR + SEP, repo + SEP, ".jar", ':');
+ libs += ":"+new File("junit-4.12.jar").getAbsolutePath();
+ libs += ":"+new File("hamcrest-core-1.3.jar").getAbsolutePath();
+ String [] command = {
+ java.getAbsolutePath(),
+ "-cp", libs,
+ "org.junit.runner.JUnitCore",
+ "main.TestAll"
+ };
+ return CustomJavaCommon.execute(command, new File(repo), oldBuilder, true);
+ }
+
+ private TestDetails parseOutput(int ret, String out) {
+ if (ret == 0) {
+ return parseOK(out);
+ } else if (out.contains("Tests run")) {
+ return parseFail(out);
+ } else {
+ System.out.println(out);
+ }
+ return new TestDetails(0, 0);
+ }
+
+ private TestDetails parseOK(String out) {
+ String line = out.substring(out.indexOf("OK"), out.indexOf('\n', out.indexOf("OK")));
+ Matcher m = JUNIT_OK_PATTERN.matcher(line);
+ if (!m.matches()) {
+ System.err.println("Failed to match OK pattern: " + line);
+ return new TestDetails(0, 0);
+ }
+ return new TestDetails(Integer.parseInt(m.group(1)), 0);
+ }
+
+ private TestDetails parseFail(String out) {
+ String line = out.substring(out.indexOf("Tests run"), out.indexOf('\n', out.indexOf("Tests run")));
+ Matcher m = JUNIT_FAIL_PATTERN.matcher(line);
+ if (!m.matches()) {
+ System.err.println("Failed to match FAIL pattern: " + line);
+ return new TestDetails(0, 0);
+ }
+ return new TestDetails(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)));
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/Frontend.java b/src/com/projectswg/lightspeed_frontend/Frontend.java
index 3a64e49..e6b17ea 100644
--- a/src/com/projectswg/lightspeed_frontend/Frontend.java
+++ b/src/com/projectswg/lightspeed_frontend/Frontend.java
@@ -29,38 +29,33 @@ package com.projectswg.lightspeed_frontend;
import java.net.InetSocketAddress;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.info.Log;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.request.RequestBuildHistoryPacket;
import com.projectswg.common.network.packets.request.RequestDeploymentHistoryPacket;
import com.projectswg.common.network.packets.request.RequestPacket;
import com.projectswg.common.network.packets.request.RequestServerListPacket;
-import com.projectswg.common.network.packets.response.ResponseBuildHistoryPacket;
-import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket;
import com.projectswg.common.network.packets.response.ResponsePacket;
-import com.projectswg.common.network.packets.response.ResponseServerListPacket;
-import com.projectswg.lightspeed_frontend.FrontendData.FrontendDataType;
import com.projectswg.lightspeed_frontend.communication.FrontendCommunication;
import com.projectswg.lightspeed_frontend.communication.FrontendLightspeedSession.LightspeedSessionCallback;
-import com.projectswg.lightspeed_frontend.data.SharedBuildData;
-import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedData;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
+import com.projectswg.lightspeed_frontend.intents.ConnectionStateUpdateIntent;
public class Frontend {
private final FrontendCommunication communication;
- private final FrontendData data;
+ private final SharedData data;
private final Map requests;
private final AtomicLong requestId;
public Frontend() {
communication = new FrontendCommunication();
- data = new FrontendData();
+ data = new SharedData();
requests = new HashMap<>();
requestId = new AtomicLong(0);
communication.setCallback(new LightspeedSessionCallback() {
@@ -70,21 +65,19 @@ public class Frontend {
}
public void start() {
- communication.start();
+ Assert.test(communication.start());
}
public void stop() {
Log.i(this, "Disconnecting...");
- communication.stop();
- Log.i(this, "Closing data...");
- data.close();
+ Assert.test(communication.stop());
}
public FrontendCommunication getCommunication() {
return communication;
}
- public FrontendData getData() {
+ public SharedData getData() {
return data;
}
@@ -110,87 +103,36 @@ public class Frontend {
}
public boolean isConnected() {
- return data.isConnected();
+ return communication.isConnected();
}
public void loadBuildHistory(String serverId, ResponseCallback callback) {
send(RequestBuildHistoryPacket.create(requestId.incrementAndGet(), serverId), callback);
}
- public void loadDeploymentHistory(long buildId, ResponseCallback callback) {
- send(RequestDeploymentHistoryPacket.create(requestId.incrementAndGet(), buildId), callback);
+ public void loadDeploymentHistory(String serverId, ResponseCallback callback) {
+ send(RequestDeploymentHistoryPacket.create(requestId.incrementAndGet(), serverId), callback);
}
public void requestCompleteLoad() {
- AtomicInteger requests = new AtomicInteger(1);
send(RequestServerListPacket.create(requestId.incrementAndGet()), (response) -> {
for (SharedServerData server : data.getServers()) {
- requests.incrementAndGet();
- loadBuildHistory(server.getName(), (buildResponse) -> {
- for (SharedBuildData build : server.getBuildData()) {
- requests.incrementAndGet();
- loadDeploymentHistory(build.getId(), (deploymentResponse) -> {
- if (requests.decrementAndGet() == 0)
- data.notifyDataUpdated(FrontendDataType.SERVER_LIST);
- });
- }
- if (requests.decrementAndGet() == 0)
- data.notifyDataUpdated(FrontendDataType.SERVER_LIST);
- });
+ loadBuildHistory(server.getName(), null);
+ loadDeploymentHistory(server.getName(), null);
}
- if (requests.decrementAndGet() == 0)
- data.notifyDataUpdated(FrontendDataType.SERVER_LIST);
});
}
private void onConnectionStateChanged(boolean connected) {
- data.setConnectionStatus(connected);
+ new ConnectionStateUpdateIntent(connected).broadcast();
}
private void processIncoming(Packet p) {
- switch (p.getType()) {
- case RESPONSE_SERVER_LIST: processServerList((ResponseServerListPacket) p); break;
- case RESPONSE_BUILD_HISTORY: processBuildHistory((ResponseBuildHistoryPacket) p); break;
- case RESPONSE_DEPLOYMENT_HISTORY: processDeploymentHistory((ResponseDeploymentHistoryPacket) p); break;
- default: break;
- }
+ data.interpretPacket(p);
if (p instanceof ResponsePacket)
processResponse((ResponsePacket) p);
}
- private void processServerList(ResponseServerListPacket p) {
- data.setServers(p.getServers());
- }
-
- private void processBuildHistory(ResponseBuildHistoryPacket p) {
- List buildHistory = p.getBuildHistory();
- if (buildHistory.isEmpty())
- return;
- SharedServerData server = data.getServer(p.getServerId());
- if (server == null)
- return;
- for (SharedBuildData build : buildHistory) {
- build.setServer(server);
- server.addBuild(build);
- }
- data.notifyDataUpdated(FrontendDataType.SERVER_LIST);
- }
-
- private void processDeploymentHistory(ResponseDeploymentHistoryPacket p) {
- List deploymentHistory = p.getDeploymentHistory();
- SharedServerData server = data.getServer(p.getServerId());
- if (server == null)
- return;
- SharedBuildData build = server.getBuildData(p.getBuildId());
- if (build == null)
- return;
- for (SharedDeploymentData deployment : deploymentHistory) {
- deployment.setBuild(build);
- build.addDeployment(deployment);
- }
- data.notifyDataUpdated(FrontendDataType.SERVER_LIST);
- }
-
private void processResponse(ResponsePacket rp) {
ResponseCallback callback;
synchronized (requests) {
diff --git a/src/com/projectswg/lightspeed_frontend/LightspeedFrontendGUI.java b/src/com/projectswg/lightspeed_frontend/LightspeedFrontendGUI.java
index 9cc1d66..cae4c8a 100644
--- a/src/com/projectswg/lightspeed_frontend/LightspeedFrontendGUI.java
+++ b/src/com/projectswg/lightspeed_frontend/LightspeedFrontendGUI.java
@@ -27,8 +27,15 @@
***********************************************************************************/
package com.projectswg.lightspeed_frontend;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+
+import com.projectswg.common.control.IntentManager;
import com.projectswg.common.info.Log;
import com.projectswg.lightspeed_frontend.gui.LightspeedPrimaryView;
+import com.projectswg.lightspeed_frontend.intents.ConnectionStateUpdateIntent;
import javafx.application.Application;
import javafx.scene.Scene;
@@ -43,6 +50,7 @@ public class LightspeedFrontendGUI extends Application {
public LightspeedFrontendGUI() {
frontend = new Frontend();
primaryView = new LightspeedPrimaryView(frontend);
+ IntentManager.getInstance().registerForIntent(ConnectionStateUpdateIntent.TYPE, (i) -> onConnectionUpdate(((ConnectionStateUpdateIntent) i).isConnected()));
frontend.start();
}
@@ -52,16 +60,12 @@ public class LightspeedFrontendGUI extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
+ processConnect();
+ IntentManager.getInstance().initialize();
Scene scene = new Scene(primaryView, 800, 640);
primaryStage.setTitle("Lightspeed Frontend");
primaryStage.setScene(scene);
- primaryStage.setMinWidth(scene.getWidth());
- primaryStage.setMinHeight(scene.getHeight());
- primaryStage.setMaxWidth(scene.getWidth());
- primaryStage.setMaxHeight(scene.getHeight());
primaryView.setOnMouseClicked((event) -> primaryView.requestFocus());
- primaryView.prefHeightProperty().bind(scene.heightProperty());
- primaryView.prefWidthProperty().bind(scene.widthProperty());
primaryView.requestFocus();
primaryStage.show();
primaryStage.setOnCloseRequest((we) -> {
@@ -70,11 +74,40 @@ public class LightspeedFrontendGUI extends Application {
});
}
+ private void processConnect() {
+ String address = "localhost";
+ int port = 44444;
+ Map named = getParameters().getNamed();
+ if (named.containsKey("address"))
+ address = named.get("address");
+ if (named.containsKey("port")) {
+ try {
+ port = Integer.parseInt(named.get("port"));
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ InetSocketAddress sock = new InetSocketAddress(InetAddress.getByName(address), port);
+ frontend.connect(sock);
+ primaryView.setConnectAddress(sock);
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+
private void close(WindowEvent we) {
Log.i(this, "Closing GUI...");
primaryView.close();
frontend.stop();
+ Log.i(this, "Terminating IntentManager...");
+ IntentManager.getInstance().terminate();
Log.i(this, "Closed.");
}
+ private void onConnectionUpdate(boolean connected) {
+ if (connected)
+ frontend.requestCompleteLoad();
+ }
+
}
diff --git a/src/com/projectswg/lightspeed_frontend/LightspeedFrontendText.java b/src/com/projectswg/lightspeed_frontend/LightspeedFrontendText.java
index 231320f..9cb43b1 100644
--- a/src/com/projectswg/lightspeed_frontend/LightspeedFrontendText.java
+++ b/src/com/projectswg/lightspeed_frontend/LightspeedFrontendText.java
@@ -48,6 +48,7 @@ import com.projectswg.common.network.packets.request.RequestDeploymentStatusPack
import com.projectswg.common.network.packets.request.RequestServerListPacket;
import com.projectswg.common.network.packets.response.ResponseBuildHistoryPacket;
import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket;
+import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket.DeploymentData;
import com.projectswg.common.network.packets.response.ResponseDeploymentStatusPacket;
import com.projectswg.common.network.packets.response.ResponseServerListPacket;
import com.projectswg.lightspeed_frontend.communication.FrontendCommunication;
@@ -166,11 +167,10 @@ public class LightspeedFrontendText implements LightspeedSessionCallback {
break;
case "deployment_history":
if (args.length < 3) {
- Log.e(this, "Invalid call to request build_history! Expected build id.");
+ Log.e(this, "Invalid call to request build_history! Expected server id.");
break;
}
- try { communication.send(RequestDeploymentHistoryPacket.create(0, Long.parseLong(args[2]))); }
- catch (NumberFormatException e) { e.printStackTrace(); }
+ communication.send(RequestDeploymentHistoryPacket.create(0, args[2]));
break;
default:
Log.e(this, "Unknown request: " + args[1]);
@@ -218,11 +218,11 @@ public class LightspeedFrontendText implements LightspeedSessionCallback {
private void processPostDeploy(String [] args) {
if (args.length < 3) {
- Log.e(this, "Invalid call to post deploy! Expected build id.");
+ Log.e(this, "Invalid call to post deploy! Expected server id.");
return;
}
try {
- communication.send(PostDeployPacket.create(Long.parseLong(args[2])));
+ communication.send(PostDeployPacket.create(args[2]));
} catch (NumberFormatException e) {
Log.e(this, "Invalid call to post deploy! Expected number for argument.");
}
@@ -278,8 +278,8 @@ public class LightspeedFrontendText implements LightspeedSessionCallback {
}
} else if (p instanceof ResponseDeploymentHistoryPacket) {
Log.i(this, "Deployments:");
- for (SharedDeploymentData deployment : ((ResponseDeploymentHistoryPacket) p).getDeploymentHistory()) {
- Log.i(this, " " + deployment);
+ for (DeploymentData deployment : ((ResponseDeploymentHistoryPacket) p).getDeploymentHistory()) {
+ Log.i(this, " " + deployment.getDeployment());
}
} else {
Log.i(this, "Received: " + p.getType());
diff --git a/src/com/projectswg/lightspeed_frontend/communication/FrontendCommunication.java b/src/com/projectswg/lightspeed_frontend/communication/FrontendCommunication.java
index e329a8d..20b6286 100644
--- a/src/com/projectswg/lightspeed_frontend/communication/FrontendCommunication.java
+++ b/src/com/projectswg/lightspeed_frontend/communication/FrontendCommunication.java
@@ -30,28 +30,42 @@ package com.projectswg.lightspeed_frontend.communication;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+import com.projectswg.common.control.Assert;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.utilities.ThreadUtilities;
+import com.projectswg.lightspeed.communication.LightspeedState;
import com.projectswg.lightspeed_frontend.communication.FrontendLightspeedSession.LightspeedSessionCallback;
public class FrontendCommunication {
+ private final AtomicBoolean running;
+
private ExecutorService executor;
private FrontendLightspeedSession session;
private LightspeedSessionCallback callback;
public FrontendCommunication() {
+ running = new AtomicBoolean(false);
session = null;
callback = null;
}
public boolean start() {
+ if (running.getAndSet(true)) {
+ Assert.fail();
+ return false;
+ }
executor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory("frontend-communication"));
return true;
}
public boolean stop() {
+ if (!running.getAndSet(false)) {
+ Assert.fail();
+ return false;
+ }
executor.shutdownNow();
if (session != null) {
session.disconnect();
@@ -60,6 +74,10 @@ public class FrontendCommunication {
return true;
}
+ public boolean isConnected() {
+ return session != null && session.getState() == LightspeedState.CONNECTED;
+ }
+
public void setCallback(LightspeedSessionCallback callback) {
if (session != null)
session.setCallback(callback);
@@ -67,7 +85,10 @@ public class FrontendCommunication {
}
public void connect(InetSocketAddress addr) {
+ if (addr == null)
+ throw new NullPointerException();
executor.execute(() -> {
+ Assert.test(callback != null);
if (session != null)
session.disconnect();
session = new FrontendLightspeedSession(addr);
@@ -78,6 +99,7 @@ public class FrontendCommunication {
public void disconnect() {
executor.execute(() -> {
+ Assert.test(session != null);
if (session != null) {
session.disconnect();
session = null;
@@ -86,6 +108,7 @@ public class FrontendCommunication {
}
public void send(Packet p) {
+ Assert.test(session != null);
if (session != null)
session.send(p);
}
diff --git a/src/com/projectswg/lightspeed_frontend/communication/FrontendLightspeedSession.java b/src/com/projectswg/lightspeed_frontend/communication/FrontendLightspeedSession.java
index 45da07c..b231a6a 100644
--- a/src/com/projectswg/lightspeed_frontend/communication/FrontendLightspeedSession.java
+++ b/src/com/projectswg/lightspeed_frontend/communication/FrontendLightspeedSession.java
@@ -100,9 +100,9 @@ public class FrontendLightspeedSession {
public void disconnect() {
socket.disconnect();
- callbackManager.stop();
Log.i(this, "Disconnected.");
updateState(LightspeedState.DISCONNECTED);
+ callbackManager.stop();
}
public void onIncoming(byte [] data) {
diff --git a/src/com/projectswg/lightspeed_frontend/data/SharedBuildData.java b/src/com/projectswg/lightspeed_frontend/data/SharedBuildData.java
index 6c6397c..9156714 100644
--- a/src/com/projectswg/lightspeed_frontend/data/SharedBuildData.java
+++ b/src/com/projectswg/lightspeed_frontend/data/SharedBuildData.java
@@ -27,27 +27,22 @@
***********************************************************************************/
package com.projectswg.lightspeed_frontend.data;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import me.joshlarson.json.JSONObject;
import com.projectswg.common.data.TestDetails;
+import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed.build.ServerBuildData;
import com.projectswg.lightspeed.build.InstallationState;
+import com.projectswg.lightspeed_frontend.intents.BuildDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.BuildDataUpdateIntent.BuildUpdateType;
public class SharedBuildData {
- private static final TestDetails DEFAULT_TEST_DETAILS = new TestDetails(0, 0, 0, 0);
+ private static final TestDetails DEFAULT_TEST_DETAILS = new TestDetails(0, 0);
private final long id;
- private final Map deployments;
private SharedServerData server;
- private SharedDeploymentData lastDeployment;
private long time;
private String buildString;
private String testString;
@@ -57,13 +52,10 @@ public class SharedBuildData {
private boolean testSuccess;
private boolean cancelled;
private TestDetails testDetails;
- private File jar;
public SharedBuildData(long id, SharedServerData server) {
this.id = id;
this.server = server;
- this.deployments = new HashMap<>();
- this.lastDeployment = null;
this.time = 0;
this.buildString = "";
this.testString = "";
@@ -73,21 +65,18 @@ public class SharedBuildData {
this.testSuccess = false;
this.cancelled = false;
this.testDetails = DEFAULT_TEST_DETAILS;
- this.jar = null;
}
- public SharedBuildData(long id, SharedServerData server, ServerBuildData installation, File jar) {
+ public SharedBuildData(long id, SharedServerData server, ServerBuildData installation) {
this(id, server);
this.buildString = installation.getBuildString();
this.testString = installation.getTestString();
this.time = installation.getCompletedTime();
this.compileTime = installation.getCompileTime();
- this.offline = installation.isOffline();
this.buildSuccess = installation.isBuildSuccess();
this.testSuccess = installation.isTestSuccess();
this.cancelled = installation.getState() == InstallationState.CANCELLED;
this.testDetails = installation.getTestDetails();
- this.jar = jar;
}
public SharedBuildData(JSONObject json) {
@@ -100,8 +89,7 @@ public class SharedBuildData {
this.buildSuccess = json.getBoolean("build_success");
this.testSuccess = json.getBoolean("test_success");
this.cancelled = json.getBoolean("cancelled");
- this.testDetails = new TestDetails(json.getInt("test_total"), json.getInt("test_failures"), json.getInt("test_errors"), json.getInt("test_skipped"));
- this.jar = null;
+ this.testDetails = new TestDetails(json.getInt("test_total"), json.getInt("test_failures"));
}
public JSONObject createJSON() {
@@ -117,8 +105,6 @@ public class SharedBuildData {
json.put("cancelled", cancelled);
json.put("test_total", testDetails.getTotal());
json.put("test_failures", testDetails.getFailures());
- json.put("test_errors", testDetails.getErrors());
- json.put("test_skipped", testDetails.getSkipped());
return json;
}
@@ -130,16 +116,6 @@ public class SharedBuildData {
return server;
}
- public List getDeployments() {
- synchronized (deployments) {
- return new ArrayList<>(deployments.values());
- }
- }
-
- public SharedDeploymentData getLastDeployment() {
- return lastDeployment;
- }
-
public long getTime() {
return time;
}
@@ -176,71 +152,62 @@ public class SharedBuildData {
return testDetails;
}
- public File getJar() {
- return jar;
+ public void setServer(SharedServerData server) {
+ this.server = server;
+ onUpdate();
}
public void setTime(long time) {
this.time = time;
- }
-
- public void addDeployment(SharedDeploymentData deployment) {
- synchronized (deployments) {
- deployments.put(deployment.getId(), deployment);
- if (lastDeployment == null || deployment.getId() > lastDeployment.getId())
- lastDeployment = deployment;
- }
- if (server != null)
- server.onDeploymentsChanged();
- }
-
- public void clearDeployments() {
- synchronized (deployments) {
- deployments.clear();
- lastDeployment = null;
- }
- if (server != null)
- server.onDeploymentsChanged();
- }
-
- public void setServer(SharedServerData server) {
- this.server = server;
+ onUpdate();
}
public void setBuildString(String buildString) {
this.buildString = buildString;
+ onUpdate();
}
public void setTestString(String testString) {
this.testString = testString;
+ onUpdate();
}
public void setCompileTime(double compileTime) {
this.compileTime = compileTime;
+ onUpdate();
}
public void setOffline(boolean offline) {
this.offline = offline;
+ onUpdate();
}
public void setBuildSuccess(boolean buildSuccess) {
this.buildSuccess = buildSuccess;
+ onUpdate();
}
public void setTestSuccess(boolean testSuccess) {
this.testSuccess = testSuccess;
+ onUpdate();
}
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
+ onUpdate();
}
public void setTestDetails(TestDetails testDetails) {
this.testDetails = testDetails;
+ onUpdate();
}
- public void setJar(File jar) {
- this.jar = jar;
+ public void interpretPacket(Packet p) {
+
+ }
+
+ private void onUpdate() {
+ new BuildDataUpdateIntent(server.getName(), id, BuildUpdateType.BUILD_UPDATED).broadcast();
}
public int hashCode() {
diff --git a/src/com/projectswg/lightspeed_frontend/data/SharedData.java b/src/com/projectswg/lightspeed_frontend/data/SharedData.java
new file mode 100644
index 0000000..888f6f5
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/data/SharedData.java
@@ -0,0 +1,146 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.data;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.projectswg.common.network.packets.Packet;
+import com.projectswg.common.network.packets.response.ResponseServerListPacket;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent.ServerUpdateType;
+
+public class SharedData {
+
+ private final Set servers;
+ private SharedServerData primaryServer;
+
+ public SharedData() {
+ servers = new HashSet<>();
+ }
+
+ public void addServer(SharedServerData data) {
+ synchronized (servers) {
+ if (!servers.add(data))
+ return;
+ }
+ new ServerDataUpdateIntent(data.getName(), ServerUpdateType.SERVER_ADDED).broadcast();
+ updatePrimaryServer();
+ }
+
+ public void removeServer(SharedServerData data) {
+ synchronized (servers) {
+ if (!servers.remove(data))
+ return;
+ }
+ new ServerDataUpdateIntent(data.getName(), ServerUpdateType.SERVER_REMOVED).broadcast();
+ updatePrimaryServer();
+ }
+
+ public void removeServer(String name) {
+ SharedServerData server = getServer(name);
+ if (server != null)
+ removeServer(server);
+ }
+
+ public List getServers() {
+ synchronized (servers) {
+ return new ArrayList<>(servers);
+ }
+ }
+
+ public SharedServerData getServer(String name) {
+ synchronized (servers) {
+ for (SharedServerData server : servers) {
+ if (server.getName().equals(name)) {
+ return server;
+ }
+ }
+ }
+ return null;
+ }
+
+ public SharedServerData getPrimaryServer() {
+ synchronized (servers) {
+ return primaryServer;
+ }
+ }
+
+ public void clearServers() {
+ synchronized (servers) {
+ servers.clear();
+ }
+ }
+
+ public void interpretPacket(Packet p) {
+ if (p instanceof ResponseServerListPacket) {
+ processResponseServerList((ResponseServerListPacket) p);
+ }
+ synchronized (servers) {
+ for (SharedServerData server : servers) {
+ server.interpretPacket(p);
+ }
+ }
+ }
+
+ private void updatePrimaryServer() {
+ synchronized (servers) {
+ SharedServerData bestPrimary = null;
+ for (SharedServerData server : servers) {
+ if (bestPrimary == null || bestPrimary.getName().compareTo(server.getName()) > 0) {
+ bestPrimary = server;
+ }
+ }
+ if (primaryServer == null || bestPrimary == null || !bestPrimary.equals(primaryServer)) {
+ primaryServer = bestPrimary;
+ }
+ }
+ if (primaryServer == null)
+ new ServerDataUpdateIntent("", ServerUpdateType.PRIMARY_SERVER_CHANGED).broadcast();
+ else
+ new ServerDataUpdateIntent(primaryServer.getName(), ServerUpdateType.PRIMARY_SERVER_CHANGED).broadcast();
+ }
+
+ private void processResponseServerList(ResponseServerListPacket p) {
+ List removeList = getServers();
+ for (String str : p.getServers()) {
+ SharedServerData server = getServer(str);
+ if (server == null) {
+ addServer(new SharedServerData(str));
+ } else {
+ removeList.remove(server);
+ }
+ }
+ for (SharedServerData rm : removeList) {
+ removeServer(rm);
+ }
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/data/SharedDeploymentData.java b/src/com/projectswg/lightspeed_frontend/data/SharedDeploymentData.java
index 45c051e..580ec5d 100644
--- a/src/com/projectswg/lightspeed_frontend/data/SharedDeploymentData.java
+++ b/src/com/projectswg/lightspeed_frontend/data/SharedDeploymentData.java
@@ -29,7 +29,10 @@ package com.projectswg.lightspeed_frontend.data;
import me.joshlarson.json.JSONObject;
+import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.utilities.TimeUtilities;
+import com.projectswg.lightspeed_frontend.intents.DeploymentDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.DeploymentDataUpdateIntent.DeploymentUpdateType;
public class SharedDeploymentData {
@@ -85,14 +88,25 @@ public class SharedDeploymentData {
public void setBuild(SharedBuildData build) {
this.build = build;
+ onUpdate();
}
public void setStartTime(long startTime) {
this.startTime = startTime;
+ onUpdate();
}
public void setEndTime(long endTime) {
this.endTime = endTime;
+ onUpdate();
+ }
+
+ public void interpretPacket(Packet p) {
+
+ }
+
+ private void onUpdate() {
+ new DeploymentDataUpdateIntent(build.getServer().getName(), build.getId(), id, DeploymentUpdateType.DEPLOYMENT_UPDATED).broadcast();
}
public int hashCode() {
diff --git a/src/com/projectswg/lightspeed_frontend/data/SharedServerData.java b/src/com/projectswg/lightspeed_frontend/data/SharedServerData.java
index 85252a2..3309652 100644
--- a/src/com/projectswg/lightspeed_frontend/data/SharedServerData.java
+++ b/src/com/projectswg/lightspeed_frontend/data/SharedServerData.java
@@ -28,27 +28,42 @@
package com.projectswg.lightspeed_frontend.data;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
+import com.projectswg.common.network.packets.Packet;
+import com.projectswg.common.network.packets.response.ResponseBuildHistoryPacket;
+import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket;
+import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket.DeploymentData;
+import com.projectswg.common.network.packets.response.ResponseDeploymentStatusPacket;
+import com.projectswg.lightspeed_frontend.intents.BuildDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.BuildDataUpdateIntent.BuildUpdateType;
+import com.projectswg.lightspeed_frontend.intents.DeploymentDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.DeploymentDataUpdateIntent.DeploymentUpdateType;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent.ServerUpdateType;
+
public class SharedServerData {
private final String name;
private final TreeMap builds;
- private SharedBuildData lastBuild;
- private SharedDeploymentData lastDeployment;
+ private final TreeMap deployments;
private String directory;
private String jvmArgs;
public SharedServerData(String name) {
this.name = name;
this.builds = new TreeMap<>();
- this.lastBuild = null;
- this.lastDeployment = null;
+ this.deployments = new TreeMap<>();
this.directory = "";
this.jvmArgs = "";
}
+ public String getName() {
+ return name;
+ }
+
public String getDirectory() {
return directory;
}
@@ -57,9 +72,19 @@ public class SharedServerData {
return jvmArgs;
}
- public List getBuildData() {
+ public List getBuilds() {
synchronized (builds) {
- return new ArrayList<>(builds.values());
+ List buildList = new ArrayList<>(builds.values());
+ Collections.reverse(buildList);
+ return buildList;
+ }
+ }
+
+ public List getDeployments() {
+ synchronized (deployments) {
+ List deploymentList = new ArrayList<>(deployments.values());
+ Collections.reverse(deploymentList);
+ return deploymentList;
}
}
@@ -69,43 +94,109 @@ public class SharedServerData {
}
}
+ public SharedDeploymentData getDeploymentData(long id) {
+ synchronized (deployments) {
+ return deployments.get(id);
+ }
+ }
+
public SharedBuildData getLastBuild() {
- return lastBuild;
+ synchronized (builds) {
+ if (builds.isEmpty())
+ return null;
+ return builds.lastEntry().getValue();
+ }
}
public SharedDeploymentData getLastDeployment() {
- return lastDeployment;
+ synchronized (deployments) {
+ if (deployments.isEmpty())
+ return null;
+ return deployments.lastEntry().getValue();
+ }
}
public void addBuild(SharedBuildData build) {
synchronized (builds) {
- builds.put(build.getId(), build);
- if (lastBuild == null || lastBuild.getId() < build.getId())
- lastBuild = build;
- SharedDeploymentData buildLastDeployment = build.getLastDeployment();
- if (lastDeployment == null || (buildLastDeployment != null && buildLastDeployment.getId() > lastDeployment.getId()))
- lastDeployment = buildLastDeployment;
+ if (builds.put(build.getId(), build) == build)
+ return;
+ new BuildDataUpdateIntent(build.getServer().getName(), build.getId(), BuildUpdateType.BUILD_ADDED).broadcast();
+ if (getLastBuild() == build) {
+ new BuildDataUpdateIntent(name, build.getId(), BuildUpdateType.LAST_BUILD_CHANGED).broadcast();
+ }
}
}
- public void clearBuildData() {
+ public void removeBuild(SharedBuildData build) {
synchronized (builds) {
- builds.clear();
- lastBuild = null;
- lastDeployment = null;
+ SharedBuildData lastBuild = getLastBuild();
+ if (builds.remove(build.getId()) == null)
+ return;
+ if (lastBuild == build) {
+ lastBuild = getLastBuild();
+ if (lastBuild == null)
+ new BuildDataUpdateIntent(name, -1, BuildUpdateType.LAST_BUILD_CHANGED).broadcast();
+ else
+ new BuildDataUpdateIntent(name, build.getId(), BuildUpdateType.LAST_BUILD_CHANGED).broadcast();
+ }
+ new BuildDataUpdateIntent(name, build.getId(), BuildUpdateType.BUILD_REMOVED).broadcast();
+ }
+ }
+
+ public void removeBuild(long id) {
+ SharedBuildData build;
+ synchronized (builds) {
+ build = builds.get(id);
+ }
+ if (build != null)
+ removeBuild(build);
+ }
+
+ public void addDeployment(SharedDeploymentData deployment) {
+ synchronized (deployments) {
+ if (deployments.put(deployment.getId(), deployment) == deployment)
+ return;
+ new DeploymentDataUpdateIntent(name, deployment.getBuild().getId(), deployment.getId(), DeploymentUpdateType.DEPLOYMENT_ADDED).broadcast();
+ if (getLastDeployment() == deployment) {
+ long deploymentId = deployment.getId();
+ long buildId = deployment.getBuild().getId();
+ new DeploymentDataUpdateIntent(name, buildId, deploymentId, DeploymentUpdateType.LAST_DEPLOYMENT_CHANGED).broadcast();
+ }
+ }
+ }
+
+ public void removeDeployment(SharedDeploymentData deployment) {
+ synchronized (deployments) {
+ SharedDeploymentData lastDeployment = getLastDeployment();
+ if (deployments.remove(deployment.getId()) == null)
+ return;
+ new DeploymentDataUpdateIntent(name, deployment.getBuild().getId(), deployment.getId(), DeploymentUpdateType.DEPLOYMENT_REMOVED).broadcast();
+ if (lastDeployment == deployment) {
+ lastDeployment = getLastDeployment();
+ if (lastDeployment == null)
+ new DeploymentDataUpdateIntent(name, -1, -1, DeploymentUpdateType.LAST_DEPLOYMENT_CHANGED).broadcast();
+ else
+ new DeploymentDataUpdateIntent(name, lastDeployment.getBuild().getId(), lastDeployment.getId(), DeploymentUpdateType.LAST_DEPLOYMENT_CHANGED).broadcast();
+ }
+ }
+ }
+
+ public void removeDeployment(long id) {
+ synchronized (deployments) {
+ SharedDeploymentData deployment = deployments.get(id);
+ if (deployment != null)
+ removeDeployment(deployment);
}
}
public void setDirectory(String directory) {
this.directory = directory;
+ onUpdate();
}
public void setJvmArguments(String jvmArgs) {
this.jvmArgs = jvmArgs;
- }
-
- public String getName() {
- return name;
+ onUpdate();
}
@Override
@@ -122,15 +213,79 @@ public class SharedServerData {
return ((SharedServerData) o).getName().equals(name);
}
- protected void onDeploymentsChanged() {
+ public void interpretPacket(Packet p) {
+ if (p instanceof ResponseBuildHistoryPacket) {
+ processResponseBuildHistory((ResponseBuildHistoryPacket) p);
+ } else if (p instanceof ResponseDeploymentHistoryPacket) {
+ processResponseDeploymentHistory((ResponseDeploymentHistoryPacket) p);
+ } else if (p instanceof ResponseDeploymentStatusPacket) {
+ processResponseDeploymentStatus((ResponseDeploymentStatusPacket) p);
+ }
synchronized (builds) {
- lastDeployment = null;
for (SharedBuildData build : builds.values()) {
- SharedDeploymentData buildLastDeployment = build.getLastDeployment();
- if (lastDeployment == null || (buildLastDeployment != null && buildLastDeployment.getId() > lastDeployment.getId()))
- lastDeployment = buildLastDeployment;
+ build.interpretPacket(p);
+ }
+ }
+ synchronized (deployments) {
+ for (SharedDeploymentData deployment : deployments.values()) {
+ deployment.interpretPacket(p);
}
}
}
+ private void processResponseBuildHistory(ResponseBuildHistoryPacket p) {
+ if (p.getServerId() == null || !p.getServerId().equals(name))
+ return;
+ synchronized (builds) {
+ List removeList = new ArrayList<>(builds.values());
+ for (SharedBuildData build : p.getBuildHistory()) {
+ if (builds.containsKey(build.getId())) {
+ removeList.remove(builds.get(build.getId()));
+ } else {
+ build.setServer(this);
+ addBuild(build);
+ }
+ }
+ for (SharedBuildData rm : removeList) {
+ removeBuild(rm);
+ }
+ }
+ }
+
+ private void processResponseDeploymentHistory(ResponseDeploymentHistoryPacket p) {
+ synchronized (deployments) {
+ List removeList = new ArrayList<>(deployments.values());
+ for (DeploymentData d : p.getDeploymentHistory()) {
+ if (!d.getServerId().equals(name))
+ continue;
+ SharedDeploymentData deployment = d.getDeployment();
+ synchronized (builds) {
+ deployment.setBuild(builds.get(d.getBuildId()));
+ }
+ if (deployments.containsKey(deployment.getId())) {
+ removeList.remove(deployment);
+ } else {
+ addDeployment(deployment);
+ }
+ }
+ for (SharedDeploymentData rm : removeList) {
+ removeDeployment(rm);
+ }
+ }
+ }
+
+ private void processResponseDeploymentStatus(ResponseDeploymentStatusPacket p) {
+ for (SharedDeploymentData deployment : p.getDeployments()) {
+ if (!deployment.getServer().getName().equals(name))
+ return;
+ if (!deployments.containsKey(deployment.getId())) {
+ addDeployment(deployment);
+ }
+ }
+ }
+
+ private void onUpdate() {
+ new ServerDataUpdateIntent(name, ServerUpdateType.SERVER_UPDATED).broadcast();
+ }
+
}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/BuildDataPane.java b/src/com/projectswg/lightspeed_frontend/gui/BuildDataPane.java
deleted file mode 100644
index 7bd28b0..0000000
--- a/src/com/projectswg/lightspeed_frontend/gui/BuildDataPane.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/***********************************************************************************
-* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
-* *
-* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
-* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
-* Our goal is to create an emulator which will provide a server for players to *
-* continue playing a game similar to the one they used to play. We are basing *
-* it on the final publish of the game prior to end-game events. *
-* *
-* This file is part of Holocore. *
-* *
-* -------------------------------------------------------------------------------- *
-* *
-* Holocore is free software: you can redistribute it and/or modify *
-* it under the terms of the GNU Affero General Public License as *
-* published by the Free Software Foundation, either version 3 of the *
-* License, or (at your option) any later version. *
-* *
-* Holocore is distributed in the hope that it will be useful, *
-* but WITHOUT ANY WARRANTY; without even the implied warranty of *
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
-* GNU Affero General Public License for more details. *
-* *
-* You should have received a copy of the GNU Affero General Public License *
-* along with Holocore. If not, see . *
-* *
-***********************************************************************************/
-package com.projectswg.lightspeed_frontend.gui;
-
-import java.net.URL;
-import java.util.ResourceBundle;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javafx.beans.binding.Bindings;
-import javafx.fxml.FXML;
-import javafx.fxml.Initializable;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.Pane;
-import javafx.scene.text.Text;
-
-import com.projectswg.common.data.TestDetails;
-import com.projectswg.common.utilities.TimeUtilities;
-import com.projectswg.lightspeed_frontend.data.SharedBuildData;
-import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
-import com.projectswg.lightspeed_frontend.gui.table.cell.CellMouseClickCallback;
-import com.projectswg.lightspeed_frontend.gui.table.cell.TableCellString;
-import com.projectswg.lightspeed_frontend.gui.table.column.TableColumnString;
-import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
-
-public class BuildDataPane extends GridPane implements Initializable {
-
- private final AtomicBoolean initialized;
- private final Pane root;
- private SharedBuildData build;
-
- @FXML
- private Text idText;
- @FXML
- private Text serverText;
- @FXML
- private Text timeText;
- @FXML
- private Text compileTimeText;
- @FXML
- private Text statusText;
- @FXML
- private Text modeText;
- @FXML
- private Text testText;
- @FXML
- private Text logText;
- @FXML
- private TableView deploymentsTable;
-
- public BuildDataPane(Pane root, SharedBuildData build) {
- this.initialized = new AtomicBoolean(false);
- this.root = root;
- setBuildData(build);
- FrontendFXMLLoader.load(this, "fxml/BuildDataPane.fxml");
- }
-
- public void setBuildData(SharedBuildData build) {
- this.build = build;
- updateUI();
- }
-
- @Override
- public void initialize(URL location, ResourceBundle resources) {
- initialized.set(true);
- double tenPercent = 75;
- deploymentsTable.prefHeightProperty().bind(Bindings.size(deploymentsTable.getItems()).multiply(deploymentsTable.getFixedCellSize()).add(50));
- addServerTableColumn("ID", tenPercent,
- new BuildTableIdColumn(),
- (data, me) -> root.getChildren().add(new InternalWindow("Deployment Information", new DeploymentDataPane(root, data))));
- addServerTableColumn("Start Time", 4.5*tenPercent,
- new BuildTableTimeColumn(),
- null);
- addServerTableColumn("Status", 4.5*tenPercent,
- new BuildTableStatusColumn(),
- null);
- updateUI();
- }
-
- private void addServerTableColumn(String name, double width, TableColumnString valueFactory, CellMouseClickCallback callback) {
- TableColumn column = new TableColumn<>(name);
- column.setCellValueFactory(valueFactory);
- column.setPrefWidth(width);
- column.setCellFactory((param) -> new TableCellString(callback));
- deploymentsTable.getColumns().add(column);
- }
-
- private void updateUI() {
- SharedBuildData build = this.build; // Concurrency thing, move along
- if (!initialized.get() || build == null)
- return;
- idText.setText(Long.toString(build.getId()));
- serverText.setText(build.getServer().getName());
- timeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(build.getTime())));
- int minutes = (int) (build.getCompileTime() / 60E3);
- int seconds = (int) (build.getCompileTime()/1E3 - minutes*60);
- int milliseconds = ((int) build.getCompileTime()) % 1000;
- compileTimeText.setText(String.format("%02d:%02d.%03d", minutes, seconds, milliseconds));
- if (build.isCancelled())
- statusText.setText("Cancelled");
- else if (build.isBuildSuccess() && !build.isTestSuccess())
- statusText.setText("Tests Failed");
- else if (!build.isBuildSuccess())
- statusText.setText("Build Failed");
- else
- statusText.setText("Success");
- modeText.setText(build.isOffline() ? "Offline" : "Online");
- TestDetails test = build.getTestDetails();
- testText.setText(String.format("%d of %d passed", test.getTotal()-test.getFailures(), test.getTotal()));
- String log = (build.getBuildString() == null) ? "" : build.getBuildString();
- if (build.getTestString() != null)
- log += "\n"+build.getTestString();
- logText.setText(log);
- deploymentsTable.getItems().clear();
- deploymentsTable.getItems().addAll(build.getDeployments());
- }
-
- private static class BuildTableIdColumn extends TableColumnString {
- protected String createText(SharedDeploymentData data) {
- return Long.toString(data.getId());
- }
- }
-
- private static class BuildTableTimeColumn extends TableColumnString {
- protected String createText(SharedDeploymentData data) {
- return TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(data.getStartTime()));
- }
- }
-
- private static class BuildTableStatusColumn extends TableColumnString {
- protected String createText(SharedDeploymentData data) {
- String prefix;
- double deploymentTime;
- if (data.getEndTime() == 0) {
- deploymentTime = (TimeUtilities.getTime()-data.getStartTime())/1E3;
- prefix = "Deploying for";
- } else {
- deploymentTime = (data.getEndTime()-data.getStartTime())/1E3;
- prefix = "Deployed for";
- }
- int minutes = (int) (deploymentTime / 60E3);
- int seconds = (int) (deploymentTime/1E3 - minutes*60);
- int milliseconds = ((int) deploymentTime) % 1000;
- return String.format("%s %02d:%02d.%03d", prefix, minutes, seconds, milliseconds);
- }
- }
-
-}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/LightspeedPrimaryView.java b/src/com/projectswg/lightspeed_frontend/gui/LightspeedPrimaryView.java
index 0459257..fc452a7 100644
--- a/src/com/projectswg/lightspeed_frontend/gui/LightspeedPrimaryView.java
+++ b/src/com/projectswg/lightspeed_frontend/gui/LightspeedPrimaryView.java
@@ -27,258 +27,131 @@
***********************************************************************************/
package com.projectswg.lightspeed_frontend.gui;
-import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URL;
-import java.net.UnknownHostException;
-import java.text.DateFormat;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
-import com.projectswg.common.network.packets.post.PostBuildPacket;
+import com.projectswg.common.control.Assert;
+import com.projectswg.common.control.IntentManager;
import com.projectswg.common.utilities.ThreadUtilities;
-import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed_frontend.Frontend;
-import com.projectswg.lightspeed_frontend.FrontendData.FrontendDataType;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
-import com.projectswg.lightspeed_frontend.gui.table.column.TableColumnString;
-import com.projectswg.lightspeed_frontend.gui.table.cell.CellMouseClickCallback;
-import com.projectswg.lightspeed_frontend.gui.table.cell.TableCellString;
+import com.projectswg.lightspeed_frontend.gui.primary_tabs.BuildTab;
+import com.projectswg.lightspeed_frontend.gui.primary_tabs.DeploymentTab;
+import com.projectswg.lightspeed_frontend.gui.primary_tabs.GeneralTab;
+import com.projectswg.lightspeed_frontend.intents.ConnectionStateUpdateIntent;
import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
+import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
-import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.control.TextField;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
-import javafx.scene.input.MouseButton;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
+import javafx.scene.layout.VBox;
-public class LightspeedPrimaryView extends StackPane implements Initializable {
+public class LightspeedPrimaryView extends VBox implements Initializable {
private final ExecutorService executor;
private final Frontend frontend;
- private final Image disconnectedImage;
- private final Image connectedImage;
-
- private ContextMenu secondaryMenu;
+ private final AtomicBoolean initialized;
@FXML
- private TextField lightspeedAddress;
+ private GeneralTab generalTab;
@FXML
- private TextField lightspeedPort;
+ private BuildTab buildTab;
@FXML
- private Button connectLightspeed;
+ private DeploymentTab deploymentTab;
@FXML
- private ImageView lightspeedStatus;
+ private MenuButton commonServerStatus;
+ @FXML
+ private MenuButton commonBuildStatus;
+ @FXML
+ private MenuButton commonDeploymentStatus;
- @FXML
- private Button createServer;
-
- @FXML
- private TableView serverTable;
+ private SharedServerData server;
+ private InetSocketAddress address;
public LightspeedPrimaryView(Frontend frontend) {
+ if (frontend == null)
+ throw new NullPointerException("Frontend cannot be null");
this.executor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory("lightspeed-tab"));
this.frontend = frontend;
- this.disconnectedImage = FrontendFXMLLoader.createImage("res/disconnected.png");
- this.connectedImage = FrontendFXMLLoader.createImage("res/connected.png");
- this.secondaryMenu = null;
+ this.initialized = new AtomicBoolean(false);
+ this.server = null;
+ this.address = null;
+ IntentManager.getInstance().registerForIntent(ConnectionStateUpdateIntent.TYPE, (i) -> update());
FrontendFXMLLoader.load(this, "fxml/PrimaryView.fxml");
- frontend.getData().addDataUpdateCallback((dataType) -> updateData(dataType));
- frontend.getData().addConnectionCallback((connected) -> updateConnectionState());
+ }
+
+ public void setConnectAddress(InetSocketAddress address) {
+ this.address = address;
}
public void close() {
+ Assert.test(!executor.isShutdown());
executor.shutdownNow();
}
@Override
public void initialize(URL location, ResourceBundle resources) {
- setupServerTable();
- connectLightspeed.setOnAction((ae) -> attemptConnect());
- createServer.setOnAction((ae) -> createServer());
- updateConnectionState();
- updateServerList();
- connectLightspeed.fire();
- addEventHandler(MouseEvent.MOUSE_CLICKED, (me) -> onDefaultClick());
- getChildrenUnmodifiable().forEach((child) -> child.addEventHandler(MouseEvent.MOUSE_CLICKED, (me) -> onDefaultClick()));;
+ initialized.set(true);
+ update();
+ generalTab.setFrontend(frontend);
+ buildTab.setFrontend(frontend);
+ deploymentTab.setFrontend(frontend);
+ generalTab.setSelectedServerChangedCallback((server) -> {
+ this.server = server;
+ buildTab.setServer(server);
+ deploymentTab.setServer(server);
+ update();
+ });
+ buildTab.setSelectedBuildChangedCallback((build) -> {
+ deploymentTab.setBuild(build);
+ });
}
- private void setupServerTable() {
- addServerTableColumn("Server", 95,
- new ServerTableIdColumn(),
- (data, me) -> onServerClicked(data, me));
- addServerTableColumn("Build", 350,
- new ServerTableBuildColumn(),
- (data, me) -> onBuildClicked(data, me));
- addServerTableColumn("Deployment", 350,
- new ServerTableDeploymentColumn(),
- (data, me) -> onDeploymentClicked(data, me));
- }
-
- private void addServerTableColumn(String name, double width, TableColumnString valueFactory, CellMouseClickCallback callback) {
- TableColumn column = new TableColumn<>(name);
- column.setCellValueFactory(valueFactory);
- column.setPrefWidth(width);
- column.setCellFactory((param) -> new TableCellString(callback));
- serverTable.getColumns().add(column);
- }
-
- private void onServerClicked(SharedServerData data, MouseEvent event) {
- if (data == null) {
- onDefaultClick();
- return;
- }
- if (event.getButton() == MouseButton.SECONDARY) {
- setupServerRightClick(data, event);
- }
- }
-
- private void onBuildClicked(SharedServerData data, MouseEvent event) {
- if (data == null) {
- onDefaultClick();
- return;
- }
- switch (event.getButton()) {
- case PRIMARY:
- getChildren().add(new InternalWindow("Build Information", new BuildDataPane(this, data.getLastBuild())));
- break;
- case SECONDARY:
- setupServerRightClick(data, event);
- break;
- default:
- break;
- }
- }
-
- private void onDeploymentClicked(SharedServerData data, MouseEvent event) {
- if (data == null) {
- onDefaultClick();
- return;
- }
- switch (event.getButton()) {
- case PRIMARY:
- getChildren().add(new InternalWindow("Deployment Information", new DeploymentDataPane(this, data.getLastDeployment())));
- break;
- case SECONDARY:
- setupServerRightClick(data, event);
- break;
- default:
- break;
- }
- }
-
- private void setupServerRightClick(SharedServerData data, MouseEvent event) {
- MenuItem runNew = new MenuItem("Run New Build");
- runNew.setOnAction((ae) -> frontend.send(PostBuildPacket.create(data.getName())));
- showSecondaryMenu(event.getScreenX(), event.getScreenY(), runNew);
- }
-
- private void onDefaultClick() {
- if (secondaryMenu == null)
- return;
- secondaryMenu.hide();
- secondaryMenu = null;
- }
-
- private void showSecondaryMenu(double x, double y, MenuItem ... items) {
- if (secondaryMenu != null)
- secondaryMenu.hide();
- secondaryMenu = new ContextMenu(items);
- secondaryMenu.show(this, x, y);
- }
-
- private void updateConnectionState() {
- if (frontend.isConnected()) {
- lightspeedStatus.setImage(connectedImage);
- requestData();
- } else
- lightspeedStatus.setImage(disconnectedImage);
- }
-
- private void updateData(FrontendDataType dataType) {
- switch (dataType) {
- case SERVER_LIST:
- updateServerList();
- break;
- default:
- break;
- }
- }
-
- private void updateServerList() {
- synchronized (serverTable) {
- serverTable.getItems().clear();
- serverTable.getItems().addAll(frontend.getData().getServers());
- }
- }
-
- private void requestData() {
- frontend.requestCompleteLoad();
- }
-
- private void attemptConnect() {
- String ipRaw = lightspeedAddress.getText();
- String portRaw = lightspeedPort.getText();
- executor.execute(() -> {
- try {
- frontend.connect(new InetSocketAddress(InetAddress.getByName(ipRaw), Integer.parseInt(portRaw)));
- } catch (NumberFormatException | UnknownHostException e) {
- System.err.printf("Failed to connect to: %s:%s. Invalid address/port%n", ipRaw, portRaw);
+ private void update() {
+ Platform.runLater(() -> {
+ setServerStatusText(frontend.isConnected());
+ setBuildStatusText(server == null ? null : server.getLastBuild());
+ setDeploymentStatusText(server == null ? null : server.getLastDeployment());
+ if (frontend.isConnected()) {
+ MenuItem disconnect = new MenuItem("Disconnect");
+ disconnect.setOnAction((event) -> frontend.disconnect());
+ commonServerStatus.getItems().setAll(disconnect);
+ } else {
+ if (address != null) {
+ MenuItem connect = new MenuItem("Connect");
+ connect.setOnAction((event) -> frontend.connect(address));
+ commonServerStatus.getItems().setAll(connect);
+ } else {
+ commonServerStatus.getItems().clear();
+ }
}
});
}
- private void createServer() {
- Stage popup = new Stage();
- popup.setTitle("Create Server");
- popup.setScene(new Scene(new CreateServerPane(popup, frontend), 300, 200));
- popup.setResizable(false);
- popup.centerOnScreen();
- popup.show();
+ private void setServerStatusText(boolean connected) {
+ commonServerStatus.setText(String.format("Server: %s", connected ? "Connected" : "Disconnected"));
}
- private static class ServerTableIdColumn extends TableColumnString {
- protected String createText(SharedServerData server) {
- return server.getName();
- }
+ private void setBuildStatusText(SharedBuildData build) {
+ String str = "N/A";
+ if (build != null)
+ str = (build.isBuildSuccess() && build.isTestSuccess()) ? "Success" : "Failure";
+ commonBuildStatus.setText(String.format("Build: %s", str));
}
- private static class ServerTableBuildColumn extends TableColumnString {
- protected String createText(SharedServerData server) {
- SharedBuildData lastBuild = server.getLastBuild();
- if (lastBuild == null)
- return "Not Built Yet";
- DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
- return String.format("Build #%d at %s", lastBuild.getId(), df.format(TimeUtilities.convertUtcToLocal(lastBuild.getTime())));
- }
- }
-
- private static class ServerTableDeploymentColumn extends TableColumnString {
- protected String createText(SharedServerData server) {
- SharedDeploymentData lastDeployment = server.getLastDeployment();
- if (lastDeployment == null)
- return "Not Deployed Yet";
- if (lastDeployment.getEndTime() == 0) {
- long minutes = (long) ((TimeUtilities.getTime()-lastDeployment.getStartTime())/60E3 + 0.5);
- return "Deployment #" + lastDeployment.getId() + " deploying for " + minutes + " mins";
- }
- DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
- String dfStr = df.format(TimeUtilities.convertUtcToLocal(lastDeployment.getEndTime()));
- return "Deployment #" + lastDeployment.getId() + " ended at " + dfStr;
- }
+ private void setDeploymentStatusText(SharedDeploymentData deployment) {
+ String str = "N/A";
+ if (deployment != null)
+ str = deployment.getEndTime() == -1 ? "Running" : "Stopped";
+ commonDeploymentStatus.setText(String.format("Deployment: %s", str));
}
}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/BuildTab.java b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/BuildTab.java
new file mode 100644
index 0000000..e2baa1c
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/BuildTab.java
@@ -0,0 +1,246 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.gui.primary_tabs;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import com.projectswg.common.data.TestDetails;
+import com.projectswg.common.info.Log;
+import com.projectswg.common.utilities.TimeUtilities;
+import com.projectswg.lightspeed_frontend.Frontend;
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+
+public class BuildTab extends GridPane implements Initializable {
+
+ @FXML
+ private ComboBox buildComboBox;
+ @FXML
+ private Label serverNameText;
+ @FXML
+ private Label buildIdText;
+ @FXML
+ private Label statusText;
+ @FXML
+ private Label timeText;
+ @FXML
+ private Label compileTimeText;
+ @FXML
+ private Label modeText;
+ @FXML
+ private Label testText;
+
+ private SelectedBuildChangedCallback callback;
+ private SharedServerData selectedServerData;
+ private SharedBuildData selectedBuildData;
+
+ public BuildTab() {
+ callback = null;
+ selectedServerData = null;
+ selectedBuildData = null;
+ FrontendFXMLLoader.load(this, "fxml/primary_tabs/Build.fxml");
+ }
+
+ public void setFrontend(Frontend frontend) {
+
+ }
+
+ public void setSelectedBuildChangedCallback(SelectedBuildChangedCallback callback) {
+ this.callback = callback;
+ }
+
+ public void setServer(SharedServerData server) {
+ if (this.selectedServerData == server)
+ return;
+ this.selectedServerData = server;
+ this.selectedBuildData = null;
+ updateBuildList();
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ serverNameText.getStyleClass().setAll("white-label");
+ buildIdText.getStyleClass().setAll("white-label");
+ statusText.getStyleClass().setAll("white-label");
+ timeText.getStyleClass().setAll("white-label");
+ compileTimeText.getStyleClass().setAll("white-label");
+ modeText.getStyleClass().setAll("white-label");
+ testText.getStyleClass().setAll("white-label");
+ buildComboBox.selectionModelProperty().addListener((v, prev, next) -> {
+ if (selectedServerData == null)
+ return;
+ for (SharedBuildData build : selectedServerData.getBuilds()) {
+ String val = v.getValue().getSelectedItem();
+ if (!val.isEmpty() && build.getId() == Long.parseLong(val)) {
+ selectBuild(build);
+ return;
+ }
+ }
+ selectBuild(null);
+ });
+ updateUi();
+ }
+
+ private void selectBuild(SharedBuildData build) {
+ Log.d(this, "Selected: %s", build);
+ if (build != null)
+ buildComboBox.getSelectionModel().select(Long.toString(build.getId()));
+ else
+ buildComboBox.getSelectionModel().selectFirst();
+ selectedBuildData = build;
+ if (callback != null)
+ callback.onBuildChanged(build);
+ updateUi();
+ }
+
+ private void updateUi() {
+ setServerName();
+ setBuildId();
+ setStatus();
+ setTime();
+ setCompileTime();
+ setMode();
+ setTests();
+ }
+
+ private void updateBuildList() {
+ List buildList = selectedServerData.getBuilds();
+ String [] builds = new String[buildList.size()];
+ Arrays.sort(builds, (a, b) -> b.compareTo(a));
+ for (int i = 0; i < buildList.size(); i++) {
+ builds[i] = Long.toString(buildList.get(i).getId());
+ }
+ buildComboBox.setItems(FXCollections.observableArrayList(builds));
+ buildComboBox.getItems().add(0, "");
+ if (selectedBuildData != null) {
+ selectBuild(selectedBuildData);
+ }
+ }
+
+ private void setServerName() {
+ if (selectedBuildData == null) {
+ serverNameText.setText("N/A");
+ } else {
+ serverNameText.setText(selectedBuildData.getServer().getName());
+ }
+ }
+
+ private void setBuildId() {
+ if (selectedBuildData == null) {
+ buildIdText.setText("N/A");
+ } else {
+ buildIdText.setText(Long.toString(selectedBuildData.getId()));
+ }
+ }
+
+ private void setStatus() {
+ if (selectedBuildData == null) {
+ statusText.getStyleClass().setAll("white-label");
+ statusText.setText("N/A");
+ } else {
+ boolean success = selectedBuildData.isBuildSuccess() && selectedBuildData.isTestSuccess();
+ statusText.getStyleClass().setAll(success ? "green-label" : "red-label");
+ statusText.setText(success ? "Success" : "Failure");
+ }
+ }
+
+ private void setTime() {
+ if (selectedBuildData == null) {
+ timeText.setText("N/A");
+ } else {
+ timeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedBuildData.getTime())));
+ }
+ }
+
+ private void setCompileTime() {
+ if (selectedBuildData == null) {
+ compileTimeText.setText("N/A");
+ } else {
+ compileTimeText.setText(getTime((long) (selectedBuildData.getCompileTime()*1E3)));
+ }
+ }
+
+ private void setMode() {
+ if (selectedBuildData == null) {
+ modeText.setText("N/A");
+ } else {
+ modeText.setText(selectedBuildData.isOffline() ? "Offline" : "Online");
+ }
+ }
+
+ private void setTests() {
+ if (selectedBuildData == null) {
+ testText.setText("N/A");
+ } else {
+ TestDetails details = selectedBuildData.getTestDetails();
+ int total = details.getTotal();
+ int passed = total-details.getFailures();
+ testText.setText(String.format("%d of %d passed", passed, total));
+ }
+ }
+
+ private String getTime(long time) {
+ time /= 1000;
+ int seconds = (int) (time % 60);
+ time /= 60;
+ int minutes = (int) (time % 60);
+ time /= 60;
+ int hours = (int) (time % 24);
+ time /= 24;
+ String text = "";
+ text += getPlurality("Day", (int) time);
+ text += getPlurality("Hour", hours);
+ text += getPlurality("Minute", minutes);
+ text += getPlurality("Second", seconds);
+ return text;
+ }
+
+ private String getPlurality(String base, int amount) {
+ if (amount > 1)
+ return amount + " " + base + "s ";
+ if (amount == 1)
+ return amount + " " + base + " ";
+ return "";
+ }
+
+ public interface SelectedBuildChangedCallback {
+ void onBuildChanged(SharedBuildData build);
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/DeploymentTab.java b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/DeploymentTab.java
new file mode 100644
index 0000000..e465570
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/DeploymentTab.java
@@ -0,0 +1,244 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.gui.primary_tabs;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import com.projectswg.common.utilities.TimeUtilities;
+import com.projectswg.lightspeed_frontend.Frontend;
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+
+public class DeploymentTab extends GridPane implements Initializable {
+
+ @FXML
+ private ComboBox deploymentComboBox;
+ @FXML
+ private Label serverNameText;
+ @FXML
+ private Label buildIdText;
+ @FXML
+ private Label deploymentIdText;
+ @FXML
+ private Label statusText;
+ @FXML
+ private Label startTimeText;
+ @FXML
+ private Label uptimeText;
+ @FXML
+ private Label logText;
+
+ private SharedServerData selectedServerData;
+ private SharedBuildData selectedBuildData;
+ private SharedDeploymentData selectedDeploymentData;
+
+ public DeploymentTab() {
+ FrontendFXMLLoader.load(this, "fxml/primary_tabs/Deployment.fxml");
+ }
+
+ public void setServer(SharedServerData server) {
+ if (this.selectedServerData == server)
+ return;
+ this.selectedServerData = server;
+ this.selectedBuildData = null;
+ updateDeploymentList();
+ }
+
+ public void setBuild(SharedBuildData build) {
+ if (this.selectedBuildData == build)
+ return;
+ if (build == null)
+ this.selectedServerData = null;
+ else
+ this.selectedServerData = build.getServer();
+ this.selectedBuildData = build;
+ updateDeploymentList();
+ }
+
+ public void setFrontend(Frontend frontend) {
+
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ serverNameText.getStyleClass().setAll("white-label");
+ buildIdText.getStyleClass().setAll("white-label");
+ deploymentIdText.getStyleClass().setAll("white-label");
+ statusText.getStyleClass().setAll("white-label");
+ startTimeText.getStyleClass().setAll("white-label");
+ uptimeText.getStyleClass().setAll("white-label");
+ updateUi();
+ }
+
+ private void updateUi() {
+ setServerName();
+ setBuildId();
+ setDeploymentId();
+ setStatus();
+ setStartTime();
+ setUptime();
+ setLog();
+ }
+
+ private void selectDeployment(SharedDeploymentData deployment) {
+ if (deployment != null)
+ deploymentComboBox.getSelectionModel().select(Long.toString(deployment.getId()));
+ else
+ deploymentComboBox.getSelectionModel().selectFirst();
+ selectedDeploymentData = deployment;
+ updateUi();
+ }
+
+ private void updateDeploymentList() {
+ List deploymentList = new ArrayList<>();
+ if (selectedServerData != null) {
+ deploymentList.addAll(selectedServerData.getDeployments());
+ }
+ String [] deployments = new String[deploymentList.size()];
+ Arrays.sort(deployments, (a, b) -> b.compareTo(a));
+ for (int i = 0; i < deploymentList.size(); i++) {
+ deployments[i] = Long.toString(deploymentList.get(i).getId());
+ }
+ deploymentComboBox.setItems(FXCollections.observableArrayList(deployments));
+ deploymentComboBox.getItems().add(0, "");
+ if (selectedDeploymentData != null) {
+ selectDeployment(selectedDeploymentData);
+ }
+ }
+
+ private void setServerName() {
+ if (selectedServerData == null) {
+ serverNameText.setText("N/A");
+ } else {
+ serverNameText.setText(selectedServerData.getName());
+ }
+ }
+
+ private void setBuildId() {
+ if (selectedBuildData == null) {
+ buildIdText.setText("N/A");
+ } else {
+ buildIdText.setText(Long.toString(selectedBuildData.getId()));
+ }
+ }
+
+ private void setDeploymentId() {
+ if (selectedDeploymentData == null) {
+ deploymentIdText.setText("N/A");
+ } else {
+ deploymentIdText.setText(Long.toString(selectedDeploymentData.getId()));
+ }
+ }
+
+ private void setStatus() {
+ if (selectedDeploymentData == null) {
+ statusText.getStyleClass().setAll("white-label");
+ statusText.setText("N/A");
+ } else {
+ if (selectedDeploymentData.getEndTime() == -1) {
+ statusText.getStyleClass().setAll("green-label");
+ statusText.setText("Running");
+ } else {
+ statusText.getStyleClass().setAll("white-label");
+ statusText.setText("Stopped at " + TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeploymentData.getEndTime())));
+ }
+ }
+ }
+
+ private void setStartTime() {
+ if (selectedDeploymentData == null) {
+ startTimeText.setText("N/A");
+ } else {
+ startTimeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeploymentData.getStartTime())));
+ }
+ }
+
+ private void setUptime() {
+ if (selectedDeploymentData == null) {
+ uptimeText.setText("N/A");
+ } else {
+ long start = selectedDeploymentData.getStartTime();
+ long end = selectedDeploymentData.getEndTime();
+ if (end == -1) {
+ uptimeText.setText(getTime(TimeUtilities.getTime()-start));
+ } else {
+ uptimeText.setText(getTime(end-start));
+ }
+ }
+ }
+
+ private void setLog() {
+ if (selectedDeploymentData == null) {
+ logText.setText(" ");
+ } else {
+ logText.setText(" ");
+ }
+ }
+
+ private String getTime(long time) {
+ time /= 1000;
+ int seconds = (int) (time % 60);
+ time /= 60;
+ int minutes = (int) (time % 60);
+ time /= 60;
+ int hours = (int) (time % 24);
+ time /= 24;
+ String text = "";
+ text += getPlurality("Day", (int) time);
+ text += getPlurality("Hour", hours);
+ text += getPlurality("Minute", minutes);
+ text += getPlurality("Second", seconds);
+ return text;
+ }
+
+ private String getPlurality(String base, int amount) {
+ if (amount > 1)
+ return amount + " " + base + "s ";
+ if (amount == 1)
+ return amount + " " + base + " ";
+ return "";
+ }
+
+ public interface SelectedDeploymentChangedCallback {
+ void onDeploymentChanged(SharedDeploymentData deployment);
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/GeneralTab.java b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/GeneralTab.java
new file mode 100644
index 0000000..c70b76b
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/gui/primary_tabs/GeneralTab.java
@@ -0,0 +1,236 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.gui.primary_tabs;
+
+import java.net.URL;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import com.projectswg.common.control.IntentManager;
+import com.projectswg.common.utilities.TimeUtilities;
+import com.projectswg.lightspeed_frontend.Frontend;
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent;
+import com.projectswg.lightspeed_frontend.intents.ServerDataUpdateIntent.ServerUpdateType;
+import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+
+public class GeneralTab extends GridPane implements Initializable {
+
+ @FXML
+ private ComboBox serverComboBox;
+ @FXML
+ private Label serverNameText;
+ @FXML
+ private Label buildStatusText;
+ @FXML
+ private Label deploymentStatusText;
+ @FXML
+ private Label populationText;
+ @FXML
+ private Label uptimeText;
+
+ private Frontend frontend;
+ private SharedServerData selectedServerData;
+ private SelectedServerChangedCallback callback;
+
+ public GeneralTab() {
+ frontend = null;
+ selectedServerData = null;
+ callback = null;
+ FrontendFXMLLoader.load(this, "fxml/primary_tabs/General.fxml");
+ IntentManager.getInstance().registerForIntent(ServerDataUpdateIntent.TYPE, (i) -> onIntent((ServerDataUpdateIntent) i));
+ }
+
+ public void setFrontend(Frontend frontend) {
+ this.frontend = frontend;
+ }
+
+ public void setSelectedServerChangedCallback(SelectedServerChangedCallback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ serverNameText.getStyleClass().setAll("white-label");
+ buildStatusText.getStyleClass().setAll("white-label");
+ deploymentStatusText.getStyleClass().setAll("white-label");
+ populationText.getStyleClass().setAll("white-label");
+ uptimeText.getStyleClass().setAll("white-label");
+ serverComboBox.selectionModelProperty().addListener((v, prev, next) -> {
+ for (SharedServerData server : frontend.getData().getServers()) {
+ if (server.getName().equals(v.getValue().getSelectedItem())) {
+ selectedServerData = server;
+ if (callback != null)
+ callback.onServerChanged(server);
+ break;
+ }
+ }
+ updateUi();
+ });
+ updateUi();
+ }
+
+ private void onIntent(ServerDataUpdateIntent i) {
+ if (selectedServerData == null) {
+ selectedServerData = frontend.getData().getPrimaryServer();
+ } else {
+ if (i.getUpdateType() == ServerUpdateType.SERVER_REMOVED && i.getName().equals(selectedServerData.getName()))
+ selectedServerData = frontend.getData().getPrimaryServer();
+ }
+ if (callback != null)
+ callback.onServerChanged(selectedServerData);
+ updateUi();
+ }
+
+ private void updateUi() {
+ updateServerList();
+ if (selectedServerData == null) {
+ setServerName("N/A");
+ setEmptyBuildStatus();
+ setEmptyDeploymentStatus();
+ setEmptyPopulationText();
+ setEmptyUptimeText();
+ } else {
+ SharedBuildData lastBuild = selectedServerData.getLastBuild();
+ SharedDeploymentData lastDeployment = selectedServerData.getLastDeployment();
+ setServerName(selectedServerData == null ? "N/A" : selectedServerData.getName());
+ if (lastBuild == null)
+ setEmptyBuildStatus();
+ else
+ setBuildStatus(lastBuild.isBuildSuccess() && lastBuild.isTestSuccess());
+ if (lastDeployment == null) {
+ setEmptyDeploymentStatus();
+ } else {
+ if (lastDeployment.getEndTime() != -1) {
+ setDeploymentStatus(false);
+ setEmptyPopulationText();
+ setUptimeText(lastDeployment.getEndTime()-lastDeployment.getStartTime());
+ } else {
+ setDeploymentStatus(true);
+ setPopulationText(0);
+ setUptimeText(TimeUtilities.getTime()-lastDeployment.getStartTime());
+ }
+ }
+ }
+ }
+
+ private void selectServer(SharedServerData server) {
+ this.selectedServerData = server;
+ serverComboBox.getSelectionModel().select(server.getName());
+ if (callback != null)
+ callback.onServerChanged(server);
+ }
+
+ private void updateServerList() {
+ if (frontend == null)
+ return;
+ List serverList = frontend.getData().getServers();
+ String [] servers = new String[serverList.size()];
+ for (int i = 0; i < serverList.size(); i++) {
+ servers[i] = serverList.get(i).getName();
+ }
+ serverComboBox.setItems(FXCollections.observableArrayList(servers));
+ if (selectedServerData != null) {
+ selectServer(selectedServerData);
+ }
+ }
+
+ private void setServerName(String name) {
+ serverNameText.setText(name);
+ }
+
+ private void setEmptyBuildStatus() {
+ buildStatusText.getStyleClass().setAll("white-label");
+ buildStatusText.setText("N/A");
+ }
+
+ private void setBuildStatus(boolean success) {
+ buildStatusText.getStyleClass().setAll(success ? "green-label" : "red-label");
+ buildStatusText.setText(success ? "Success" : "Failed");
+ }
+
+ private void setEmptyDeploymentStatus() {
+ deploymentStatusText.getStyleClass().setAll("white-label");
+ deploymentStatusText.setText("N/A");
+ }
+
+ private void setDeploymentStatus(boolean running) {
+ deploymentStatusText.getStyleClass().setAll(running ? "green-label" : "white-label");
+ deploymentStatusText.setText(running ? "Running" : "Idle");
+ }
+
+ private void setEmptyPopulationText() {
+ populationText.setText("N/A");
+ }
+
+ private void setPopulationText(int count) {
+ populationText.setText(String.format("%d Characters Online", count));
+ }
+
+ private void setEmptyUptimeText() {
+ uptimeText.setText("N/A");
+ }
+
+ private void setUptimeText(long uptime) {
+ uptime /= 1000;
+ int seconds = (int) (uptime % 60);
+ uptime /= 60;
+ int minutes = (int) (uptime % 60);
+ uptime /= 60;
+ int hours = (int) (uptime % 24);
+ uptime /= 24;
+ String text = "";
+ text += getPlurality("Day", (int) uptime);
+ text += getPlurality("Hour", hours);
+ text += getPlurality("Minute", minutes);
+ text += getPlurality("Second", seconds);
+ uptimeText.setText(text);
+ }
+
+ private String getPlurality(String base, int amount) {
+ if (amount > 1)
+ return amount + " " + base + "s ";
+ if (amount == 1)
+ return amount + " " + base + " ";
+ return "";
+ }
+
+ public interface SelectedServerChangedCallback {
+ void onServerChanged(SharedServerData server);
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/intents/BuildDataUpdateIntent.java b/src/com/projectswg/lightspeed_frontend/intents/BuildDataUpdateIntent.java
new file mode 100644
index 0000000..a19d29e
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/intents/BuildDataUpdateIntent.java
@@ -0,0 +1,82 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.intents;
+
+import com.projectswg.common.control.Intent;
+
+public class BuildDataUpdateIntent extends Intent {
+
+ public static final String TYPE = "BuildDataUpdateIntent";
+
+ private String serverName;
+ private long buildId;
+ private BuildUpdateType updateType;
+
+ public BuildDataUpdateIntent() {
+ this("", -1, null);
+ }
+
+ public BuildDataUpdateIntent(String serverName, long buildId, BuildUpdateType type) {
+ super(TYPE);
+ setServerName(serverName);
+ setBuildId(buildId);
+ setUpdateType(type);
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public long getBuildId() {
+ return buildId;
+ }
+
+ public BuildUpdateType getUpdateType() {
+ return updateType;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public void setBuildId(long buildId) {
+ this.buildId = buildId;
+ }
+
+ public void setUpdateType(BuildUpdateType type) {
+ this.updateType = type;
+ }
+
+ public enum BuildUpdateType {
+ BUILD_ADDED,
+ BUILD_REMOVED,
+ LAST_BUILD_CHANGED,
+ BUILD_UPDATED
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/intents/ConnectionStateUpdateIntent.java b/src/com/projectswg/lightspeed_frontend/intents/ConnectionStateUpdateIntent.java
new file mode 100644
index 0000000..d3f49bd
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/intents/ConnectionStateUpdateIntent.java
@@ -0,0 +1,55 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.intents;
+
+import com.projectswg.common.control.Intent;
+
+public class ConnectionStateUpdateIntent extends Intent {
+
+ public static final String TYPE = "ConnectionStateUpdateIntent";
+
+ private boolean connected;
+
+ public ConnectionStateUpdateIntent() {
+ this(false);
+ }
+
+ public ConnectionStateUpdateIntent(boolean connected) {
+ super(TYPE);
+ setConnected(connected);
+ }
+
+ public boolean isConnected() {
+ return connected;
+ }
+
+ public void setConnected(boolean connected) {
+ this.connected = connected;
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/intents/DeploymentDataUpdateIntent.java b/src/com/projectswg/lightspeed_frontend/intents/DeploymentDataUpdateIntent.java
new file mode 100644
index 0000000..1e5ae7c
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/intents/DeploymentDataUpdateIntent.java
@@ -0,0 +1,92 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.intents;
+
+import com.projectswg.common.control.Intent;
+
+public class DeploymentDataUpdateIntent extends Intent {
+
+ public static final String TYPE = "DeploymentDataUpdateIntent";
+
+ private String serverName;
+ private long buildId;
+ private long deploymentId;
+ private DeploymentUpdateType updateType;
+
+ public DeploymentDataUpdateIntent() {
+ this("", -1, -1, null);
+ }
+
+ public DeploymentDataUpdateIntent(String serverName, long buildId, long deploymentId, DeploymentUpdateType type) {
+ super(TYPE);
+ setServerName(serverName);
+ setBuildId(buildId);
+ setDeploymentId(deploymentId);
+ setUpdateType(type);
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public long getBuildId() {
+ return buildId;
+ }
+
+ public long getDeploymentId() {
+ return deploymentId;
+ }
+
+ public DeploymentUpdateType getUpdateType() {
+ return updateType;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public void setBuildId(long buildId) {
+ this.buildId = buildId;
+ }
+
+ public void setDeploymentId(long deploymentId) {
+ this.deploymentId = deploymentId;
+ }
+
+ public void setUpdateType(DeploymentUpdateType type) {
+ this.updateType = type;
+ }
+
+ public enum DeploymentUpdateType {
+ DEPLOYMENT_ADDED,
+ DEPLOYMENT_REMOVED,
+ LAST_DEPLOYMENT_CHANGED,
+ DEPLOYMENT_UPDATED
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/intents/ServerDataUpdateIntent.java b/src/com/projectswg/lightspeed_frontend/intents/ServerDataUpdateIntent.java
new file mode 100644
index 0000000..8d4533c
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/intents/ServerDataUpdateIntent.java
@@ -0,0 +1,72 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.intents;
+
+import com.projectswg.common.control.Intent;
+
+public class ServerDataUpdateIntent extends Intent {
+
+ public static final String TYPE = "ServerDataUpdateIntent";
+
+ private String name;
+ private ServerUpdateType updateType;
+
+ public ServerDataUpdateIntent() {
+ this("", null);
+ }
+
+ public ServerDataUpdateIntent(String name, ServerUpdateType type) {
+ super(TYPE);
+ setName(name);
+ setUpdateType(type);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ServerUpdateType getUpdateType() {
+ return updateType;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setUpdateType(ServerUpdateType type) {
+ this.updateType = type;
+ }
+
+ public enum ServerUpdateType {
+ SERVER_ADDED,
+ SERVER_REMOVED,
+ PRIMARY_SERVER_CHANGED,
+ SERVER_UPDATED
+ }
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/javafx/Dialog.java b/src/com/projectswg/lightspeed_frontend/javafx/Dialog.java
new file mode 100644
index 0000000..6034cdf
--- /dev/null
+++ b/src/com/projectswg/lightspeed_frontend/javafx/Dialog.java
@@ -0,0 +1,139 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed_frontend.javafx;
+
+import javafx.geometry.Dimension2D;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.layout.Region;
+import javafx.stage.Stage;
+
+public class Dialog {
+
+ private static final Parent DEFAULT_ROOT = new Region();
+
+ private final Stage popup;
+
+ private String title;
+ private Parent root;
+ private double width;
+ private double height;
+ private boolean resizable;
+
+ public Dialog(String title) {
+ this("", 300, 200);
+ }
+
+ public Dialog(String title, double width, double height) {
+ this(title, width, height, null);
+ }
+
+ public Dialog(String title, double width, double height, Parent root) {
+ if (root == null)
+ root = DEFAULT_ROOT;
+ this.popup = new Stage();
+ this.title = title;
+ this.width = width;
+ this.height = height;
+ this.root = root;
+
+ this.resizable = false;
+ this.popup.setScene(new Scene(root, width, height));
+ }
+
+ public Stage getStage() {
+ return popup;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public Parent getRoot() {
+ return root;
+ }
+
+ public double getWidth() {
+ return width;
+ }
+
+ public double getHeight() {
+ return height;
+ }
+
+ public Dimension2D getSize() {
+ return new Dimension2D(width, height);
+ }
+
+ public boolean isResizable() {
+ return resizable;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ popup.setTitle(title);
+ }
+
+ public void setRoot(Parent root) {
+ this.root = root;
+ popup.getScene().setRoot(root);
+ }
+
+ public void setWidth(double width) {
+ this.width = width;
+ popup.setWidth(width);
+ }
+
+ public void setHeight(double height) {
+ this.height = height;
+ popup.setHeight(height);
+ }
+
+ public void setSize(double width, double height) {
+ setWidth(width);
+ setHeight(height);
+ }
+
+ public void setResizable(boolean resizable) {
+ popup.setResizable(resizable);
+ }
+
+ public Stage show() {
+ if (root == null)
+ throw new NullPointerException("Root cannot be null!");
+ popup.centerOnScreen();
+ popup.show();
+ return popup;
+ }
+
+ public void hide() {
+ if (popup != null)
+ popup.hide();
+ }
+
+}
diff --git a/test/com/projectswg/lightspeed/TestLightspeed.java b/test/com/projectswg/lightspeed/TestLightspeed.java
new file mode 100644
index 0000000..c076a85
--- /dev/null
+++ b/test/com/projectswg/lightspeed/TestLightspeed.java
@@ -0,0 +1,42 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+import com.projectswg.lightspeed.frontend.TestFrontend;
+
+@RunWith(Suite.class)
+@SuiteClasses({
+ TestFrontend.class
+})
+public class TestLightspeed {
+
+}
diff --git a/src/com/projectswg/lightspeed_frontend/gui/CreateServerPane.java b/test/com/projectswg/lightspeed/frontend/LinearTestFrontendCommunication.java
similarity index 54%
rename from src/com/projectswg/lightspeed_frontend/gui/CreateServerPane.java
rename to test/com/projectswg/lightspeed/frontend/LinearTestFrontendCommunication.java
index 8f8257e..1139b33 100644
--- a/src/com/projectswg/lightspeed_frontend/gui/CreateServerPane.java
+++ b/test/com/projectswg/lightspeed/frontend/LinearTestFrontendCommunication.java
@@ -25,82 +25,67 @@
* along with Holocore. If not, see . *
* *
***********************************************************************************/
-package com.projectswg.lightspeed_frontend.gui;
+package com.projectswg.lightspeed.frontend;
-import java.net.URL;
-import java.util.ResourceBundle;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicBoolean;
-import javafx.fxml.FXML;
-import javafx.fxml.Initializable;
-import javafx.scene.control.Alert;
-import javafx.scene.control.Button;
-import javafx.scene.control.TextField;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.layout.GridPane;
-import javafx.stage.Stage;
+import com.projectswg.common.network.packets.Packet;
+import com.projectswg.lightspeed_frontend.communication.FrontendCommunication;
+import com.projectswg.lightspeed_frontend.communication.FrontendLightspeedSession.LightspeedSessionCallback;
-import com.projectswg.common.network.packets.post.PostCreateServerPacket;
-import com.projectswg.lightspeed_frontend.Frontend;
-import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
-
-public class CreateServerPane extends GridPane implements Initializable {
+public class LinearTestFrontendCommunication {
- private final AtomicBoolean initialized;
- private final Stage stage;
- private final Frontend frontend;
+ private static final InetSocketAddress ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 44444);
- @FXML
- private TextField nameText;
- @FXML
- private TextField pathText;
- @FXML
- private TextField jvmArgsText;
- @FXML
- private Button createServer;
+ private final FrontendCommunication communication;
+ private final AtomicBoolean connected;
- public CreateServerPane(Stage stage, Frontend frontend) {
- this.initialized = new AtomicBoolean(false);
- this.stage = stage;
- this.frontend = frontend;
- FrontendFXMLLoader.load(this, "fxml/CreateServerPane.fxml");
+ public LinearTestFrontendCommunication() {
+ communication = new FrontendCommunication();
+ connected = new AtomicBoolean(false);
+ communication.setCallback(new LightspeedSessionCallback() {
+ public void onIncomingPacket(Packet p) { LinearTestFrontendCommunication.this.onIncomingPacket(p); }
+ public void onConnectionStateChanged(boolean connected) { LinearTestFrontendCommunication.this.onConnectionStateChanged(connected); }
+ });
+ communication.start();
}
- @Override
- public void initialize(URL location, ResourceBundle resources) {
- initialized.set(true);
- updateUI();
+ public void shutdown() {
+ communication.stop();
}
- private void updateUI() {
- if (!initialized.get())
- return;
- createServer.setOnAction((ae) -> onSubmit());
+ public void connect() {
+ communication.connect(ADDR);
}
- private void onSubmit() {
- String name = nameText.getText().trim();
- String path = pathText.getText().trim();
- String jvmArgs = jvmArgsText.getText().trim();
- if (name.isEmpty()) {
- alert("Invalid Input", "Name cannot be empty!", AlertType.ERROR);
- return;
+ public void disconnect() {
+ communication.disconnect();
+ }
+
+ public boolean isConnected() {
+ return connected.get();
+ }
+
+ public boolean waitForConnectionState(boolean state, long timeout) {
+ while (connected.get() != state && timeout >= 0) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ timeout--;
}
- if (path.isEmpty()) {
- alert("Invalid Input", "Path cannot be empty!", AlertType.ERROR);
- return;
- }
- frontend.send(PostCreateServerPacket.create(name, path, jvmArgs));
- frontend.requestCompleteLoad();
- stage.close();
+ return connected.get() == state;
}
- private void alert(String title, String text, AlertType type) {
- Alert alert = new Alert(type);
- alert.setTitle(title);
- alert.setHeaderText(null);
- alert.setContentText(text);
- alert.show();
+ private void onIncomingPacket(Packet p) {
+
+ }
+
+ private void onConnectionStateChanged(boolean connected) {
+ this.connected.set(connected);
}
}
diff --git a/test/com/projectswg/lightspeed/frontend/TestConnect.java b/test/com/projectswg/lightspeed/frontend/TestConnect.java
new file mode 100644
index 0000000..7962d96
--- /dev/null
+++ b/test/com/projectswg/lightspeed/frontend/TestConnect.java
@@ -0,0 +1,89 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.frontend;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.projectswg.common.network.packets.Packet;
+import com.projectswg.lightspeed_frontend.communication.FrontendCommunication;
+import com.projectswg.lightspeed_frontend.communication.FrontendLightspeedSession.LightspeedSessionCallback;
+
+public class TestConnect {
+
+ @Test
+ public void testConnect() throws InterruptedException {
+ AtomicBoolean state = new AtomicBoolean(false);
+ FrontendCommunication communication = new FrontendCommunication();
+ communication.setCallback(new LightspeedSessionCallback() {
+ @Override
+ public void onIncomingPacket(Packet p) {
+
+ }
+ @Override
+ public void onConnectionStateChanged(boolean connected) {
+ state.set(connected);
+ }
+ });
+ communication.start();
+ communication.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 44444));
+ int timeout = 1000;
+ while (!state.get() && timeout >= 0) {
+ Thread.sleep(1);
+ timeout--;
+ }
+ Assert.assertTrue("Connection state is disabled", state.get());
+ communication.stop();
+ }
+
+ @Test
+ public void testLinearConnect() {
+ LinearTestFrontendCommunication communication = new LinearTestFrontendCommunication();
+ communication.connect();
+ Assert.assertTrue("Connection state is disabled", communication.waitForConnectionState(true, 1000));
+ Assert.assertTrue("Connection state is disabled", communication.isConnected());
+ communication.shutdown();
+ }
+
+ @Test
+ public void testLinearDisconnect() {
+ LinearTestFrontendCommunication communication = new LinearTestFrontendCommunication();
+ communication.connect();
+ communication.waitForConnectionState(true, 1000);
+ Assert.assertTrue("Connection state is disabled", communication.isConnected());
+ communication.disconnect();
+ Assert.assertTrue("Connection state is still enabled", communication.waitForConnectionState(false, 1000));
+ Assert.assertFalse("Connection state is still enabled", communication.isConnected());
+ communication.shutdown();
+ }
+
+}
diff --git a/test/com/projectswg/lightspeed/frontend/TestData.java b/test/com/projectswg/lightspeed/frontend/TestData.java
new file mode 100644
index 0000000..e99abff
--- /dev/null
+++ b/test/com/projectswg/lightspeed/frontend/TestData.java
@@ -0,0 +1,101 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.frontend;
+
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.projectswg.common.network.packets.response.ResponseBuildHistoryPacket;
+import com.projectswg.common.network.packets.response.ResponseDeploymentHistoryPacket;
+import com.projectswg.common.network.packets.response.ResponseDeploymentStatusPacket;
+import com.projectswg.common.network.packets.response.ResponseServerListPacket;
+import com.projectswg.lightspeed_frontend.data.SharedBuildData;
+import com.projectswg.lightspeed_frontend.data.SharedData;
+import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
+import com.projectswg.lightspeed_frontend.data.SharedServerData;
+
+public class TestData {
+
+ @Test
+ public void testSharedData() {
+ SharedData sharedData = new SharedData();
+ ResponseServerListPacket response = ResponseServerListPacket.create(1, Arrays.asList("ProjectSWG", "Localhost"));
+ sharedData.interpretPacket(response);
+ SharedServerData projectswg = sharedData.getServer("ProjectSWG");
+ SharedServerData localhost = sharedData.getServer("Localhost");
+ Assert.assertNotNull(sharedData.getPrimaryServer());
+ Assert.assertNotNull(projectswg);
+ Assert.assertNotNull(localhost);
+ response = ResponseServerListPacket.create(1, Arrays.asList("ProjectSWG", "Localhost", "Other"));
+ sharedData.interpretPacket(response);
+ Assert.assertEquals(projectswg, sharedData.getServer("ProjectSWG"));
+ Assert.assertEquals(localhost, sharedData.getServer("Localhost"));
+ Assert.assertTrue(projectswg == sharedData.getServer("ProjectSWG"));
+ Assert.assertTrue(localhost == sharedData.getServer("Localhost"));
+ Assert.assertNotNull(sharedData.getServer("Other"));
+ }
+
+ @Test
+ public void testSharedServerData() {
+ SharedServerData sharedData = new SharedServerData("ProjectSWG");
+ ResponseBuildHistoryPacket response = ResponseBuildHistoryPacket.create(1, Arrays.asList(
+ new SharedBuildData(1, sharedData),
+ new SharedBuildData(2, sharedData)));
+ sharedData.interpretPacket(response);
+ Assert.assertEquals(2, sharedData.getBuilds().size());
+ Assert.assertNotNull(sharedData.getBuildData(1));
+ Assert.assertNotNull(sharedData.getBuildData(2));
+ Assert.assertEquals(1, sharedData.getBuildData(1).getId());
+ Assert.assertEquals(2, sharedData.getBuildData(2).getId());
+ Assert.assertEquals(2, sharedData.getLastBuild().getId());
+ }
+
+ @Test
+ public void testSharedBuildData() {
+ SharedServerData serverData = new SharedServerData("ProjectSWG");
+ SharedBuildData buildData = new SharedBuildData(1, serverData);
+ serverData.addBuild(buildData);
+ ResponseDeploymentHistoryPacket history = ResponseDeploymentHistoryPacket.create(1, Arrays.asList(
+ new SharedDeploymentData(1, buildData),
+ new SharedDeploymentData(2, buildData)));
+ serverData.interpretPacket(history);
+ Assert.assertEquals(2, serverData.getDeployments().size());
+ Assert.assertEquals(1, serverData.getDeployments().get(1).getId());
+ Assert.assertEquals(2, serverData.getDeployments().get(0).getId());
+ Assert.assertEquals(2, serverData.getLastDeployment().getId());
+ ResponseDeploymentStatusPacket status = ResponseDeploymentStatusPacket.create(1, Arrays.asList(
+ new SharedDeploymentData(3, buildData)));
+ serverData.interpretPacket(status);
+ Assert.assertEquals(3, serverData.getDeployments().size());
+ Assert.assertEquals(3, serverData.getDeployments().get(0).getId());
+ Assert.assertEquals(3, serverData.getLastDeployment().getId());
+ }
+
+}
diff --git a/test/com/projectswg/lightspeed/frontend/TestFrontend.java b/test/com/projectswg/lightspeed/frontend/TestFrontend.java
new file mode 100644
index 0000000..ce8ae42
--- /dev/null
+++ b/test/com/projectswg/lightspeed/frontend/TestFrontend.java
@@ -0,0 +1,41 @@
+/***********************************************************************************
+* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
+* *
+* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+* Our goal is to create an emulator which will provide a server for players to *
+* continue playing a game similar to the one they used to play. We are basing *
+* it on the final publish of the game prior to end-game events. *
+* *
+* This file is part of Holocore. *
+* *
+* -------------------------------------------------------------------------------- *
+* *
+* Holocore is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU Affero General Public License as *
+* published by the Free Software Foundation, either version 3 of the *
+* License, or (at your option) any later version. *
+* *
+* Holocore is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU Affero General Public License for more details. *
+* *
+* You should have received a copy of the GNU Affero General Public License *
+* along with Holocore. If not, see . *
+* *
+***********************************************************************************/
+package com.projectswg.lightspeed.frontend;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({
+ TestConnect.class,
+ TestData.class
+})
+public class TestFrontend {
+
+}