Massive refactoring and fixed the client

This commit is contained in:
Josh Larson
2017-03-15 02:17:30 -05:00
parent d55a668b4e
commit e6c7bb6759
102 changed files with 1023 additions and 6132 deletions
+1
View File
@@ -24,5 +24,6 @@
<classpathentry kind="lib" path="lib/lz4-1.3.0.jar"/>
<classpathentry kind="lib" path="lib/ant/ant-launcher.jar"/>
<classpathentry kind="lib" path="lib/ant/ant.jar"/>
<classpathentry kind="lib" path="lib/PSWGCommon.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+16 -15
View File
@@ -9,6 +9,7 @@
<property name="lib" location="${opdir}/lib"/>
<property name="dist" location="${bin}/dist"/>
<property name="jar" location="${dist}/ProjectSWG.jar"/>
<property name="ext-jar" location="${dist}/ProjectSWG-dependencies.jar"/>
<path id="ant.path">
<fileset dir="lib/ant/">
@@ -26,9 +27,7 @@
<target name="compile" depends="init" description="Compile the sources">
<path id="classpath">
<pathelement path="${classpath}"/>
<fileset dir="${lib}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${lib}" includes="**/*.jar" />
</path>
<!-- Compile sources -->
<javac srcdir="${src}" destdir="${bin}" includeantruntime="true" fork="true" debug="true">
@@ -46,9 +45,7 @@
<pathelement location="${bin}" />
<pathelement location="hamcrest-core-1.3.jar" />
<pathelement location="junit-4.12.jar" />
<fileset dir="${lib}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${lib}" includes="**/*.jar" />
</classpath>
<test name="main.TestAll" haltonfailure="no">
</test>
@@ -61,22 +58,26 @@
<mkdir dir="${dist}"/>
<!-- Create the classpath -->
<path id="classpath">
<pathelement location="${bin}" />
<fileset dir="${lib}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${lib}" includes="**/*.jar" />
</path>
<pathconvert property="manifest.classpath" pathsep=" " refid="classpath">
<!-- Map it to a manifest-compatible string -->
<map from="${opdir}/" to=""/>
</pathconvert>
<jar jarfile="${ext-jar}">
<zipgroupfileset dir="${lib}">
<include name="**/*.jar"/>
</zipgroupfileset>
</jar>
<!-- Create the JAR -->
<manifestclasspath property="manifest.classpath" jarfile="${jar}">
<classpath refid="classpath" />
</manifestclasspath>
<jar jarfile="${jar}">
<jar destfile="${jar}" basedir="${bin}">
<fileset dir="${bin}" includes="**/*.class" />
<zipfileset src="${ext-jar}" excludes="META-INF/**/*" />
<manifest>
<attribute name="Main-Class" value="main.ProjectSWG"/>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
<delete file="${ext-jar}" />
</target>
<target name="clean" description="Clean up">
-54
View File
@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<fx:root type="com.projectswg.lightspeed_frontend.gui.primary_tabs.DeploymentTab" xmlns:fx="http://javafx.com/fxml" stylesheets="@Deployment.css">
<padding>
<Insets top="5.0" left="5.0" right="5.0" bottom="5.0" />
</padding>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="200.0" minWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="150.0" percentWidth="80" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER" prefHeight="50" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="ALWAYS" prefHeight="75" />
</rowConstraints>
<ComboBox fx:id="deploymentComboBox" GridPane.fillWidth="true" maxWidth="200" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label text="Server:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="1" />
<Label text="Build #:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="2" />
<Label text="Deployment #:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="3" />
<Label text="Status:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="4" />
<Label text="Start Time:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="5" />
<Label text="Uptime:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="6" />
<Label text="Deployment Log:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="7" />
<Label fx:id="serverNameText" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label fx:id="buildIdText" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label fx:id="deploymentIdText" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label fx:id="statusText" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label fx:id="startTimeText" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label fx:id="uptimeText" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<VBox styleClass="log-wrapper" GridPane.columnIndex="0" GridPane.rowIndex="8" GridPane.columnSpan="2">
<padding>
<Insets top="5.0" left="5.0" right="5.0" bottom="5.0" />
</padding>
<Label fx:id="logText" styleClass="log" GridPane.hgrow="ALWAYS" />
</VBox>
</fx:root>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

-43
View File
@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 507.2 507.2" style="enable-background:new 0 0 507.2 507.2;" xml:space="preserve">
<circle style="fill:#32BA7C;" cx="253.6" cy="253.6" r="253.6"/>
<path style="fill:#0AA06E;" d="M188.8,368l130.4,130.4c108-28.8,188-127.2,188-244.8c0-2.4,0-4.8,0-7.2L404.8,152L188.8,368z"/>
<g>
<path style="fill:#FFFFFF;" d="M260,310.4c11.2,11.2,11.2,30.4,0,41.6l-23.2,23.2c-11.2,11.2-30.4,11.2-41.6,0L93.6,272.8
c-11.2-11.2-11.2-30.4,0-41.6l23.2-23.2c11.2-11.2,30.4-11.2,41.6,0L260,310.4z"/>
<path style="fill:#FFFFFF;" d="M348.8,133.6c11.2-11.2,30.4-11.2,41.6,0l23.2,23.2c11.2,11.2,11.2,30.4,0,41.6l-176,175.2
c-11.2,11.2-30.4,11.2-41.6,0l-23.2-23.2c-11.2-11.2-11.2-30.4,0-41.6L348.8,133.6z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

-43
View File
@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 507.2 507.2" style="enable-background:new 0 0 507.2 507.2;" xml:space="preserve">
<circle style="fill:#F15249;" cx="253.6" cy="253.6" r="253.6"/>
<path style="fill:#AD0E0E;" d="M147.2,368L284,504.8c115.2-13.6,206.4-104,220.8-219.2L367.2,148L147.2,368z"/>
<path style="fill:#FFFFFF;" d="M373.6,309.6c11.2,11.2,11.2,30.4,0,41.6l-22.4,22.4c-11.2,11.2-30.4,11.2-41.6,0l-176-176
c-11.2-11.2-11.2-30.4,0-41.6l23.2-23.2c11.2-11.2,30.4-11.2,41.6,0L373.6,309.6z"/>
<path style="fill:#D6D6D6;" d="M280.8,216L216,280.8l93.6,92.8c11.2,11.2,30.4,11.2,41.6,0l23.2-23.2c11.2-11.2,11.2-30.4,0-41.6
L280.8,216z"/>
<path style="fill:#FFFFFF;" d="M309.6,133.6c11.2-11.2,30.4-11.2,41.6,0l23.2,23.2c11.2,11.2,11.2,30.4,0,41.6L197.6,373.6
c-11.2,11.2-30.4,11.2-41.6,0l-22.4-22.4c-11.2-11.2-11.2-30.4,0-41.6L309.6,133.6z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

@@ -1,6 +1,8 @@
#primaryViewContainer {
-fx-background-color: #000000;
-fx-text-fill: #FFFFFF;
-fx-pref-width: 800;
-fx-pref-height: 640;
}
#commonPanel {
@@ -1,39 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.effect.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.geometry.*?>
<?import java.net.URL?>
<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml/1" fx:id="primaryViewContainer" stylesheets="@PrimaryView.css" >
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:id="primaryViewContainer" stylesheets="@PrimaryView.css" fx:controller="com.projectswg.lightspeed_frontend.gui.LightspeedPrimaryView">
<HBox fx:id="commonPanel" alignment="CENTER_RIGHT" HBox.hgrow="ALWAYS" spacing="5.0">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<MenuButton fx:id="commonServerStatus" mnemonicParsing="false" />
<MenuButton fx:id="commonBuildStatus" mnemonicParsing="false" />
<MenuButton fx:id="commonDeploymentStatus" mnemonicParsing="false" />
</HBox>
<TabPane tabClosingPolicy="UNAVAILABLE">
<TabPane tabClosingPolicy="UNAVAILABLE" VBox.vgrow="ALWAYS">
<tabs>
<Tab text="General">
<content>
<com.projectswg.lightspeed_frontend.gui.primary_tabs.GeneralTab fx:id="generalTab" />
<fx:include source="primary_tabs/General.fxml" />
</content>
</Tab>
<Tab text="Build">
<content>
<com.projectswg.lightspeed_frontend.gui.primary_tabs.BuildTab fx:id="buildTab" />
<fx:include source="primary_tabs/Build.fxml" />
</content>
</Tab>
<Tab text="Deployment">
<content>
<com.projectswg.lightspeed_frontend.gui.primary_tabs.DeploymentTab fx:id="deploymentTab" />
<fx:include source="primary_tabs/Deployment.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</fx:root>
</VBox>
@@ -1,13 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.image.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.effect.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import java.net.URL?>
<fx:root type="com.projectswg.lightspeed_frontend.gui.primary_tabs.BuildTab" xmlns:fx="http://javafx.com/fxml" stylesheets="@Build.css" >
<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:id="rootBuild" stylesheets="@Build.css" fx:controller="com.projectswg.lightspeed_frontend.gui.primary_tabs.BuildTab">
<padding>
<Insets top="5.0" left="5.0" right="5.0" bottom="5.0" />
</padding>
@@ -41,5 +45,4 @@
<Label fx:id="compileTimeText" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label fx:id="modeText" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Label fx:id="testText" GridPane.columnIndex="1" GridPane.rowIndex="7" />
</fx:root>
</GridPane>
@@ -10,15 +10,13 @@
-fx-text-fill: #04ff00;
}
.log-wrapper {
.log {
-fx-text-fill: #FFFFFF;
}
.log .content {
-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;
}
+50
View File
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.effect.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import java.net.URL?>
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:id="rootDeployment" stylesheets="@Deployment.css" fx:controller="com.projectswg.lightspeed_frontend.gui.primary_tabs.DeploymentTab">
<padding>
<Insets top="5.0" left="5.0" right="5.0" bottom="5.0" />
</padding>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="200.0" minWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="150.0" percentWidth="80" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER" prefHeight="50" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
<RowConstraints vgrow="NEVER" prefHeight="40" />
</rowConstraints>
<ComboBox fx:id="deploymentComboBox" GridPane.fillWidth="true" maxWidth="200" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label text="Server:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="1" />
<Label text="Build #:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="2" />
<Label text="Deployment #:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="3" />
<Label text="Status:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="4" />
<Label text="Start Time:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="5" />
<Label text="Uptime:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="6" />
<Label text="Deployment Log:" styleClass="white-label" GridPane.columnIndex="0" GridPane.rowIndex="7" />
<Label fx:id="serverNameText" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label fx:id="buildIdText" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label fx:id="deploymentIdText" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label fx:id="statusText" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label fx:id="startTimeText" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label fx:id="uptimeText" GridPane.columnIndex="1" GridPane.rowIndex="6" />
</GridPane>
<TextArea fx:id="logTextArea" styleClass="log" editable="false" maxHeight="Infinity" VBox.vgrow="ALWAYS" />
</VBox>
@@ -1,14 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.image.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.effect.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import java.net.URL?>
<fx:root type="com.projectswg.lightspeed_frontend.gui.primary_tabs.GeneralTab" xmlns:fx="http://javafx.com/fxml" stylesheets="@General.css" >
<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:id="rootGeneral" stylesheets="@General.css" fx:controller="com.projectswg.lightspeed_frontend.gui.primary_tabs.GeneralTab">
<padding>
<Insets top="5.0" left="5.0" right="5.0" bottom="5.0" />
</padding>
@@ -36,4 +39,4 @@
<Label fx:id="deploymentStatusText" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label fx:id="populationText" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label fx:id="uptimeText" GridPane.columnIndex="1" GridPane.rowIndex="5" />
</fx:root>
</GridPane>
@@ -1,70 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
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.common.info.Log;
import com.projectswg.lightspeed.server.ServerServerData;
import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
public class CombinedLightspeed {
public static void main(String [] args) {
ServerServerData 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 ServerServerData getServer() {
try {
if (System.getProperty("os.name").toLowerCase().contains("win"))
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
Log.e(e);
}
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;
ServerServerData server = new ServerServerData("LIGHTSPEED");
server.setDirectory(chooser.getSelectedFile().getAbsolutePath());
return server;
}
}
+10 -7
View File
@@ -30,9 +30,11 @@ package com.projectswg;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import com.projectswg.common.debug.Log;
import com.projectswg.common.debug.Log.LogLevel;
import com.projectswg.common.debug.log_wrapper.ConsoleLogWrapper;
import com.projectswg.common.info.HeavyweightDataManager;
import com.projectswg.common.info.Log;
import com.projectswg.lightspeed.LightspeedManager;
import com.projectswg.lightspeed.LightspeedMainManager;
public class Lightspeed {
@@ -42,13 +44,14 @@ public class Lightspeed {
public static void main(String [] args) {
if (MAIN_THREAD.get() != null)
throw new IllegalStateException("Cannot run main() twice!");
Log.addWrapper(new ConsoleLogWrapper(LogLevel.VERBOSE));
MAIN_THREAD.set(Thread.currentThread());
LightspeedManager.setDataManager(new HeavyweightDataManager());
LightspeedManager.getDataManager().initialize();
LightspeedManager lightspeed = new LightspeedManager();
LightspeedMainManager.setDataManager(new HeavyweightDataManager());
LightspeedMainManager.getDataManager().initialize();
LightspeedMainManager lightspeed = new LightspeedMainManager();
Runtime.getRuntime().addShutdownHook(new Thread(Lightspeed::doShutdown, "lightspeed-shutdown-hook"));
runLightspeed(lightspeed);
LightspeedManager.getDataManager().terminate();
LightspeedMainManager.getDataManager().terminate();
}
public static void requestShutdown() {
@@ -66,7 +69,7 @@ public class Lightspeed {
}
}
private static void runLightspeed(LightspeedManager lightspeed) {
private static void runLightspeed(LightspeedMainManager lightspeed) {
Log.i("Initializing...");
lightspeed.initialize();
Log.i("Initialized.");
@@ -29,18 +29,18 @@ package com.projectswg;
import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.debug.Log;
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.LightspeedMainManager;
import com.projectswg.lightspeed.server.ServerServerData;
public class LightweightLightspeed {
public static int runConcurrent(ServerServerData server, AtomicBoolean running) {
Thread mainThread = Thread.currentThread();
LightspeedManager.setDataManager(createDataManager(0, server));
LightspeedMainManager.setDataManager(createDataManager(0, server));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
running.set(false);
mainThread.interrupt();
@@ -49,7 +49,7 @@ public class LightweightLightspeed {
} catch (Exception e) {
Log.e(e);
}
LightspeedManager.getDataManager().terminate();
LightspeedMainManager.getDataManager().terminate();
}, "lightspeed-shutdown-hook"));
return runLightspeedConcurrent(running);
}
@@ -57,13 +57,13 @@ public class LightweightLightspeed {
public static void run(int port, ServerServerData server) {
Thread mainThread = Thread.currentThread();
AtomicBoolean running = new AtomicBoolean(true);
LightspeedManager.setDataManager(createDataManager(port, server));
LightspeedMainManager.setDataManager(createDataManager(port, server));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
running.set(false);
mainThread.interrupt();
}, "lightspeed-shutdown-hook"));
runLightspeed(running);
LightspeedManager.getDataManager().terminate();
LightspeedMainManager.getDataManager().terminate();
}
private static LightweightDataManager createDataManager(int port, ServerServerData server) {
@@ -76,7 +76,7 @@ public class LightweightLightspeed {
}
private static void runLightspeed(AtomicBoolean running) {
LightspeedManager lightspeed = new LightspeedManager();
LightspeedMainManager lightspeed = new LightspeedMainManager();
Log.i("Lightspeed", "Initializing...");
lightspeed.initialize();
Log.i("Lightspeed", "Initialized.");
@@ -99,7 +99,7 @@ public class LightweightLightspeed {
}
private static int runLightspeedConcurrent(AtomicBoolean running) {
LightspeedManager lightspeed = new LightspeedManager();
LightspeedMainManager lightspeed = new LightspeedMainManager();
Log.i("Lightspeed", "Initializing...");
lightspeed.initialize();
Log.i("Lightspeed", "Initialized.");
@@ -1,106 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.callback;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.utilities.ThreadUtilities;
class BaseCallbackManager {
private final Object executorMutex;
private final String name;
private final int threadCount;
private final AtomicBoolean shutdown;
private ExecutorService executor;
public BaseCallbackManager(String name) {
this(name, 1);
}
public BaseCallbackManager(String name, int threadCount) {
this.executorMutex = new Object();
this.name = name;
this.threadCount = threadCount;
this.shutdown = new AtomicBoolean(false);
this.executor = null;
}
public void start() {
synchronized (executorMutex) {
if (executor != null && !shutdown.get())
executor.shutdown();
shutdown.set(false);
if (threadCount <= 1)
executor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory(name+"-callback-manager"));
else
executor = Executors.newFixedThreadPool(threadCount, ThreadUtilities.newThreadFactory(name+"-callback-manager-%d"));
}
}
public void stop() {
synchronized (executorMutex) {
executor.shutdown();
shutdown.set(true);
}
}
public boolean awaitTermination(long timeout, TimeUnit unit) {
synchronized (executorMutex) {
if (executor == null)
return true;
if (!shutdown.get())
throw new IllegalStateException("Cannot wait for termination when never stopped!");
try {
return executor.awaitTermination(timeout, unit);
} catch (InterruptedException e) {
return false;
}
}
}
protected boolean call(Runnable r) {
synchronized (executorMutex) {
if (executor == null)
throw new IllegalStateException("Manager has not been started!");
if (shutdown.get())
return false;
try {
executor.execute(r);
return true;
} catch (RejectedExecutionException e) {
return false;
}
}
}
}
@@ -1,91 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.callback;
import java.util.ArrayList;
import java.util.List;
import com.projectswg.common.info.Log;
public class CallbackManager<T> extends BaseCallbackManager {
private final List<T> callbacks;
public CallbackManager(String name) {
this(name, 1);
}
public CallbackManager(String name, int threadCount) {
super(name, threadCount);
this.callbacks = new ArrayList<>();
}
public void addCallback(T callback) {
synchronized (callbacks) {
callbacks.add(callback);
}
}
public void removeCallback(T callback) {
synchronized (callbacks) {
callbacks.remove(callback);
}
}
public void setCallback(T callback) {
synchronized (callbacks) {
callbacks.clear();
callbacks.add(callback);
}
}
public void clearCallbacks() {
synchronized (callbacks) {
callbacks.clear();
}
}
public boolean callOnEach(CallCallback<T> call) {
synchronized (callbacks) {
return call(() -> {
for (T callback : callbacks) {
try {
call.run(callback);
} catch (Exception e) {
Log.e(e);
}
}
});
}
}
public interface CallCallback<T> {
void run(T callback);
}
}
@@ -1,64 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
public class PswgBasicScheduledThread extends PswgScheduledThreadPool {
private final Runnable runnable;
public PswgBasicScheduledThread(String name, Runnable runnable) {
super(1, name);
this.runnable = runnable;
}
@Override
public void start() {
throw new UnsupportedOperationException("Cannot use this function. Must use startX(initialDelay, periodicDelay)");
}
public void startWithFixedRate(long initialDelay, long periodicDelay) {
super.start();
super.executeWithFixedRate(initialDelay, periodicDelay, runnable);
}
public void startWithFixedDelay(long initialDelay, long periodicDelay) {
super.start();
super.executeWithFixedDelay(initialDelay, periodicDelay, runnable);
}
@Override
public void executeWithFixedRate(long initialDelay, long periodicDelay, Runnable runnable) {
throw new UnsupportedOperationException("Runnable is defined in the constructor!");
}
@Override
public void executeWithFixedDelay(long initialDelay, long periodicDelay, Runnable runnable) {
throw new UnsupportedOperationException("Runnable is defined in the constructor!");
}
}
@@ -1,65 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
import java.util.concurrent.atomic.AtomicBoolean;
public class PswgBasicThread extends PswgThreadPool {
private final AtomicBoolean executing;
private final Runnable runnable;
public PswgBasicThread(String name, Runnable runnable) {
super(1, name);
this.executing = new AtomicBoolean(false);
this.runnable = runnable;
}
@Override
public void start() {
super.start();
super.execute(() -> {
executing.set(true);
try {
runnable.run();
} finally {
executing.set(false);
}
});
}
public boolean isExecuting() {
return executing.get();
}
@Override
public void execute(Runnable runnable) {
throw new UnsupportedOperationException("Runnable is defined in the constructor!");
}
}
@@ -1,115 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.control.Assert;
public class PswgScheduledThreadPool {
private final AtomicBoolean running;
private final int nThreads;
private final ThreadFactory threadFactory;
private ScheduledExecutorService executor;
public PswgScheduledThreadPool(int nThreads, String nameFormat) {
this.running = new AtomicBoolean(false);
this.nThreads = nThreads;
this.threadFactory = new CustomThreadFactory(nameFormat);
this.executor = null;
}
public void start() {
Assert.test(!running.getAndSet(true));
executor = Executors.newScheduledThreadPool(nThreads, threadFactory);
}
public void stop() {
Assert.test(running.getAndSet(false));
executor.shutdownNow();
}
public void executeWithFixedRate(long initialDelay, long time, Runnable runnable) {
Assert.test(running.get());
executor.scheduleAtFixedRate(() -> {
try {
runnable.run();
} catch (Throwable t) {
t.printStackTrace();
}
}, initialDelay, time, TimeUnit.MILLISECONDS);
}
public void executeWithFixedDelay(long initialDelay, long time, Runnable runnable) {
Assert.test(running.get());
executor.scheduleWithFixedDelay(() -> {
try {
runnable.run();
} catch (Throwable t) {
t.printStackTrace();
}
}, initialDelay, time, TimeUnit.MILLISECONDS);
}
public boolean awaitTermination(long time) {
Assert.notNull(executor);
try {
return executor.awaitTermination(time, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
private static class CustomThreadFactory implements ThreadFactory {
private final String pattern;
private int counter;
public CustomThreadFactory(String pattern) {
this.pattern = pattern;
this.counter = 0;
}
@Override
public Thread newThread(Runnable r) {
String name;
if (pattern.contains("%d"))
name = String.format(pattern, counter++);
else
name = pattern;
return new Thread(r, name);
}
}
}
@@ -1,108 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.control.Assert;
public class PswgThreadPool {
private final AtomicBoolean running;
private final int nThreads;
private final ThreadFactory threadFactory;
private ExecutorService executor;
public PswgThreadPool(int nThreads, String nameFormat) {
this.running = new AtomicBoolean(false);
this.nThreads = nThreads;
this.threadFactory = new CustomThreadFactory(nameFormat);
this.executor = null;
}
public void start() {
Assert.test(!running.getAndSet(true));
executor = Executors.newFixedThreadPool(nThreads, threadFactory);
}
public void stop() {
Assert.test(running.getAndSet(false));
executor.shutdownNow();
}
public void execute(Runnable runnable) {
Assert.test(running.get());
executor.execute(() -> {
try {
runnable.run();
} catch (Throwable t) {
t.printStackTrace();
}
});
}
public boolean awaitTermination(long time) {
Assert.notNull(executor);
try {
return executor.awaitTermination(time, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
public boolean isRunning() {
return running.get();
}
private static class CustomThreadFactory implements ThreadFactory {
private final String pattern;
private int counter;
public CustomThreadFactory(String pattern) {
this.pattern = pattern;
this.counter = 0;
}
@Override
public Thread newThread(Runnable r) {
String name;
if (pattern.contains("%d"))
name = String.format(pattern, counter++);
else
name = pattern;
return new Thread(r, name);
}
}
}
@@ -1,129 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SmartLock {
private final Lock lock;
private final Condition condition;
public SmartLock() {
this.lock = new ReentrantLock(true);
this.condition = lock.newCondition();
}
public void lock() {
lock.lock();
}
public void lockInterruptibly() throws InterruptedException {
lock.lockInterruptibly();
}
public boolean tryLock() {
return lock.tryLock();
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return lock.tryLock(time, unit);
}
public void unlock() {
lock.unlock();
}
public void await() throws InterruptedException {
lock();
try {
condition.await();
} finally {
unlock();
}
}
public void awaitUninterruptibly() {
lock();
try {
condition.awaitUninterruptibly();
} finally {
unlock();
}
}
public long awaitNanos(long nanosTimeout) throws InterruptedException {
lock();
try {
return condition.awaitNanos(nanosTimeout);
} finally {
unlock();
}
}
public boolean await(long time, TimeUnit unit) throws InterruptedException {
lock();
try {
return condition.await(time, unit);
} finally {
unlock();
}
}
public boolean awaitUntil(Date deadline) throws InterruptedException {
lock();
try {
return condition.awaitUntil(deadline);
} finally {
unlock();
}
}
public void signal() {
lock();
try {
condition.signal();
} finally {
unlock();
}
}
public void signalAll() {
lock();
try {
condition.signalAll();
} finally {
unlock();
}
}
}
@@ -1,151 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class SynchronizedQueue<T> implements Queue<T> {
private final Queue<T> queue;
public SynchronizedQueue() {
this(new ArrayDeque<>());
}
public SynchronizedQueue(Queue<T> queue) {
this.queue = queue;
}
public synchronized void forEach(Consumer<? super T> action) {
queue.forEach(action);
}
public synchronized boolean add(T e) {
return queue.add(e);
}
public synchronized boolean offer(T e) {
return queue.offer(e);
}
public synchronized int size() {
return queue.size();
}
public synchronized boolean isEmpty() {
return queue.isEmpty();
}
public synchronized boolean contains(Object o) {
return queue.contains(o);
}
public synchronized T remove() {
return queue.remove();
}
public synchronized T poll() {
return queue.poll();
}
public synchronized T element() {
return queue.element();
}
public synchronized Iterator<T> iterator() {
return queue.iterator();
}
public synchronized T peek() {
return queue.peek();
}
public synchronized Object[] toArray() {
return queue.toArray();
}
public synchronized <E> E[] toArray(E[] a) {
return queue.toArray(a);
}
public synchronized boolean remove(Object o) {
return queue.remove(o);
}
public synchronized boolean containsAll(Collection<?> c) {
return queue.containsAll(c);
}
public synchronized boolean addAll(Collection<? extends T> c) {
return queue.addAll(c);
}
public synchronized boolean removeAll(Collection<?> c) {
return queue.removeAll(c);
}
public synchronized boolean removeIf(Predicate<? super T> filter) {
return queue.removeIf(filter);
}
public synchronized boolean retainAll(Collection<?> c) {
return queue.retainAll(c);
}
public synchronized void clear() {
queue.clear();
}
public synchronized boolean equals(Object o) {
return queue.equals(o);
}
public synchronized int hashCode() {
return queue.hashCode();
}
public synchronized Spliterator<T> spliterator() {
return queue.spliterator();
}
public synchronized Stream<T> stream() {
return queue.stream();
}
public synchronized Stream<T> parallelStream() {
return queue.parallelStream();
}
}
@@ -1,117 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
import com.projectswg.common.info.Log;
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) {
notNull(o, "");
}
public static void notNull(Object o, String message) {
if (debug() && o == null)
handle(new NullPointerException(message));
}
public static void isNull(Object o) {
isNull(o, "");
}
public static void isNull(Object o, String message) {
if (debug() && o != null)
handle(new AssertionException(message));
}
public static void test(boolean expr) {
test(expr, "");
}
public static void test(boolean expr, String message) {
if (debug() && !expr)
handle(new AssertionException(message));
}
public static void fail() {
fail("");
}
public static void fail(String message) {
if (debug())
handle(new AssertionException(message));
}
private static void handle(RuntimeException e) {
AssertLevel level = Assert.level;
switch (level) {
case WARN:
warn(e);
break;
case ASSERT:
throw e;
default:
break;
}
}
private static void warn(Exception e) {
StackTraceElement [] elements = e.getStackTrace();
if (elements.length <= 1)
Log.e(e);
else
Log.e(e);
}
private static class AssertionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public AssertionException(String message) {
super(message);
}
}
public enum AssertLevel {
IGNORE,
WARN,
ASSERT
}
}
@@ -1,140 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
public abstract class Intent {
private boolean broadcasted;
private boolean complete;
private Intent parallel;
private Intent sequential;
protected Intent() {
this.broadcasted = false;
this.complete = false;
this.parallel = null;
this.sequential = null;
}
/**
* Called when the intent has been completed
*/
public synchronized void markAsComplete() {
this.complete = true;
if (sequential != null)
sequential.broadcast();
sequential = null;
parallel = null;
}
/**
* Determines whether or not the intent has been broadcasted and processed
* by the system
* @return TRUE if the intent has been broadcasted and processed, FALSE
* otherwise
*/
public synchronized boolean isComplete() {
return complete;
}
/**
* Determines whether or not the intent has been broadcasted to the system
* @return TRUE if the intent has been broadcasted, FALSE otherwise
*/
public synchronized boolean isBroadcasted() {
return broadcasted;
}
/**
* Waits for the intent as the parameter to finish before this intent
* starts
* @param i the intent to execute after
*/
public synchronized void broadcastAfterIntent(Intent i) {
if (i == null) {
broadcast();
return;
}
synchronized (i) {
if (i.isComplete())
broadcast();
else
i.setAsSequential(this);
}
}
/**
* Waits for the intent as the parameter to start before this intent starts
* @param i the intent to execute with
*/
public synchronized void broadcastWithIntent(Intent i) {
if (i == null) {
broadcast();
return;
}
synchronized (i) {
if (!isComplete()) {
setAsParallel(i);
}
broadcast();
}
}
/**
* Broadcasts this node to the system
*/
public synchronized void broadcast() {
if (broadcasted)
throw new IllegalStateException("Intent has already been broadcasted!");
broadcasted = true;
IntentManager.getInstance().broadcastIntent(this);
if (parallel != null)
parallel.broadcast();
parallel = null;
}
@Override
public synchronized String toString() {
return getClass().getSimpleName();
}
private synchronized void setAsParallel(Intent i) {
if (parallel == null)
parallel = i;
else
parallel.setAsParallel(i);
}
private synchronized void setAsSequential(Intent i) {
if (sequential == null)
sequential = i;
else
sequential.setAsParallel(i);
}
}
@@ -1,53 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
public class IntentChain {
private final Object mutex;
private Intent i;
public IntentChain() {
mutex = new Object();
i = null;
}
public void reset() {
synchronized (mutex) {
i = null;
}
}
public void broadcastAfter(Intent i) {
synchronized (mutex) {
i.broadcastAfterIntent(this.i);
this.i = i;
}
}
}
@@ -1,132 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
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<Runnable> 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;
}
}
}
}
}
@@ -1,144 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import com.projectswg.common.info.Log;
import com.projectswg.common.utilities.ThreadUtilities;
public class IntentManager {
private static final IntentManager INSTANCE = new IntentManager();
private final Runnable broadcastRunnable;
private final Map <Class<? extends Intent>, List<IntentReceiver>> intentRegistrations;
private final Queue <Intent> intentQueue;
private ExecutorService broadcastThreads;
private boolean initialized = false;
private boolean terminated = false;
private IntentManager() {
intentRegistrations = new HashMap<>();
intentQueue = new IntentQueue<>();
initialize();
broadcastRunnable = () -> {
Intent i;
synchronized (intentQueue) {
i = intentQueue.poll();
}
if (i != null)
broadcast(i);
};
}
public void initialize() {
if (!initialized) {
final int broadcastThreadCount = Runtime.getRuntime().availableProcessors() * 10;
broadcastThreads = Executors.newFixedThreadPool(broadcastThreadCount, ThreadUtilities.newThreadFactory("intent-processor-%d"));
initialized = true;
terminated = false;
}
}
public void terminate() {
if (!terminated) {
broadcastThreads.shutdown();
initialized = false;
terminated = true;
}
}
protected void broadcastIntent(Intent i) {
if (i == null)
throw new NullPointerException("Intent cannot be null!");
synchronized (intentQueue) {
intentQueue.add(i);
}
try { broadcastThreads.execute(broadcastRunnable); }
catch (RejectedExecutionException e) { } // This error is thrown when the server is being shut down
}
public void registerForIntent(Class<? extends Intent> c, IntentReceiver r) {
if (r == null)
throw new NullPointerException("Cannot register a null value for an intent");
synchronized (intentRegistrations) {
List <IntentReceiver> intents = intentRegistrations.get(c);
if (intents == null) {
intents = new CopyOnWriteArrayList<>();
intentRegistrations.put(c, intents);
}
synchronized (intents) {
intents.add(r);
}
}
}
private void broadcast(Intent i) {
List <IntentReceiver> receivers;
synchronized (intentRegistrations) {
receivers = intentRegistrations.get(i.getClass());
}
if (receivers == null) {
i.markAsComplete();
return;
}
for (IntentReceiver r : receivers) {
broadcast(r, i);
}
i.markAsComplete();
}
private void broadcast(IntentReceiver r, Intent i) {
try {
r.onIntentReceived(i);
} catch (Throwable t) {
Log.e("Fatal Exception while processing intent: " + i);
Log.e(t);
}
}
public static int getIntentsQueued() {
synchronized (getInstance().intentQueue) {
return getInstance().intentQueue.size();
}
}
public static IntentManager getInstance() {
return INSTANCE;
}
}
@@ -1,235 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.Queue;
class IntentQueue<E> implements Queue<E> {
private final Node head;
private int size;
private int modificationCount;
public IntentQueue() {
head = new Node(null, null, null); // Left = Forward, Right = Reverse
head.left = head;
head.right = head;
modificationCount = 0;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object o) {
Node n = head;
while (n.left != head) {
if (n.left.value == o)
return true;
}
return false;
}
@Override
public Iterator iterator() {
return new Iterator();
}
@Override
public Object [] toArray() {
return null;
}
@Override
public <T> T [] toArray(T [] a) {
return null;
}
@Override
public boolean remove(Object o) {
modificationCount++;
Node n = head;
while (n.left != head) {
if (n.left.value == o) {
n.left = n.left.left;
n.left.right = n;
}
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c)
if (!contains(o))
return false;
return true;
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean added = false;
for (E i : c)
added = add(i) || added;
return added;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean changed = false;
for (Object o : c)
changed = remove(o) || changed;
return changed;
}
@Override
public boolean retainAll(Collection<?> c) {
boolean changed = false;
Node n = head;
while (n.left != head) {
if (!c.contains(n.left.value)) {
n.left.left.right = n;
n.left = n.left.left;
}
}
return changed;
}
@Override
public void clear() {
modificationCount++;
size = 0;
head.left = head;
head.right = head;
}
@Override
public boolean add(E e) {
head.right.left = new Node(e, head, head.right);
head.right = head.right.left;
modificationCount++;
size++;
return true;
}
@Override
public boolean offer(E e) {
return add(e);
}
@Override
public E remove() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty!");
modificationCount++;
E i = head.left.value;
head.left = head.left.left;
head.left.right = head;
size--;
return i;
}
@Override
public E poll() {
if (isEmpty())
return null;
modificationCount++;
E i = head.left.value;
head.left = head.left.left;
head.left.right = head;
size--;
return i;
}
@Override
public E element() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty!");
return head.left.value;
}
@Override
public E peek() {
if (isEmpty())
return null;
return head.left.value;
}
private class Iterator implements java.util.Iterator<E> {
private final int modificationCount;
private Node currentNode;
public Iterator() {
this.modificationCount = IntentQueue.this.modificationCount;
this.currentNode = IntentQueue.this.head;
}
@Override
public boolean hasNext() {
if (this.modificationCount != IntentQueue.this.modificationCount)
throw new ConcurrentModificationException();
return currentNode.left != IntentQueue.this.head;
}
@Override
public E next() {
if (!hasNext())
throw new NoSuchElementException("Iterator has reached the end of the queue!");
E i = currentNode.left.value;
currentNode = currentNode.left;
return i;
}
}
private class Node {
public final E value;
public Node left;
public Node right;
public Node(E value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
}
}
@@ -27,15 +27,34 @@
***********************************************************************************/
package com.projectswg.common.control;
import com.projectswg.common.data.BackendData;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.DataManager;
public interface IntentReceiver {
public class LightspeedManager extends Manager {
/**
* This function will be called if an intent is broadcasted and this
* manager is listening for it, or if this manager is specifically given
* this intent.
* @param i the intent received
* 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
*/
public void onIntentReceived(Intent i);
public final Config getConfig(ConfigFile file) {
return getDataManager().getConfig(file);
}
public BackendData getBackendData() {
return getDataManager().getBackendData();
}
public static void setDataManager(DataManager dataManager) {
LightspeedService.setDataManager(dataManager);
}
public static DataManager getDataManager() {
return LightspeedService.getDataManager();
}
}
@@ -25,43 +25,38 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.concurrency;
package com.projectswg.common.control;
import java.util.ArrayDeque;
import java.util.Queue;
import com.projectswg.common.data.BackendData;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.DataManager;
public class PswgTaskThreadPool<T> extends PswgThreadPool {
public class LightspeedService extends Service {
private final Queue<T> tasks;
private final Runnable runner;
private static DataManager dataManager = null;
public PswgTaskThreadPool(int nThreads, String namePattern, TaskExecutor<T> executor) {
super(nThreads, namePattern);
this.tasks = new ArrayDeque<>();
this.runner = () -> {
T t = null;
synchronized (tasks) {
t = tasks.poll();
}
if (t != null)
executor.run(t);
};
/**
* 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
*/
public final Config getConfig(ConfigFile file) {
return getDataManager().getConfig(file);
}
@Override
public void execute(Runnable runnable) {
throw new UnsupportedOperationException("Runnable are posted automatically by addTask!");
public BackendData getBackendData() {
return getDataManager().getBackendData();
}
public void addTask(T t) {
synchronized (tasks) {
tasks.add(t);
}
super.execute(runner);
public static void setDataManager(DataManager dataManager) {
LightspeedService.dataManager = dataManager;
}
public interface TaskExecutor<T> {
void run(T t);
public static DataManager getDataManager() {
return dataManager;
}
}
@@ -1,187 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
import java.util.ArrayList;
import java.util.List;
import com.projectswg.common.info.Log;
/**
* A Manager is a class that will manage services, and generally controls the
* program as a whole
*/
public abstract class Manager extends Service {
private List <Service> children;
public Manager() {
children = new ArrayList<Service>();
}
/**
* Initializes this manager. If the manager returns false on this method
* then the initialization failed and may not work as intended. This will
* initialize all children automatically.
* @return TRUE if initialization was successful, FALSE otherwise
*/
@Override
public boolean initialize() {
boolean success = super.initialize();
synchronized (children) {
for (Service child : children) {
if (!child.initialize()) {
Log.e(child.getClass().getSimpleName() + " failed to initialize!");
success = false;
break;
}
}
}
return success;
}
/**
* Starts this manager. If the manager returns false on this method then
* the manger failed to start and may not work as intended. This will start
* all children automatically.
* @return TRUE if starting was successful, FALSE otherwise
*/
@Override
public boolean start() {
boolean success = super.start();
synchronized (children) {
for (Service child : children) {
if (!child.start()) {
Log.e(child.getClass().getSimpleName() + " failed to start!");
success = false;
break;
}
}
}
return success;
}
/**
* Stops this manager. If the manager returns false on this method then
* the manger failed to stop and may not have fully locked down. This will
* start all children automatically.
* @return TRUE if stopping was successful, FALSE otherwise
*/
@Override
public boolean stop() {
boolean success = super.stop(), cSuccess = true;
synchronized (children) {
for (Service child : children) {
if (!success)
break;
cSuccess = child.stop();
if (!cSuccess) {
Log.e(child.getClass().getSimpleName() + " failed to stop!");
success = false;
}
}
}
return success;
}
/**
* Terminates this manager. If the manager returns false on this method
* then the manager failed to shut down and resources may not have been
* cleaned up. This will terminate all children automatically.
* @return TRUE if termination was successful, FALSE otherwise
*/
@Override
public boolean terminate() {
boolean success = super.terminate();
synchronized (children) {
for (Service child : children) {
if (!child.terminate())
success = false;
}
}
return success;
}
/**
* Determines whether or not this manager is operational
* @return TRUE if this manager is operational, FALSE otherwise
*/
@Override
public boolean isOperational() {
boolean success = true;
synchronized (children) {
for (Service child : children) {
if (!child.isOperational())
success = false;
}
}
return success;
}
/**
* Adds a child to the manager's list of children. This creates a tree of
* managers that allows information to propogate freely through the network
* in an easy way.
* @param m the manager to add as a child.
*/
public void addChildService(Service s) {
if (s == null)
throw new NullPointerException("Child service cannot be null!");
synchronized (children) {
for (Service child : children) {
if (s == child || s.equals(child))
return;
}
children.add(s);
}
}
/**
* Removes the sub-manager from the list of children
* @param m the sub-manager to remove
*/
public void removeChildService(Service s) {
if (s == null)
return;
synchronized (children) {
children.remove(s);
}
}
/**
* Returns a copied ArrayList of the children of this manager
* @return a copied ArrayList of the children of this manager
*/
public List<Service> getManagerChildren() {
synchronized (children) {
return new ArrayList<Service>(children);
}
}
}
@@ -1,122 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.control;
import java.util.function.Consumer;
import com.projectswg.common.data.BackendData;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.DataManager;
/**
* A Service is a class that does a specific job for the application
*/
public abstract class Service {
private static DataManager dataManager = null;
public Service() {
IntentManager.getInstance().initialize();
}
/**
* Initializes this service. If the service returns false on this method
* then the initialization failed and may not work as intended.
* @return TRUE if initialization was successful, FALSE otherwise
*/
public boolean initialize() {
return true;
}
/**
* Starts this service. If the service returns false on this method then
* the service failed to start and may not work as intended.
* @return TRUE if starting was successful, FALSE otherwise
*/
public boolean start() {
return true;
}
/**
* Stops the service. If the service returns false on this method then the
* service failed to stop and may not have fully locked down.
* @return TRUE if stopping was successful, FALSe otherwise
*/
public boolean stop() {
return true;
}
/**
* Terminates this service. If the service returns false on this method
* then the service failed to shut down and resources may not have been
* cleaned up.
* @return TRUE if termination was successful, FALSE otherwise
*/
public boolean terminate() {
IntentManager.getInstance().terminate();
return true;
}
/**
* Determines whether or not this service is operational
* @return TRUE if this service is operational, FALSE otherwise
*/
public boolean isOperational() {
return true;
}
@SuppressWarnings("unchecked")
protected final <T extends Intent> void registerForIntent(Class<T> c, Consumer<T> consumer) {
IntentManager.getInstance().registerForIntent(c, (i) -> consumer.accept((T) i));
}
/**
* 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
*/
public final Config getConfig(ConfigFile file) {
return dataManager.getConfig(file);
}
public BackendData getBackendData() {
return dataManager.getBackendData();
}
public static void setDataManager(DataManager dataManager) {
Service.dataManager = dataManager;
}
public static DataManager getDataManager() {
return dataManager;
}
}
@@ -33,10 +33,8 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.projectswg.common.data.SQLBuildData;
import com.projectswg.common.data.SQLBuildData.BuildInformationBuilder;
import com.projectswg.common.data.TestDetails;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.RelationalDatabase;
import com.projectswg.common.info.RelationalServerFactory;
@@ -33,9 +33,8 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.projectswg.common.data.SQLDeploymentData;
import com.projectswg.common.data.SQLDeploymentData.DeploymentInformationBuilder;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.RelationalDatabase;
import com.projectswg.common.info.RelationalServerFactory;
@@ -116,16 +116,16 @@ public class HeavyweightBackendData implements BackendData {
try (BuildHistoryTable buildTable = new BuildHistoryTable(db)) {
for (SQLBuildData info : buildTable.getBuildHistory(server.getName())) {
ServerBuildData build = createBuildFromInfo(server, info);
fetchDeploymentHistory(db, server, build);
server.addBuild(build);
}
}
fetchDeploymentHistory(db, server);
}
private void fetchDeploymentHistory(RelationalDatabase db, ServerServerData server, ServerBuildData build) {
private void fetchDeploymentHistory(RelationalDatabase db, ServerServerData server) {
try (DeploymentTable deploymentTable = new DeploymentTable(db)) {
for (SQLDeploymentData info : deploymentTable.getDeployments(server.getName())) {
ServerDeploymentData deployment = createDeploymentFromInfo(build, info);
ServerDeploymentData deployment = createDeploymentFromInfo(server, info);
server.addDeployment(deployment);
}
}
@@ -151,8 +151,8 @@ public class HeavyweightBackendData implements BackendData {
return build;
}
private ServerDeploymentData createDeploymentFromInfo(ServerBuildData build, SQLDeploymentData info) {
ServerDeploymentData deployment = new ServerDeploymentData(info.getId(), build);
private ServerDeploymentData createDeploymentFromInfo(ServerServerData server, SQLDeploymentData info) {
ServerDeploymentData deployment = new ServerDeploymentData(info.getId(), server.getBuild(info.getBuildId()));
deployment.setStartTime(info.getStartTime());
deployment.setEndTime(info.getEndTime());
return deployment;
@@ -34,7 +34,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.RelationalDatabase;
import com.projectswg.common.info.RelationalServerFactory;
-183
View File
@@ -1,183 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.File;
import java.util.Map;
/**
* Reads and stores configuration data from a file
*/
public class Config {
private final ConfigData configData;
/**
* Initilizes the Config and loads the data in the file
* @param filename the file to load
*/
public Config(String filename) {
this(new File(filename));
}
/**
* Initilizes the Config and loads the data in the file
* @param file the file to load
*/
public Config(File file) {
if (!file.exists() || !file.isFile())
throw new IllegalArgumentException("Filepath does not point to a valid file!");
configData = new ConfigData(file);
load();
save();
}
/**
* Determines whether or not the key-value pair exists in the config
* @param key the key to check
* @return TRUE if the key-value pair exists, FALSE otherwise
*/
public boolean containsKey(String key) {
return configData.containsKey(key);
}
/**
* Gets the parameter with the specified key. If no such parameter exists,
* it returns the default
* @param key the key to get the value for
* @param def the default value
* @return the value represented by the key, or the default value
*/
public String getString(String key, String def) {
if (!containsKey(key)) {
setProperty(key, def);
return def;
}
return configData.get(key);
}
/**
* Gets the parameter with the specified key. If no such parameter exists,
* or if the value isn't an integer then it returns the default
* @param key the key to get the value for
* @param def the default value
* @return the value represented by the key, or the default value
*/
public int getInt(String key, int def) {
try {
return Integer.parseInt(getString(key, Integer.toString(def)));
} catch (NumberFormatException e) {
return def;
}
}
/**
* Gets the parameter with the specified key. If no such parameter exists,
* or if the value isn't a double then it returns the default
* @param key the key to get the value for
* @param def the default value
* @return the value represented by the key, or the default value
*/
public double getDouble(String key, double def) {
try {
return Double.parseDouble(getString(key, Double.toString(def)));
} catch (NumberFormatException e) {
return def;
}
}
/**
* Gets the parameter with the specified key. If no such parameter exists,
* or if the value isn't a boolean then it returns the default
* @param key the key to get the value for
* @param def the default value
* @return the value represented by the key, or the default value
*/
public boolean getBoolean(String key, boolean def) {
String val = getString(key, def?"true":"false");
if (val.equalsIgnoreCase("true") || val.equals("1"))
return true;
if (val.equalsIgnoreCase("false") || val.equals("0"))
return false;
return def;
}
/**
* Sets the property value for the specified key
* @param key the key of the value to set
* @param value the value to set
*/
public void setProperty(String key, String value) {
configData.put(key, value);
save();
}
/**
* Sets the property value for the specified key
* @param key the key of the value to set
* @param value the value to set
*/
public void setProperty(String key, int value) {
setProperty(key, Integer.toString(value));
}
/**
* Sets the property value for the specified key
* @param key the key of the value to set
* @param value the value to set
*/
public void setProperty(String key, boolean value) {
setProperty(key, value ? "true" : "false");
}
/**
* Sets the property value for the specified key
* @param key the key of the value to set
* @param value the value to set
*/
public void setProperty(String key, double value) {
setProperty(key, Double.toString(value));
}
/**
* Reloads the config data from the file
* @return TRUE if the data was successfully loaded, FALSE otherwise
*/
public Map<String, String> load() {
return configData.load();
}
/**
* Saves the config data to the file
* @return TRUE if the data was successfully saved, FALSE otherwise
*/
public boolean save() {
return configData.save();
}
}
@@ -1,152 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
class ConfigData {
private final DateFormat FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss zzz");
private final Map<String, String> data;
private final File file;
public ConfigData(File file) {
this.data = new TreeMap<>();
this.file = file;
}
public boolean containsKey(String key) {
synchronized (data) {
return data.containsKey(key);
}
}
public String get(String key) {
synchronized (data) {
return data.get(key);
}
}
public String put(String key, String value) {
synchronized (data) {
return data.put(key, value);
}
}
/**
* @return null on an I/O failure, an empty {@code Map} on the first load and
* a populated {@code Map} when called afterwards
*/
public Map<String, String> load() {
Map<String, String> delta = new HashMap<>();
BufferedReader reader = null;
synchronized (data) {
delta.putAll(data); // Copy the current data
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
String line = reader.readLine();
while (line != null) {
loadLine(line);
line = reader.readLine();
}
} catch (IOException e) {
Log.e(e);
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
return null;
}
}
}
for(Entry<String, String> entry : data.entrySet())
delta.remove(entry.getKey(), entry.getValue());
}
return delta;
}
public boolean save() {
BufferedWriter writer = null;
synchronized (data) {
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
writer.write("# "+FORMAT.format(System.currentTimeMillis()));
writer.newLine();
for (Entry <String, String> e : data.entrySet()) {
writer.write(e.getKey() + "=" + e.getValue());
writer.newLine();
}
return true;
} catch (IOException e) {
Log.e(e);
return false;
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
}
}
}
}
}
private void loadLine(String line) {
String beforeComment = line;
if (line.contains("#"))
beforeComment = line.substring(0, line.indexOf('#'));
if (!beforeComment.contains("="))
return;
String key = beforeComment.substring(0, beforeComment.indexOf('='));
String val = beforeComment.substring(key.length()+1);
synchronized (data) {
data.put(key, val);
}
}
}
@@ -35,6 +35,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.data.BackendData;
import com.projectswg.common.data.HeavyweightBackendData;
import com.projectswg.common.debug.Log;
import com.projectswg.common.debug.log_wrapper.FileLogWrapper;
public class HeavyweightDataManager implements DataManager {
@@ -51,8 +53,13 @@ public class HeavyweightDataManager implements DataManager {
if (initialized.getAndSet(true))
return;
initializeConfig();
if (getConfig(ConfigFile.LIGHTSPEED).getBoolean("ENABLE-LOGGING", true))
Log.start();
if (getConfig(ConfigFile.LIGHTSPEED).getBoolean("ENABLE-LOGGING", true)) {
try {
Log.addWrapper(new FileLogWrapper(new File("log.txt")));
} catch (IOException e) {
Log.e(e);
}
}
}
public synchronized void terminate() {
@@ -50,7 +50,6 @@ public class LightweightDataManager implements DataManager {
if (initialized.getAndSet(true))
return;
setupConfigs();
Log.start();
}
public synchronized void terminate() {
-258
View File
@@ -1,258 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Log {
private static final DateFormat LOG_FORMAT = new SimpleDateFormat("dd-MM-yy HH:mm:ss.SSS");
private static final Log LOG = new Log("log.txt", LogLevel.VERBOSE);
private final File file;
private BufferedWriter writer;
private LogLevel level;
private boolean open;
private Log(String filename, LogLevel level) {
this.file = new File(filename);
this.level = level;
open = false;
}
private synchronized void open() throws IOException {
if (!open)
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
open = true;
}
private synchronized void close() throws IOException {
if (open)
writer.close();
open = false;
}
private synchronized void write(String str) throws IOException {
if (open) {
writer.write(str);
writer.newLine();
writer.flush();
}
}
private synchronized void setLevel(LogLevel level) {
this.level = level;
}
private synchronized LogLevel getLevel() {
return level;
}
protected static final void start() {
try {
LOG.open();
} catch (IOException e) {
Log.e(e);
}
}
protected static final void stop() {
try {
LOG.close();
} catch (IOException e) {
Log.e(e);
}
}
/**
* Sets the minimum level for logs to be reported. This is according to the
* following order: VERBOSE, DEBUG, INFO, WARNING, ERROR, then ASSERT.
* @param level the minimum log level, inclusively. Default is VERBOSE
*/
public static final void setLogLevel(LogLevel level) {
synchronized (LOG) {
LOG.setLevel(level);
}
}
/**
* Logs the string to the server log file, formatted to display the log
* severity, time and message.
* @param level the log level of this message between VERBOSE and ASSERT
* @param tag the tag to use for the log
* @param str the format string for the log
* @param args the string format arguments, if specified
*/
public static final void log(LogLevel level, String str, Object ... args) {
synchronized (LOG) {
if (LOG.getLevel().compareTo(level) > 0)
return;
}
String date;
synchronized (LOG_FORMAT) {
date = LOG_FORMAT.format(System.currentTimeMillis());
}
String logStr = String.format(str, args);
String log = String.format("%s %c: %s", date, level.getChar(), logStr);
if (level.compareTo(LogLevel.WARN) >= 0)
System.err.println(date + " " + level.getChar() + ": " + logStr);
else
System.out.println(date + " " + level.getChar() + ": " + logStr);
synchronized (LOG) {
try {
LOG.write(log);
} catch (IOException e) {
Log.e(e);
}
}
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as VERBOSE, as well as the time and message.
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void v(String message, Object ... args) {
log(LogLevel.VERBOSE, message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as DEBUG, as well as the time and message.
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void d(String message, Object ... args) {
log(LogLevel.DEBUG, message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as INFO, as well as the time and message.
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void i(String message, Object ... args) {
log(LogLevel.INFO, message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as WARN, as well as the time and message.
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void w(String message, Object ... args) {
log(LogLevel.WARN, message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as WARN, as well as the time, and tag.
* @param exception the exception to print
*/
public static final void w(Throwable exception) {
printException(LogLevel.WARN, exception);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as ERROR, as well as the time and message.
* @param tag the tag to use for the log
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void e(String message, Object ... args) {
log(LogLevel.ERROR, message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ERROR, as well as the time, and tag.
* @param exception the exception to print
*/
public static final void e(Throwable exception) {
printException(LogLevel.ERROR, exception);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as ASSERT, as well as the time and message.
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void a(String message, Object ... args) {
log(LogLevel.ASSERT, message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ASSERT, as well as the time, and tag.
* @param exception the exception to print
*/
public static final void a(Throwable exception) {
printException(LogLevel.ASSERT, exception);
}
private static final void printException(LogLevel level, Throwable exception) {
synchronized (LOG) {
log(level, "Exception in thread\"%s\" %s: %s", Thread.currentThread().getName(), exception.getClass().getName(), exception.getMessage());
log(level, "Caused by: %s: %s", exception.getClass(), exception.getMessage());
for (StackTraceElement e : exception.getStackTrace()) {
log(level, " " + e.toString());
}
}
}
public static enum LogLevel {
VERBOSE ('V'),
DEBUG ('D'),
INFO ('I'),
WARN ('W'),
ERROR ('E'),
ASSERT ('A');
private char c;
LogLevel(char c) {
this.c = c;
}
public char getChar() { return c; }
}
}
@@ -1,190 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.Closeable;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
public abstract class RelationalDatabase implements Closeable {
private DatabaseMetaData metaData;
private Connection connection;
private boolean online;
protected RelationalDatabase(String jdbcClass, String url) {
try {
Class.forName(jdbcClass);
initialize(url);
} catch (ClassNotFoundException e) {
Log.e(e);
online = false;
}
}
protected RelationalDatabase(String jdbcClass, String url, String user, String pass) {
try {
Class.forName(jdbcClass);
initialize(url, user, pass);
} catch (ClassNotFoundException e) {
Log.e(e);
online = false;
}
}
public RelationalDatabase(String jdbcClass, String url, String user, String pass, String params) {
try {
Class.forName(jdbcClass);
if (params != null && params.length() > 0)
url += "?" + params;
initialize(url, user, pass);
} catch (ClassNotFoundException e) {
Log.e(e);
online = false;
}
}
public RelationalDatabase(String jdbcClass, String type, String host, String db, String user, String pass, String params) {
try {
Class.forName(jdbcClass);
String url = "jdbc:" + type + "://" + host + "/" + db;
if (params != null && params.length() > 0)
url += "?" + params;
initialize(url, user, pass);
} catch (ClassNotFoundException e) {
Log.e(e);
online = false;
}
}
private void initialize(String url) {
try {
connection = DriverManager.getConnection(url);
metaData = connection.getMetaData();
online = true;
} catch (SQLException e) {
Log.e("RelationalDatabase", "Failed to initialize relational database! %s - %s", e.getClass().getSimpleName(), e.getMessage());
online = false;
}
}
private void initialize(String url, String user, String pass) {
try {
connection = DriverManager.getConnection(url, user, pass);
metaData = connection.getMetaData();
online = true;
} catch (SQLException e) {
Log.e("RelationalDatabase", "Failed to initialize relational database! %s - %s", e.getClass().getSimpleName(), e.getMessage());
online = false;
}
}
public void close() {
try {
connection.close();
online = false;
} catch (SQLException e) {
Log.e(e);
}
}
public boolean isOnline() {
if (connection == null)
return false;
try {
return online && !connection.isClosed();
} catch (SQLException e) {
return online;
}
}
public PreparedStatement prepareStatement(String sql) {
if (connection == null) {
Log.e("RelationalDatabase", "Cannot prepare statement! Connection is null");
return null;
}
try {
return connection.prepareStatement(sql);
} catch (SQLException e) {
Log.e(e);
return null;
}
}
public ResultSet executeQuery(String query) {
if (connection == null)
return null;
Statement s = null;
try {
s = connection.createStatement();
s.execute(query);
try {
s.closeOnCompletion();
} catch (SQLFeatureNotSupportedException e) {
// It was worth a shot
}
return s.getResultSet();
} catch (SQLException e) {
Log.e(e);
if (s != null) {
try { s.close(); } catch (SQLException ex) { }
}
return null;
}
}
public int updateQuery(String query) {
if (connection == null)
return 0;
try {
try (Statement s = connection.createStatement()) {
return s.executeUpdate(query);
}
} catch (SQLException e) {
Log.e(e);
return 0;
}
}
public boolean isTable(String name) {
if (metaData == null)
return false;
try {
return metaData.getTables(null, null, name, null).next();
} catch (SQLException e) {
return false;
}
}
}
@@ -1,445 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class RelationalServerData extends RelationalDatabase {
private static final Charset ASCII = Charset.forName("ASCII");
private static final String META_TABLE = "__server_table_metadata__";
private final PreparedStatement getTableMetadata;
private final PreparedStatement updateTableMetadata;
private final PreparedStatement insertTableMetadata;
public RelationalServerData(String file) {
super("org.sqlite.JDBC", "jdbc:sqlite:" + file);
/*
* GREATLY speeds up INSERT speeds. This makes it so SQLite will not
* wait until the previous write finishes before starting to write the
* next INSERT. All imports will only take milliseconds. A caveat of
* this is that if the power ever cuts or the application is force
* killed it may result in database corruption.
*/
updateQuery("PRAGMA synchronous=OFF");
updateQuery("CREATE TABLE IF NOT EXISTS "+META_TABLE+" (table_name TEXT, last_imported INTEGER)");
getTableMetadata = prepareStatement("SELECT * FROM "+META_TABLE+" WHERE table_name=?");
updateTableMetadata = prepareStatement("UPDATE "+META_TABLE+" SET last_imported=? WHERE table_name=?");
insertTableMetadata = prepareStatement("INSERT INTO "+META_TABLE+" (table_name, last_imported) VALUES (?, ?)");
}
public boolean linkTableWithSdb(String table, String filepath) {
File sdb = new File(filepath);
if (!sdb.isFile())
return false;
if (testLastModified(table, sdb) || testMasterSdbModified(table, sdb)) {
updateQuery("DROP TABLE IF EXISTS " + table);
importFromSdb(table, sdb);
updateLastImported(table, System.currentTimeMillis());
}
return true;
}
private boolean testLastModified(String table, File sdb) {
return sdb.lastModified() > getLastImported(table);
}
private boolean testMasterSdbModified(String table, File sdb) {
if (!sdb.getName().endsWith(".msdb"))
return false;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(sdb), ASCII))) {
reader.readLine();
reader.readLine();
String line;
while ((line = reader.readLine()) != null) {
if (testLastModified(table, new File(sdb.getParent(), line.substring(0, line.indexOf('\t')))))
return true;
}
} catch (IOException e) {
Log.e(e);
}
return false;
}
/**
* Inserts a record with the specified information into the database
* @param table the table to insert into
* @param columns the columns to insert into
* @param params the parameters to insert
* @return TRUE on success, FALSE on failure
* @throws SQLException upon error
*/
public boolean insert(String table, String [] columns, Object ... params) throws SQLException {
StringBuilder columnStr = new StringBuilder("");
StringBuilder valuesStr = new StringBuilder("");
if (columns == null)
columns = getColumnsForTable(table);
for (int i = 0; i < columns.length; i++) {
columnStr.append(columns[i]);
valuesStr.append('?');
if (i+1 < columns.length) {
columnStr.append(',');
valuesStr.append(',');
}
}
final String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", table, columnStr, valuesStr);
try (PreparedStatement statement = prepareStatement(sql)) {
if (statement == null || params.length < getSqlParameterCount(sql))
return false;
assignParameters(statement, params);
return statement.executeUpdate() > 0;
}
}
/**
* Selects from the specified table with the supplied where clause, given
* the supplied parameters
* @param tables the tables to query, separated by commas
* @param columns the columns to select, null to select all
* @param where the where clause
* @param params the parameters to put into the ?s in the where clause
* @return the result set
* @throws SQLException upon error
*/
public ResultSet selectFromTable(String tables, String [] columns, String where, Object ... params) throws SQLException {
final String sql = createSelectQuery(tables, columns, where, params);
PreparedStatement statement = prepareStatement(sql);
if (statement == null || params.length < getSqlParameterCount(sql))
return null;
assignParameters(statement, params);
return statement.executeQuery();
}
private void assignParameters(PreparedStatement statement, Object ... params) throws SQLException {
for (int i = 0; i < params.length; i++) {
if (params[i] instanceof Integer || params[i] instanceof Long)
statement.setLong(i+1, ((Number) params[i]).longValue());
else if (params[i] instanceof Float || params[i] instanceof Double)
statement.setDouble(i+1, ((Number) params[i]).doubleValue());
else if (params[i] instanceof String)
statement.setString(i+1, (String) params[i]);
else if (params[i] != null)
throw new IllegalArgumentException("Unknown object type: " + params[i].getClass().getSimpleName());
else
throw new NullPointerException("Parameters cannot have null elements!");
}
}
private int getSqlParameterCount(String sql) {
int ret = 0;
for (int i = 0; i < sql.length(); i++) {
if (sql.charAt(i) == '?')
ret++;
}
return ret;
}
private String createSelectQuery(String tables, String [] columns, String where, Object ... params) {
String columnStr = "*";
if (columns == null && tables.contains(",")) {
StringBuilder bldr = new StringBuilder("");
for (String table : tables.split(",")) {
bldr.append(table.trim());
bldr.append(".*, ");
}
columnStr = bldr.substring(0, columnStr.length()-2);
} else if (columns != null) {
StringBuilder bldr = new StringBuilder("");
for (String column : columns) {
bldr.append(column);
bldr.append(", ");
}
columnStr = bldr.substring(0, bldr.length()-2);
}
return "SELECT " + columnStr + " FROM " + tables + " WHERE " + where;
}
private String [] getColumnsForTable(String table) throws SQLException {
List<String> columns = new ArrayList<>();
try (ResultSet set = executeQuery("PRAGMA table_info('"+table+"')")) {
int colInd = set.findColumn("name");
while (set.next()) {
columns.add(set.getString(colInd));
}
}
return columns.toArray(new String[columns.size()]);
}
private long getLastImported(String table) {
synchronized (getTableMetadata) {
ResultSet set = null;
try {
getTableMetadata.setString(1, table);
set = getTableMetadata.executeQuery();
if (set.next())
return set.getLong("last_imported");
} catch (SQLException e) {
Log.e(e);
} finally {
if (set != null) {
try {
set.close();
} catch (SQLException e) {
Log.e(e);
}
}
}
return -1;
}
}
private void updateLastImported(String table, long lastImported) {
synchronized (updateTableMetadata) {
try {
updateTableMetadata.setLong(1, lastImported);
updateTableMetadata.setString(2, table);
if (updateTableMetadata.executeUpdate() > 0)
return;
} catch (SQLException e) {
Log.e(e);
return;
}
}
synchronized (insertTableMetadata) {
try {
insertTableMetadata.setString(1, table);
insertTableMetadata.setLong(2, lastImported);
insertTableMetadata.executeUpdate();
} catch (SQLException e) {
Log.e(e);
}
}
}
private boolean importFromSdb(String table, File sdb) {
try (TableReader reader = new TableReader(table, sdb)) {
Log.i("RelationalServerData", "Importing sdb... '" + sdb + "'");
if (sdb.getName().endsWith(".msdb"))
reader.readMaster();
else
reader.readNormal();
return true;
} catch (IOException e) {
Log.e(e);
} catch (SQLException e) {
Log.e(e);
} catch (IllegalArgumentException e) {
Log.e("RelationalServerData", "Invalid file format. Aborting read of %s! Message: %s", sdb, e.getMessage());
}
return false;
}
private class TableReader implements Closeable {
private final String table;
private final File file;
private String [] columnNames;
private String [] columnTypes;
private PreparedStatement insert;
public TableReader(String table, File file) {
this.table = table;
this.file = file;
this.columnNames = null;
this.columnTypes = null;
this.insert = null;
}
@Override
public void close() {
if (insert != null) {
try {
insert.close();
} catch (SQLException e) {
Log.e(e);
}
}
}
public void readNormal() throws IOException, SQLException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
readNormalRemainder(reader, 1);
}
}
public void readMaster() throws SQLException, IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
int lineNum = 1;
readLine(reader.readLine(), lineNum++);
readLine(reader.readLine(), lineNum++);
readMasterRemainder(reader, lineNum);
}
}
private void readSlave() throws IOException, SQLException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
int lineNum = 3;
reader.readLine();
reader.readLine(); // Skip column names and types
readNormalRemainder(reader, lineNum);
}
}
private void readMasterRemainder(BufferedReader reader, int lineNum) throws IOException, SQLException {
String line;
while ((line = reader.readLine()) != null) {
String [] parts = line.split("\t");
if (parts.length != 2) {
Log.e("RelationalServerData", "Invalid line [%d]: %s", lineNum, line);
continue;
}
boolean load = Boolean.parseBoolean(parts[1]);
if (load) {
File sdb = new File(file.getParent(), parts[0]);
Log.i("RelationalServerData", " Importing sdb... '" + sdb + "'");
if (!sdb.isFile()) {
Log.e("RelationalServerData", " Failed to import sdb! File is not file or does not exist");
continue;
}
@SuppressWarnings("resource") // This closes the database.. we don't want to do that yet
TableReader slave = new TableReader(table, sdb);
slave.columnNames = columnNames;
slave.columnTypes = columnTypes;
slave.insert = insert;
slave.readSlave();
}
}
}
private void readNormalRemainder(BufferedReader reader, int lineNum) throws IOException, SQLException {
String line;
while ((line = reader.readLine()) != null) {
readLine(line, lineNum++);
}
if (insert != null)
insert.executeBatch();
}
private void readLine(String line, int lineNum) throws SQLException {
if (line == null)
return;
switch (lineNum) {
case 1:
columnNames = fastTabSplit(line);
break;
case 2:
columnTypes = fastTabSplit(line);
createTable();
createPreparedStatement();
break;
default:
generateInsert(fastTabSplit(line), lineNum);
break;
}
}
private String [] fastTabSplit(String str) {
int count = 1;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '\t') {
count++;
}
}
String [] tabs = new String[count];
int tabInd = 0;
int prevInd = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '\t') {
tabs[tabInd++] = str.substring(prevInd, i);
prevInd = i+1;
}
}
if (prevInd < str.length())
tabs[tabInd++] = str.substring(prevInd);
return tabs;
}
private void createTable() {
if (columnNames.length != columnTypes.length)
throw new IllegalArgumentException("Names length and types length mismatch");
StringBuilder sql = new StringBuilder("CREATE TABLE "+table+" (");
for (int i = 0; i < columnNames.length; i++) {
if (i > 0)
sql.append(", ");
sql.append(columnNames[i]);
sql.append(' ');
sql.append(columnTypes[i]);
}
sql.append(')');
updateQuery(sql.toString());
}
private void createPreparedStatement() {
StringBuilder sql = new StringBuilder("INSERT INTO " + table + " VALUES (");
for (int i = 0; i < columnNames.length; i++) {
if (i > 0)
sql.append(", ");
sql.append('?');
}
sql.append(')');
insert = prepareStatement(sql.toString());
}
private void generateInsert(String [] data, int line) throws SQLException {
if (columnTypes.length != data.length) {
Log.e("RelationalServerData", "Could not load record: Types length and data length mismatch. Line: " + line);
return;
}
int column = 0;
try {
for (int i = 0; i < data.length; i++, column++) {
if (columnTypes[i].startsWith("TEXT"))
insert.setString(i+1, data[i]);
else if (columnTypes[i].startsWith("REAL"))
insert.setDouble(i+1, Double.parseDouble(data[i]));
else if (columnTypes[i].startsWith("INTEGER"))
insert.setLong(i+1, Long.parseLong(data[i]));
else
throw new SQLException("Data type unsupported by sdb/sqlite! Type: " + columnTypes[i]);
}
insert.addBatch();
} catch (NumberFormatException e) {
Log.e("RelationalServerData", "Could not load record: Record has invalid data. Line: " + line + " Column: " + column);
}
}
}
}
@@ -1,271 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class RelationalServerFactory {
private static final RelationalServerFactory INSTANCE = new RelationalServerFactory();
private static final String BASE_PATH = "data" + File.separator;
private static final Map <String, Object> FILE_LOAD_LOCKING = new HashMap<>();
public static RelationalServerData getServerData(String file, String ... tables) {
return INSTANCE.getData(file, tables);
}
public static RelationalServerData getServerDatabase(String file) {
return INSTANCE.getDatabase(file);
}
private RelationalServerData getData(String file, String ... tables) {
if (!file.endsWith(".db"))
throw new IllegalArgumentException("File path for database must end in .db!");
file = file.replace('/', File.separatorChar);
final Object lock = getFileLocking(file);
synchronized (lock) {
File f = new File(BASE_PATH + file);
RelationalServerData data = new RelationalServerData(BASE_PATH + file);
if (loadServerData(data, f, tables))
return data;
return null;
}
}
private boolean loadServerData(RelationalServerData data, File file, String ... tables) {
File parent = file.getParentFile();
try {
if (loadTables(data, parent, tables))
return true;
data.close();
} catch (Exception e) {
Log.e(e);
data.close();
}
return false;
}
private RelationalServerData getDatabase(String file) {
if (!file.endsWith(".db"))
throw new IllegalArgumentException("File path for database must end in .db!");
final Object lock = getFileLocking(file);
synchronized (lock) {
File f = new File(BASE_PATH + file);
RelationalServerData data = new RelationalServerData(BASE_PATH + file);
try {
String [] commands = getCommandsFromSchema(f.getPath().substring(0, f.getPath().length()-3) + ".sql");
ParserData parserData = new ParserData();
for (String command : commands)
executeCommand(data, command, parserData);
return data;
} catch (Exception e) {
Log.e(e);
}
data.close();
return null;
}
}
private boolean loadTables(RelationalServerData data, File parent, String [] tables) {
for (String table : tables) {
table = table.replace('/', File.separatorChar);
String path = generatePath(parent, table);
table = path.substring(path.lastIndexOf(File.separatorChar)+1, path.lastIndexOf('.'));
if (!data.linkTableWithSdb(table, path))
return false;
}
return true;
}
private String generatePath(File parent, String table) {
String base;
if (table.contains(File.separator))
base = BASE_PATH + table;
else
base = parent.getPath() + File.separator + table;
if (new File(base + ".msdb").isFile())
return base + ".msdb";
return base + ".sdb";
}
private void executeCommand(RelationalServerData data, String command, ParserData parserData) {
command = command.trim();
if (command.startsWith("SELECT") && parserData.getConditional()) {
try (ResultSet set = data.executeQuery(command)) {
} catch (SQLException e) {
Log.e(e);
}
} else if (command.startsWith("IF")) { // VERY SIMPLE 'if' logic, no parenthesis and no AND/OR's - expects 3 arguments: <num/var> <op> <num/var>
parserData.addConditional(evaluateIf(data, command.substring(2).trim()));
} else if (command.startsWith("ENDIF")) {
parserData.unwrapLastConditional();
} else if (parserData.getConditional()) {
data.updateQuery(command);
}
}
private boolean evaluateIf(RelationalServerData data, String statement) {
String [] args = statement.split(" ", 3);
if (args.length != 3) {
Log.e("Invalid IF statement: %s", statement);
return false;
}
double num1 = parseToNumber(data, args[0]);
String comparator = args[1];
double num2 = parseToNumber(data, args[2]);
switch (comparator) {
case "<": return num1 < num2;
case ">": return num1 > num2;
case "=": return num1 == num2;
case "==": return num1 == num2;
case "<=": return num1 <= num2;
case ">=": return num1 >= num2;
default:
Log.e("Invalid comparator: %s", comparator);
return false;
}
}
private double parseToNumber(RelationalServerData data, String str) {
if (str.equals("user_version")) {
ResultSet set = data.executeQuery("PRAGMA user_version");
try {
if (set.next())
return set.getDouble(1);
else
Log.e("Variable 'user_version' has not been set!");
} catch (SQLException e) {
Log.e(e);
}
} else {
try {
return Double.parseDouble(str);
} catch (NumberFormatException e) {
Log.e("Number '%s' is not a valid number!", str);
}
}
return Double.NaN;
}
private String [] getCommandsFromSchema(String schema) throws IOException {
String command;
try (InputStream input = new FileInputStream(new File(schema))) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(input.available());
byte [] block = new byte[1024];
while (input.available() > 0) {
int size = input.read(block);
baos.write(block, 0, size);
}
command = new String(baos.toByteArray(), Charset.forName("ASCII"));
}
return command.split(";");
}
private Object getFileLocking(String file) {
synchronized (FILE_LOAD_LOCKING) {
Object o = FILE_LOAD_LOCKING.get(file);
if (o == null)
FILE_LOAD_LOCKING.put(file, o = new Object());
return o;
}
}
private static class ParserData {
private RecursiveBoolean conditionalValue;
public ParserData() {
conditionalValue = null;
}
public void addConditional(boolean val) {
if (conditionalValue == null)
conditionalValue = new RecursiveBoolean(val);
else
conditionalValue.createRecursive(val);
}
public void unwrapLastConditional() {
if (conditionalValue != null && conditionalValue.unwrapLast())
conditionalValue = null;
}
public boolean getConditional() {
if (conditionalValue == null)
return true;
return conditionalValue.get();
}
}
private static class RecursiveBoolean {
private final boolean val;
private RecursiveBoolean recursive;
public RecursiveBoolean(boolean val) {
this.val = val;
this.recursive = null;
}
public boolean get() {
if (recursive != null)
return val && recursive.get();
return val;
}
public RecursiveBoolean createRecursive(boolean val) {
if (recursive != null)
return recursive.createRecursive(val);
return (recursive = new RecursiveBoolean(val));
}
public boolean unwrapLast() {
RecursiveBoolean recur = this;
while (recur.recursive != null && recur.recursive.recursive != null)
recur = recur.recursive;
if (recur != null && recur.recursive != null) {
recur.recursive = null;
return true;
}
return true;
}
}
}
@@ -1,237 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
public class NetBuffer {
public static final Charset ASCII = Charset.forName("UTF-8");
public static final Charset UNICODE = Charset.forName("UTF-16LE");
private final ByteBuffer data;
private final int size;
private NetBuffer(ByteBuffer data) {
this.data = data;
this.size = data.array().length;
}
public static final NetBuffer allocate(int size) {
return new NetBuffer(ByteBuffer.allocate(size));
}
public static final NetBuffer wrap(byte [] data) {
return new NetBuffer(ByteBuffer.wrap(data));
}
public static final NetBuffer wrap(ByteBuffer data) {
return new NetBuffer(data);
}
public int remaining() {
return data.remaining();
}
public int position() {
return data.position();
}
public void position(int position) {
data.position(position);
}
public void seek(int relative) {
data.position(data.position()+relative);
}
public ByteBuffer getBuffer() {
return data;
}
public void addBoolean(boolean b) {
data.put(b ? (byte)1 : (byte)0);
}
public void addAscii(String s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putShort((short)s.length());
data.put(s.getBytes(ASCII));
}
public void addAscii(char [] s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putShort((short)s.length);
ByteBuffer bb = ASCII.encode(CharBuffer.wrap(s));
byte [] bData = new byte[bb.limit()];
bb.get(bData);
data.put(bData);
}
public void addUnicode(String s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putInt(s.length());
data.put(s.getBytes(UNICODE));
}
public void addLong(long l) {
data.order(ByteOrder.LITTLE_ENDIAN).putLong(l);
}
public void addInt(int i) {
data.order(ByteOrder.LITTLE_ENDIAN).putInt(i);
}
public void addFloat(float f) {
data.putFloat(f);
}
public void addShort(int i) {
data.order(ByteOrder.LITTLE_ENDIAN).putShort((short)i);
}
public void addNetLong(long l) {
data.order(ByteOrder.BIG_ENDIAN).putLong(l);
}
public void addNetInt(int i) {
data.order(ByteOrder.BIG_ENDIAN).putInt(i);
}
public void addNetShort(int i) {
data.order(ByteOrder.BIG_ENDIAN).putShort((short)i);
}
public void addByte(int b) {
data.put((byte)b);
}
public void addArray(byte [] b) {
addShort(b.length);
data.put(b);
}
public void addRawArray(byte [] b) {
data.put(b);
}
public boolean getBoolean() {
return getByte() == 1 ? true : false;
}
public String getAscii() {
data.order(ByteOrder.LITTLE_ENDIAN);
short length = data.getShort();
if (length > data.remaining())
return "";
byte [] str = new byte[length];
data.get(str);
return new String(str, ASCII);
}
public String getUnicode() {
data.order(ByteOrder.LITTLE_ENDIAN);
int length = data.getInt() * 2;
if (length > data.remaining())
return "";
byte [] str = new byte[length];
data.get(str);
return new String(str, UNICODE);
}
public byte getByte() {
return data.get();
}
public short getShort() {
return data.order(ByteOrder.LITTLE_ENDIAN).getShort();
}
public int getInt() {
return data.order(ByteOrder.LITTLE_ENDIAN).getInt();
}
public float getFloat() {
return data.getFloat();
}
public long getLong() {
return data.order(ByteOrder.LITTLE_ENDIAN).getLong();
}
public short getNetShort() {
return data.order(ByteOrder.BIG_ENDIAN).getShort();
}
public int getNetInt() {
return data.order(ByteOrder.BIG_ENDIAN).getInt();
}
public long getNetLong() {
return data.order(ByteOrder.BIG_ENDIAN).getLong();
}
public byte [] getArray() {
byte [] bData = new byte[getShort()];
data.get(bData);
return bData;
}
public byte [] getArray(int size) {
byte [] bData = new byte[size];
data.get(bData);
return bData;
}
public byte [] array() {
return data.array();
}
public int size() {
return size;
}
public byte [] copyArray() {
return copyArray(0, size);
}
public byte [] copyArray(int offset, int length) {
if (length < 0)
throw new IllegalArgumentException("Length cannot be less than 0!");
if (offset+length > size)
throw new IllegalArgumentException("Length extends past the end of the array!");
byte [] ret = new byte[length];
System.arraycopy(array(), offset, ret, 0, length);
return ret;
}
}
@@ -1,435 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class NetBufferStream extends OutputStream {
private final Object expansionMutex;
private final Object bufferMutex;
private NetBuffer buffer;
private int capacity;
private int size;
private int mark;
public NetBufferStream() {
this(1024);
}
public NetBufferStream(int size) {
if (size <= 0)
throw new NegativeArraySizeException("Size cannot be less than or equal to 0!");
this.expansionMutex = new Object();
this.bufferMutex = new Object();
this.buffer = NetBuffer.allocate(size);
this.capacity = size;
this.size = 0;
this.mark = 0;
}
@Override
public void close() {
reset();
}
@Override
public void flush() {
}
/**
* Sets the mark to the buffer's current position
*/
public void mark() {
synchronized (bufferMutex) {
mark = buffer.position();
}
}
/**
* Rewinds the buffer to the previously set mark
*/
public void rewind() {
synchronized (bufferMutex) {
buffer.position(mark);
mark = 0;
}
}
/**
* Resets the buffer to the default capacity and clears all data
*/
public void reset() {
synchronized (expansionMutex) {
synchronized (bufferMutex) {
buffer = NetBuffer.allocate(1024);
capacity = 1024;
size = 0;
mark = 0;
}
}
}
@Override
public void write(int b) {
ensureCapacity(size + 1);
synchronized (bufferMutex) {
buffer.array()[size] = (byte) b;
size++;
}
}
public void write(byte [] data) {
write(data, 0, data.length);
}
public void write(byte [] data, int offset, int length) {
ensureCapacity(size + length);
synchronized (bufferMutex) {
System.arraycopy(data, offset, buffer.array(), size, length);
size += length;
}
}
public void write(ByteBuffer data) {
ensureCapacity(size + data.remaining());
synchronized (bufferMutex) {
while (data.hasRemaining()) {
buffer.array()[size++] = data.get();
}
}
}
/**
* Moves all data from the buffer's current position to position 0. This
* method also adjusts the mark to be pointing to the same data
*/
public void compact() {
synchronized (bufferMutex) {
byte [] data = buffer.array();
for (int i = buffer.position(), j = 0; i < size; ++i, ++j) {
data[j] = data[i];
}
size -= buffer.position();
mark -= buffer.position();
buffer.position(0);
}
}
public int remaining() {
synchronized (bufferMutex) {
return size - buffer.position();
}
}
public boolean hasRemaining() {
return remaining() > 0;
}
public int position() {
synchronized (bufferMutex) {
return buffer.position();
}
}
public void position(int position) {
synchronized (bufferMutex) {
buffer.position(position);
}
}
public void seek(int relative) {
synchronized (bufferMutex) {
buffer.seek(relative);
}
}
public ByteBuffer getBuffer() {
synchronized (bufferMutex) {
return buffer.getBuffer();
}
}
public boolean getBoolean() {
synchronized (bufferMutex) {
return buffer.getBoolean();
}
}
public String getAscii() {
synchronized (bufferMutex) {
return buffer.getAscii();
}
}
public String getUnicode() {
synchronized (bufferMutex) {
return buffer.getUnicode();
}
}
public byte getByte() {
synchronized (bufferMutex) {
return buffer.getByte();
}
}
public short getShort() {
synchronized (bufferMutex) {
return buffer.getShort();
}
}
public int getInt() {
synchronized (bufferMutex) {
return buffer.getInt();
}
}
public float getFloat() {
synchronized (bufferMutex) {
return buffer.getFloat();
}
}
public long getLong() {
synchronized (bufferMutex) {
return buffer.getLong();
}
}
public short getNetShort() {
synchronized (bufferMutex) {
return buffer.getNetShort();
}
}
public int getNetInt() {
synchronized (bufferMutex) {
return buffer.getNetInt();
}
}
public long getNetLong() {
synchronized (bufferMutex) {
return buffer.getNetLong();
}
}
public byte[] getArray() {
synchronized (bufferMutex) {
return buffer.getArray();
}
}
public byte[] getArray(int size) {
synchronized (bufferMutex) {
return buffer.getArray(size);
}
}
public void getList(NumericalIterator ni) {
int size = getInt();
for (int i = 0; i < size; i++)
ni.onItem(i);
}
public void addBoolean(boolean b) {
ensureCapacity(size+1);
synchronized (bufferMutex) {
buffer.addBoolean(b);
size++;
}
}
public void addAscii(String s) {
ensureCapacity(size+2+s.length());
synchronized (bufferMutex) {
buffer.addAscii(s);
size += 2 + s.length();
}
}
public void addAscii(char[] s) {
ensureCapacity(size+2+s.length);
synchronized (bufferMutex) {
buffer.addAscii(s);
size += 2 + s.length;
}
}
public void addUnicode(String s) {
ensureCapacity(size+4+s.length()*2);
synchronized (bufferMutex) {
buffer.addUnicode(s);
size += 4 + s.length()*2;
}
}
public void addLong(long l) {
ensureCapacity(size+8);
synchronized (bufferMutex) {
buffer.addLong(l);
size += 8;
}
}
public void addInt(int i) {
ensureCapacity(size+4);
synchronized (bufferMutex) {
buffer.addInt(i);
size += 4;
}
}
public void addFloat(float f) {
ensureCapacity(size+4);
synchronized (bufferMutex) {
buffer.addFloat(f);
size += 4;
}
}
public void addShort(int i) {
ensureCapacity(size+2);
synchronized (bufferMutex) {
buffer.addShort(i);
size += 2;
}
}
public void addNetLong(long l) {
ensureCapacity(size+8);
synchronized (bufferMutex) {
buffer.addNetLong(l);
size += 8;
}
}
public void addNetInt(int i) {
ensureCapacity(size+4);
synchronized (bufferMutex) {
buffer.addNetInt(i);
size += 4;
}
}
public void addNetShort(int i) {
ensureCapacity(size+2);
synchronized (bufferMutex) {
buffer.addNetShort(i);
size += 2;
}
}
public void addByte(int b) {
ensureCapacity(size+1);
synchronized (bufferMutex) {
buffer.addByte(b);
size++;
}
}
public void addArray(byte[] b) {
ensureCapacity(size+2+b.length);
synchronized (bufferMutex) {
buffer.addArray(b);
size += 2 + b.length;
}
}
public <T> void addList(List<T> l, ListIterable<T> r) {
addInt(l.size());
for (T t : l)
r.onItem(t);
}
public <T> void addList(Set<T> s, ListIterable<T> r) {
addInt(s.size());
for (T t : s)
r.onItem(t);
}
public <K, V> void addMap(Map<K, V> m, MapIterable<K, V> r) {
addInt(m.size());
for (Entry<K, V> e : m.entrySet())
r.onItem(e);
}
public void addRawArray(byte[] b) {
write(b);
}
public byte [] array() {
synchronized (bufferMutex) {
return buffer.array();
}
}
public int size() {
return size;
}
public int capacity() {
return capacity;
}
private void ensureCapacity(int size) {
if (size <= capacity)
return;
synchronized (expansionMutex) {
while (size > capacity)
capacity <<= 2;
synchronized (bufferMutex) {
NetBuffer buf = NetBuffer.allocate(capacity);
System.arraycopy(buffer.array(), 0, buf.array(), 0, this.size);
buf.position(buffer.position());
this.buffer = buf;
}
}
}
public static interface ListIterable<T> {
void onItem(T item);
}
public static interface MapIterable<K, V> {
void onItem(Entry<K, V> item);
}
public static interface NumericalIterator {
void onItem(int index);
}
}
@@ -1,298 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
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;
public class TCPServer {
private final CallbackManager<TCPCallback> callbackManager;
private final Map<SocketAddress, SocketChannel> sockets;
private final AtomicBoolean running;
private final InetAddress addr;
private final int port;
private final int bufferSize;
private ServerSocketChannel channel;
private TCPListener listener;
public TCPServer(int port, int bufferSize) {
this(null, port, bufferSize);
}
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;
this.channel = null;
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));
channel.configureBlocking(false);
listener.start();
}
public SocketChannel connectTo(InetAddress addr, int port) throws IOException {
return connectTo(new InetSocketAddress(addr, port));
}
public SocketChannel connectTo(InetSocketAddress sock) throws IOException {
Assert.notNull(sock);
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
if (sc == null || (!sc.isConnected() && !sc.isConnectionPending())) {
sc = SocketChannel.open(sock);
sc.configureBlocking(false);
sockets.put(sock, sc);
}
return sc;
}
}
public boolean disconnect(SocketAddress sock) {
Assert.notNull(sock);
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
Assert.notNull(sc);
sockets.remove(sock);
try {
Socket s = sc.socket();
sc.close();
callbackManager.callOnEach((callback) -> callback.onConnectionDisconnect(s, sock));
return true;
} catch (IOException e) {
Log.e(e);
return false;
}
}
}
private boolean disconnect(SocketChannel sc) {
try {
return disconnect(sc.getRemoteAddress());
} catch (IOException e) {
return false;
}
}
public boolean close() {
if (!running.getAndSet(false)) {
Assert.fail();
return false;
}
callbackManager.stop();
listener.stop();
try {
channel.close();
return true;
} catch (IOException e) {
Log.e(e);
}
return false;
}
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())
sc.write(data);
return true;
}
} catch (IOException e) {
Log.e("TCPServer", "Terminated connection with %s. Error: %s", sock.toString(), e.getMessage());
disconnect(sc);
}
}
return false;
}
public void setCallback(TCPCallback callback) {
callbackManager.setCallback(callback);
}
public interface TCPCallback {
void onIncomingConnection(Socket s);
void onConnectionDisconnect(Socket s, SocketAddress addr);
void onIncomingData(Socket s, byte [] data);
}
private class TCPListener implements Runnable {
private final ByteBuffer buffer;
private Thread thread;
private boolean running;
public TCPListener() {
buffer = ByteBuffer.allocateDirect(bufferSize);
running = false;
thread = null;
}
public void start() {
running = true;
thread = new Thread(this, "TCPServer port " + channel.socket().getLocalPort());
thread.start();
}
public void stop() {
running = false;
if (thread != null)
thread.interrupt();
thread = null;
}
public void run() {
try (Selector selector = setupSelector()) {
while (running) {
try {
selector.select();
processSelectionKeys(selector);
} catch (Exception e) {
Log.e(e);
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
break;
}
}
}
} catch (IOException e) {
Log.e(e);
}
}
private Selector setupSelector() throws IOException {
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
return selector;
}
private void processSelectionKeys(Selector selector) throws ClosedChannelException {
for (SelectionKey key : selector.selectedKeys()) {
if (!key.isValid())
continue;
if (key.isAcceptable()) {
accept(selector);
} else if (key.isReadable()) {
SelectableChannel selectable = key.channel();
if (selectable instanceof SocketChannel) {
boolean canRead = true;
while (canRead)
canRead = read(key, (SocketChannel) selectable);
}
}
}
}
private void accept(Selector selector) {
try {
while (channel.isOpen()) {
SocketChannel sc = channel.accept();
if (sc == null)
break;
SocketChannel old = sockets.get(sc.getRemoteAddress());
if (old != null)
disconnect(old);
sockets.put(sc.getRemoteAddress(), sc);
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
callbackManager.callOnEach((callback) -> callback.onIncomingConnection(sc.socket()));
}
} catch (IOException e) {
Log.e(e);
}
}
private boolean read(SelectionKey key, SocketChannel s) {
try {
buffer.position(0);
buffer.limit(bufferSize);
int n = s.read(buffer);
buffer.flip();
if (n < 0) {
key.cancel();
disconnect(s);
} else if (n > 0) {
ByteBuffer smaller = ByteBuffer.allocate(n);
smaller.put(buffer);
callbackManager.callOnEach((callback) -> callback.onIncomingData(s.socket(), smaller.array()));
return true;
}
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().toLowerCase(Locale.US).contains("connection reset"))
Log.e("TCPServer", "Connection Reset with %s", s.socket().getRemoteSocketAddress());
else if (!(e instanceof ClosedByInterruptException))
Log.e("TCPServer", e);
key.cancel();
disconnect(s);
}
return false;
}
}
}
@@ -1,172 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicBoolean;
import com.projectswg.common.callback.CallbackManager;
import com.projectswg.common.info.Log;
public class TCPSocket {
private final InetSocketAddress address;
private final TCPSocketListener listener;
private final CallbackManager<TCPSocketCallback> callbackManager;
private final int bufferSize;
private SocketChannel socket;
public TCPSocket(InetSocketAddress address, int bufferSize) {
this.address = address;
this.listener = new TCPSocketListener();
this.bufferSize = bufferSize;
this.callbackManager = new CallbackManager<>("tcpsocket-"+address, 1);
this.socket = null;
}
public InetSocketAddress getRemoteAddress() {
return address;
}
public void setCallback(TCPSocketCallback callback) {
callbackManager.setCallback(callback);
}
public void connect() {
disconnect();
try {
callbackManager.start();
socket = SocketChannel.open(address);
listener.start();
callbackManager.callOnEach((callback) -> callback.onConnected(this));
} catch (IOException e) {
Log.e(e);
callbackManager.callOnEach((callback) -> callback.onDisconnected(this));
callbackManager.stop();
}
}
public boolean disconnect() {
if (socket == null)
return true;
try {
callbackManager.stop();
socket.close();
listener.stop();
callbackManager.callOnEach((callback) -> callback.onDisconnected(this));
return true;
} catch (IOException e) {
Log.e(e);
}
return false;
}
public boolean send(ByteBuffer data) {
try {
while (data.hasRemaining()) {
if (socket == null || socket.write(data) <= 0)
return false;
}
return true;
} catch (IOException e) {
Log.e(e);
}
return false;
}
public interface TCPSocketCallback {
void onConnected(TCPSocket socket);
void onDisconnected(TCPSocket socket);
void onIncomingData(TCPSocket socket, byte [] data);
}
private class TCPSocketListener implements Runnable {
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean alive = new AtomicBoolean(false);
private Thread thread;
public void start() {
stop();
awaitTermination();
thread = new Thread(this);
running.set(true);
thread.start();
}
public void stop() {
running.set(false);
if (thread != null)
thread.interrupt();
thread = null;
}
public void awaitTermination() {
while (alive.get()) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
break;
}
}
}
public void run() {
alive.set(true);
SocketChannel sc = TCPSocket.this.socket;
ByteBuffer buf = ByteBuffer.allocateDirect(TCPSocket.this.bufferSize);
if (sc == null)
return;
try {
while (running.get()) {
buf.position(0);
buf.limit(bufferSize);
int n = sc.read(buf);
buf.flip();
if (n > 0) {
byte [] data = new byte[n];
buf.position(0);
buf.get(data, 0, n);
callbackManager.callOnEach((callback) -> callback.onIncomingData(TCPSocket.this, data));
} else
disconnect();
}
} catch (Exception e) {
disconnect();
} finally {
running.set(false);
alive.set(false);
thread = null;
}
}
}
}
@@ -27,7 +27,7 @@
***********************************************************************************/
package com.projectswg.common.network.packets;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.network.packets.post.*;
import com.projectswg.common.network.packets.request.*;
import com.projectswg.common.network.packets.response.*;
@@ -64,6 +64,11 @@ public class Packet {
return type;
}
@Override
public String toString() {
return "LightspeedPacket["+type+"]";
}
public static JSONObject createPacketJson(PacketType type) {
JSONObject json = new JSONObject();
json.put("type", type.name());
@@ -29,10 +29,9 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public class PostBuildPacket extends Packet {
public class PostBuildPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
@@ -29,11 +29,10 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
public class PostCreateServerPacket extends Packet {
public class PostCreateServerPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
private static final String DIRECTORY = "directory";
@@ -29,10 +29,9 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public class PostDeleteServerPacket extends Packet {
public class PostDeleteServerPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
@@ -29,10 +29,9 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public class PostDeployPacket extends Packet {
public class PostDeployPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
@@ -25,12 +25,21 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.info;
package com.projectswg.common.network.packets.post;
public class PostgresqlDatabase extends RelationalDatabase {
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public abstract class PostPacket extends Packet {
public PostgresqlDatabase(String host, String db, String user, String pass) {
super("org.postgresql.Driver", "postgresql", host, db, user, pass, "");
public PostPacket(JSONObject json, PacketType type) {
super(json, type);
}
public PostPacket(PacketType type) {
super(type);
}
}
@@ -29,10 +29,9 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public class PostStopBuildPacket extends Packet {
public class PostStopBuildPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
@@ -29,10 +29,9 @@ package com.projectswg.common.network.packets.post;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
public class PostStopDeployPacket extends Packet {
public class PostStopDeployPacket extends PostPacket {
private static final String SERVER_ID = "server_id";
@@ -1,51 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network.protocol;
import java.nio.ByteBuffer;
import com.projectswg.common.network.packets.Packet;
public abstract class Protocol {
private final String version;
protected Protocol(String version) {
this.version = version;
}
public abstract ByteBuffer preparePacket(Packet p);
public abstract void onIncomingData(byte [] data);
public abstract Packet getNextPacket();
public abstract int getPacketCount();
public String getVersion() {
return version;
}
}
@@ -1,41 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network.protocol;
public class ProtocolFactory {
public static Protocol createProtocol(String version) {
if (version == null)
return new AlphaProtocol();
switch (version) {
case AlphaProtocol.VERSION: return new AlphaProtocol();
default: return null;
}
}
}
@@ -1,60 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.utilities;
import java.util.concurrent.ThreadFactory;
public class ThreadUtilities {
public static ThreadFactory newThreadFactory(String pattern) {
return new CustomThreadFactory(pattern);
}
private static class CustomThreadFactory implements ThreadFactory {
private final String pattern;
private int counter;
public CustomThreadFactory(String pattern) {
this.pattern = pattern;
this.counter = 0;
}
@Override
public Thread newThread(Runnable r) {
String name;
if (pattern.contains("%d"))
name = String.format(pattern, counter++);
else
name = pattern;
return new Thread(r, name);
}
}
}
@@ -1,97 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.utilities;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import com.projectswg.common.info.Log;
public class TimeUtilities {
private static final String DATE_TIME_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
private static final TimeZone CURRENT_TIMEZONE = TimeZone.getDefault();
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
private static final DateFormat DATE_TIME_FORMATTER_CUR = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.US);
private static final DateFormat DATE_TIME_FORMATTER_UTC = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.US);
static {
DATE_TIME_FORMATTER_UTC.setTimeZone(UTC);
}
public static long getTime() {
return System.currentTimeMillis() - CURRENT_TIMEZONE.getOffset(System.currentTimeMillis());
}
public static long getTime(long offset, TimeUnit unit) {
return getTime() + unit.toMillis(offset);
}
public static String getDateStringUtc(long time) {
synchronized (DATE_TIME_FORMATTER_UTC) {
return DATE_TIME_FORMATTER_UTC.format(time);
}
}
public static String getDateString(long time) {
synchronized (DATE_TIME_FORMATTER_CUR) {
return DATE_TIME_FORMATTER_CUR.format(time);
}
}
public static long getTimeFromStringUtc(String str) {
synchronized (DATE_TIME_FORMATTER_UTC) {
try {
return DATE_TIME_FORMATTER_UTC.parse(str).getTime();
} catch (ParseException e) {
Log.e(e);
return -1;
}
}
}
public static long getTimeFromString(String str) {
synchronized (DATE_TIME_FORMATTER_CUR) {
try {
return DATE_TIME_FORMATTER_CUR.parse(str).getTime();
} catch (ParseException e) {
Log.e(e);
return -1;
}
}
}
public static long convertUtcToLocal(long time) {
return time + CURRENT_TIMEZONE.getOffset(time);
}
}
@@ -36,11 +36,11 @@ import java.util.Map.Entry;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.control.Assert;
import com.projectswg.common.control.Service;
import com.projectswg.common.control.LightspeedService;
import com.projectswg.common.debug.Assert;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.Log;
import com.projectswg.common.intents.RegisterHttpListenerIntent;
import com.projectswg.common.network.packets.PacketType;
import com.projectswg.lightspeed.communication.HttpResponder;
@@ -50,7 +50,7 @@ import fi.iki.elonen.NanoHTTPD.IHTTPSession;
import fi.iki.elonen.NanoHTTPD.Response;
import fi.iki.elonen.NanoHTTPD.Response.Status;
public class CommunicationService extends Service {
public class CommunicationService extends LightspeedService {
private final NanoHTTPD httpServer;
private final Map<PacketType, HttpResponder> responders;
@@ -38,14 +38,14 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import network.packets.swg.admin.AdminShutdownServer;
import me.joshlarson.json.JSONObject;
import network.packets.swg.admin.AdminShutdownServer;
import com.projectswg.common.control.Assert;
import com.projectswg.common.control.Service;
import com.projectswg.common.control.LightspeedService;
import com.projectswg.common.debug.Assert;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.Log;
import com.projectswg.common.intents.LaunchStarshipIntent;
import com.projectswg.common.intents.RegisterHttpListenerIntent;
import com.projectswg.common.network.packets.PacketType;
@@ -65,7 +65,7 @@ import com.projectswg.lightspeed.sequenced.SequencedStarter;
import com.projectswg.lightspeed.server.ServerServerData;
import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
public class DeploymentService extends Service {
public class DeploymentService extends LightspeedService {
private final AtomicLong deploymentId;
private final Map<String, Deployment> deployments;
@@ -130,7 +130,10 @@ public class DeploymentService extends Service {
private JSONObject processPostDeploy(JSONObject params) {
PostDeployPacket deploy = new PostDeployPacket(params);
launchStarship(deploy.getServerId());
ServerServerData server = getBackendData().getServer(deploy.getServerId());
if (server == null)
return new PostResult(false).getJSON();
launchStarship(server);
return new PostResult(true).getJSON();
}
@@ -171,8 +174,7 @@ public class DeploymentService extends Service {
return new ResponseDeploymentListPacket(request.getServerId(), deployList).getJSON();
}
private void launchStarship(String serverId) {
ServerServerData server = getBackendData().getServer(serverId);
private void launchStarship(ServerServerData server) {
ServerBuildData build = server.getLastBuild();
if (!launchStarshipChecks(build))
return;
@@ -210,7 +212,7 @@ public class DeploymentService extends Service {
return;
}
ServerDeploymentData deployment = new ServerDeploymentData(deploymentId.incrementAndGet(), build);
Log.i("Creating Deployment #%d", deployment.getId());
Log.i("Creating Deployment #%d from build #%d and server %s", deployment.getId(), build.getId(), deployment.getServer().getName());
Deployment newDeployment = new Deployment(deployment);
if (old != null) {
old.setReplacement(newDeployment);
@@ -304,12 +306,16 @@ public class DeploymentService extends Service {
}
private StarshipProcess prepareProcess(ServerDeploymentData deployment) {
String serverId = deployment.getServer().getName();
File java = new File(getJdk(), File.separatorChar+"bin"+File.separatorChar+"java");
File jar = new File("data"+File.separatorChar+"releases"+File.separatorChar+serverId+".jar");
File jar = new File("data"+File.separatorChar+"releases"+File.separatorChar+deployment.getServer().getName()+".jar");
File dir = new File(deployment.getServer().getDirectory());
String args = deployment.getServer().getJvmArguments();
return StarshipProcess.create(java, jar, dir, args, "");
String [] command = new String[] {
java.getAbsolutePath(),
"-jar",
jar.getAbsolutePath(),
deployment.getServer().getJvmArguments()
};
return StarshipProcess.create(dir, command);
}
private void onDeploymentStarted(ServerDeploymentData deployment) {
@@ -27,9 +27,9 @@
***********************************************************************************/
package com.projectswg.lightspeed;
import com.projectswg.common.control.Service;
import com.projectswg.common.control.LightspeedService;
public class GitListenerService extends Service {
public class GitListenerService extends LightspeedService {
public GitListenerService() {
@@ -27,12 +27,12 @@
***********************************************************************************/
package com.projectswg.lightspeed;
import com.projectswg.common.control.Manager;
import com.projectswg.common.control.LightspeedManager;
import com.projectswg.lightspeed.build.BuildService;
import com.projectswg.lightspeed.gui.GUIService;
import com.projectswg.lightspeed.server.ServerService;
public class LightspeedManager extends Manager {
public class LightspeedMainManager extends LightspeedManager {
private final GitListenerService gitListenerService;
private final ServerService serverService;
@@ -41,7 +41,7 @@ public class LightspeedManager extends Manager {
private final CommunicationService communicationService;
private final GUIService guiService;
public LightspeedManager() {
public LightspeedMainManager() {
gitListenerService = new GitListenerService();
serverService = new ServerService();
buildService = new BuildService();
@@ -33,54 +33,36 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
import com.projectswg.common.control.Assert;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Assert;
import com.projectswg.common.debug.Log;
import com.projectswg.lightspeed.deployment.ServerDeploymentData;
import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
public class StarshipProcess {
private final Object processMutex;
private final File java;
private final File jar;
private final File dir;
private final String jvmArgs;
private final String swgArgs;
private final String [] commands;
private Process process;
private int exitValue;
private StarshipProcess(File java, File jar, File dir, String jvmArgs, String swgArgs) {
if (java == null)
throw new NullPointerException("Java cannot be null!");
if (jar == null)
throw new NullPointerException("Jar cannot be null!");
private StarshipProcess(File dir, String [] commands) {
if (dir == null)
throw new NullPointerException("Directory cannot be null!");
if (!java.isFile())
throw new IllegalArgumentException("Java does not exist or is not a file!");
if (!jar.isFile())
throw new IllegalArgumentException("Jar does not exist or is not a file!");
if (!dir.isDirectory())
throw new IllegalArgumentException("Directory does not exist or is not a directory!");
if (commands == null)
throw new NullPointerException("");
this.processMutex = new Object();
this.java = java;
this.jar = jar;
this.dir = dir;
this.jvmArgs = jvmArgs;
this.swgArgs = swgArgs;
this.commands = new String[commands.length+1];
System.arraycopy(commands, 0, this.commands, 0, commands.length);
this.commands[commands.length] = "";
this.process = null;
this.exitValue = Integer.MAX_VALUE;
}
private ProcessBuilder createBuilder(int adminServerPort) {
String adminArg = "-adminServerPort=" + adminServerPort;
if (jvmArgs != null && swgArgs != null)
return new ProcessBuilder(java.getAbsolutePath(), jvmArgs, "-jar", jar.getAbsolutePath(), swgArgs, adminArg);
else if (jvmArgs != null)
return new ProcessBuilder(java.getAbsolutePath(), jvmArgs, "-jar", jar.getAbsolutePath(), adminArg);
else if (swgArgs != null)
return new ProcessBuilder(java.getAbsolutePath(), "-jar", jar.getAbsolutePath(), swgArgs, adminArg);
return new ProcessBuilder(java.getAbsolutePath(), "-jar", jar.getAbsolutePath(), adminArg);
commands[commands.length-1] = "-adminServerPort=" + adminServerPort;
return new ProcessBuilder(commands);
}
/**
@@ -173,16 +155,8 @@ public class StarshipProcess {
}
}
public static StarshipProcess create(File java, File pswgJar, File dir) {
return create(java, pswgJar, dir, null, null);
}
public static StarshipProcess create(File java, File pswgJar, File dir, String jvmArgs, String swgArgs) {
if (jvmArgs != null && jvmArgs.trim().isEmpty())
jvmArgs = null;
if (swgArgs != null && swgArgs.trim().isEmpty())
swgArgs = null;
return new StarshipProcess(java, pswgJar, dir, jvmArgs, swgArgs);
public static StarshipProcess create(File dir, String [] commands) {
return new StarshipProcess(dir, commands);
}
}
@@ -41,10 +41,10 @@ import java.util.concurrent.atomic.AtomicLong;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.control.Service;
import com.projectswg.common.control.LightspeedService;
import com.projectswg.common.debug.Log;
import com.projectswg.common.info.Config;
import com.projectswg.common.info.ConfigFile;
import com.projectswg.common.info.Log;
import com.projectswg.common.intents.LaunchStarshipIntent;
import com.projectswg.common.intents.PrepareStarshipIntent;
import com.projectswg.common.intents.RegisterHttpListenerIntent;
@@ -61,15 +61,13 @@ import com.projectswg.lightspeed.sequenced.SequencedStarter;
import com.projectswg.lightspeed.server.ServerServerData;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
public class BuildService extends Service {
public class BuildService extends LightspeedService {
private final JavaBuildMethod buildMethod;
private final AtomicLong buildId;
private final Map <String, Build> inprogress;
private final Set<ServerBuildData> buildHistory;
public BuildService() {
buildMethod = new JavaBuildMethod(getJdk());
buildId = new AtomicLong(0);
inprogress = new HashMap<>();
buildHistory = new HashSet<>();
@@ -112,9 +110,10 @@ public class BuildService extends Service {
private void onPrepareStarshipIntent(PrepareStarshipIntent psi) {
ServerBuildData buildData = new ServerBuildData(buildId.incrementAndGet(), psi.getServer());
Log.i("Creating build #%d", buildData.getId());
buildMethod.createJar(buildData, psi.getServer(), new BuildInstallationCallback(psi.getServer().getName(), psi.isRedeploy()));
Build build = new Build(buildData);
BuildInstallationCallback callback = new BuildInstallationCallback(psi.getServer().getName(), psi.isRedeploy());
JavaBuildMethod buildMethod = new JavaBuildMethod(getJdk(), psi.getServer(), buildData, callback);
synchronized (inprogress) {
Build build = new Build(buildData);
Build old = inprogress.put(psi.getServer().getName(), build);
if (old != null) {
old.setReplacement(build);
@@ -123,6 +122,7 @@ public class BuildService extends Service {
build.start();
}
}
buildMethod.start();
}
private JSONObject processBuild(JSONObject params) {
@@ -28,107 +28,103 @@
package com.projectswg.lightspeed.build;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.projectswg.common.data.TestDetails;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
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;
import com.projectswg.lightspeed.build.java_builder.RepoInstaller;
import com.projectswg.lightspeed.server.ServerServerData;
public class JavaBuildMethod {
private static final Pattern JUNIT_PATTERN = Pattern.compile("Tests run: (\\d+), Failures: (\\d+), Errors: (\\d+).*$");
private static final String SEP = File.separator;
private final File jdk;
private final RepoInstaller installer;
private final ServerBuildData buildData;
private final InstallationCallback callback;
public JavaBuildMethod(File jdk) {
this.jdk = jdk;
public JavaBuildMethod(File jdk, ServerServerData serverData, ServerBuildData buildData, InstallationCallback callback) {
this.installer = new RepoInstaller(processRepositoryArgument(serverData.getDirectory()), jdk);
this.buildData = buildData;
this.callback = callback;
}
public void createJar(ServerBuildData build, ServerServerData server, InstallationCallback callback) {
String repo = server.getDirectory();
String processedRepo = processRepositoryArgument(repo);
public void start() {
new Thread(() -> {
createJar(processedRepo, build, callback);
}).start();
createJar();
}, "java-build-"+buildData.getId()).start();
}
private String processRepositoryArgument(String repo) {
private File processRepositoryArgument(String repo) {
if (repo.endsWith(SEP))
return repo.substring(0, repo.length()-1);
return repo;
return new File(repo.substring(0, repo.length()-1));
return new File(repo);
}
private void createJar(String repo, ServerBuildData buildData, InstallationCallback callback) {
private void createJar() {
try {
RepoInstaller installer = new RepoInstaller(new File(repo), jdk);
buildData.setTime(TimeUtilities.getTime());
if (!build(installer, buildData, callback)) {
updateState(buildData, callback, InstallationState.FAILED);
return;
if (build() && test() && install()) {
updateState(InstallationState.SUCCESS);
} else {
if (buildData.getState() != InstallationState.CANCELLED) {
updateState(InstallationState.CANCELLED);
}
}
if (!test(installer, buildData, callback)) {
updateState(buildData, callback, InstallationState.FAILED);
return;
}
if (!install(installer, buildData, callback)) {
updateState(buildData, callback, InstallationState.FAILED);
return;
}
updateState(buildData, callback, InstallationState.SUCCESS);
} catch (Exception e) {
Log.e(e);
updateState(buildData, callback, InstallationState.FAILED);
updateState(InstallationState.FAILED);
}
}
private boolean build(RepoInstaller installer, ServerBuildData buildData, InstallationCallback callback) {
updateState(buildData, callback, InstallationState.BUILDING);
CustomJavaBuild build = new CustomJavaBuild(installer);
if (!build.compile(buildData))
return false;
if (detectCancelled(buildData, callback))
return false;
return true;
private boolean build() {
updateState(InstallationState.BUILDING);
long start = System.nanoTime();
StringBuilder output = new StringBuilder("");
boolean success = installer.executeAnt("compile", output);
buildData.setBuildSuccess(success);
buildData.setBuildString(output.toString());
buildData.setCompileTime((System.nanoTime() - start) / 1E6);
return success && !detectCancelled(buildData, callback);
}
private boolean test(RepoInstaller installer, ServerBuildData buildData, InstallationCallback callback) {
updateState(buildData, callback, InstallationState.TESTING);
CustomJavaTest test = new CustomJavaTest(installer);
TestDetails details = test.test(buildData);
if (details.getFailures() > 0 || details.getTotal() < 0)
return false;
if (detectCancelled(buildData, callback))
return false;
return true;
}
private boolean install(RepoInstaller installer, ServerBuildData buildData, InstallationCallback callback) {
updateState(buildData, callback, InstallationState.INSTALLING);
try {
CustomJavaInstall install = new CustomJavaInstall(installer);
install.createRawJar(buildData, "main.ProjectSWG");
return true;
} catch (CustomJavaException e) {
Log.e(e);
return false;
private boolean test() {
updateState(InstallationState.TESTING);
StringBuilder output = new StringBuilder("");
boolean success = installer.executeAnt("test", output);
Matcher m = JUNIT_PATTERN.matcher(output.substring(output.indexOf("Tests run"), output.indexOf("\n", output.indexOf("Tests run"))));
if (!m.matches()) {
System.err.println("Failed to match FAIL pattern: " + output);
buildData.setTestSuccess(false);
buildData.setTestDetails(new TestDetails(0, 0));
} else {
buildData.setTestSuccess(success);
buildData.setTestDetails(new TestDetails(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)) + Integer.parseInt(m.group(3))));
}
buildData.setTestString(output.toString());
return buildData.isTestSuccess() && !detectCancelled(buildData, callback);
}
private boolean install() {
updateState(InstallationState.INSTALLING);
installer.executeAnt("jar", new StringBuilder(""));
buildData.setJar(installer.getJar());
return !detectCancelled(buildData, callback);
}
private boolean detectCancelled(ServerBuildData buildData, InstallationCallback callback) {
if (buildData.getState() == InstallationState.CANCELLED) {
updateState(buildData, callback, InstallationState.CANCELLED);
updateState(InstallationState.CANCELLED);
return true;
}
return false;
}
private void updateState(ServerBuildData buildData, InstallationCallback callback, InstallationState newState) {
private void updateState(InstallationState newState) {
InstallationState oldState = buildData.getState();
buildData.setState(newState);
if (callback != null)
@@ -34,7 +34,7 @@ import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.lightspeed.build.ServerBuildData.InstallationCallback;
public class MavenInterface implements BuildMethod {
@@ -1,52 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.lightspeed.build.java_builder;
import com.projectswg.common.info.Log;
import com.projectswg.lightspeed.build.ServerBuildData;
public class CustomJavaBuild {
private final RepoInstaller installer;
public CustomJavaBuild(RepoInstaller installer) {
this.installer = installer;
}
public boolean compile(ServerBuildData buildData) {
long start = System.nanoTime();
StringBuilder output = new StringBuilder("");
boolean success = installer.executeAnt("compile", output);
buildData.setBuildSuccess(success);
buildData.setBuildString(output.toString());
buildData.setCompileTime((System.nanoTime() - start) / 1E6);
Log.i("Output: %s", output.toString());
return success;
}
}
@@ -36,7 +36,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
public class CustomJavaCommon {
@@ -1,45 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.lightspeed.build.java_builder;
import com.projectswg.lightspeed.build.ServerBuildData;
public class CustomJavaInstall {
private final RepoInstaller installer;
public CustomJavaInstall(RepoInstaller installer) {
this.installer = installer;
}
public void createRawJar(ServerBuildData buildData, String file) throws CustomJavaException {
installer.executeAnt("jar", new StringBuilder(""));
buildData.setJar(installer.getJar());
}
}
@@ -1,68 +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 <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.lightspeed.build.java_builder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.projectswg.common.data.TestDetails;
import com.projectswg.common.info.Log;
import com.projectswg.lightspeed.build.ServerBuildData;
public class CustomJavaTest {
private static final Pattern JUNIT_PATTERN = Pattern.compile("Tests run: (\\d+), Failures: (\\d+), Errors: (\\d+).*$");
private final RepoInstaller installer;
public CustomJavaTest(RepoInstaller installer) {
this.installer = installer;
}
public TestDetails test(ServerBuildData buildData) {
StringBuilder output = new StringBuilder("");
boolean success = installer.executeAnt("test", output);
TestDetails details = parseFail(output.toString());
buildData.setTestSuccess(success);
buildData.setTestString(output.toString());
buildData.setTestDetails(details);
Log.i("Output: %s", output.toString());
return details;
}
private TestDetails parseFail(String out) {
String line = out.substring(out.indexOf("Tests run"), out.indexOf('\n', out.indexOf("Tests run")));
Matcher m = JUNIT_PATTERN.matcher(line);
if (!m.matches()) {
System.err.println("Failed to match FAIL pattern: " + line);
return new TestDetails(-1, 0);
}
return new TestDetails(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)) + Integer.parseInt(m.group(3)));
}
}
@@ -36,7 +36,8 @@ import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
public class RepoInstaller {
@@ -39,7 +39,8 @@ import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
public class GitInterface {
@@ -55,7 +56,7 @@ public class GitInterface {
return "";
return qa.getObjectId().getName();
} catch (GitAPIException e) {
Log.e(e);
Log.e("Failed to query last commit from repository [%s]: %s", repository, e.getMessage());
}
return "";
}
@@ -69,7 +70,7 @@ public class GitInterface {
.setProgressMonitor(new CustomProgressMonitor()).call();
return res.isSuccessful();
} catch (GitAPIException e) {
Log.e(e);
Log.e("Failed to pull from repository [%s]: %s", repository, e.getMessage());
}
return false;
}
@@ -31,11 +31,11 @@ import javafx.application.Application;
import com.projectswg.Lightspeed;
import com.projectswg.common.concurrency.PswgBasicThread;
import com.projectswg.common.control.Service;
import com.projectswg.common.control.LightspeedService;
import com.projectswg.common.data.BackendData;
import com.projectswg.common.info.ConfigFile;
public class GUIService extends Service {
public class GUIService extends LightspeedService {
private final PswgBasicThread guiThread;
private boolean headless;
@@ -32,7 +32,8 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
public abstract class SequencedStarter {
@@ -95,6 +95,10 @@ public class ServerServerData {
return builds.lastEntry().getValue();
}
public ServerBuildData getBuild(long buildId) {
return builds.get(buildId);
}
public List<ServerBuildData> getBuilds() {
return new ArrayList<>(builds.values());
}
@@ -105,6 +109,10 @@ public class ServerServerData {
return deployments.lastEntry().getValue();
}
public ServerDeploymentData getDeployment(long deploymentId) {
return deployments.get(deploymentId);
}
public List<ServerDeploymentData> getDeployments() {
return new ArrayList<>(deployments.values());
}
@@ -36,8 +36,8 @@ import java.util.Set;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.concurrency.PswgBasicScheduledThread;
import com.projectswg.common.control.Service;
import com.projectswg.common.info.Log;
import com.projectswg.common.control.LightspeedService;
import com.projectswg.common.debug.Log;
import com.projectswg.common.intents.PrepareStarshipIntent;
import com.projectswg.common.intents.RegisterHttpListenerIntent;
import com.projectswg.common.network.packets.PacketType;
@@ -49,7 +49,7 @@ import com.projectswg.common.network.packets.response.ResponseServerListPacket;
import com.projectswg.lightspeed.git.GitInterface;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
public class ServerService extends Service {
public class ServerService extends LightspeedService {
private final Set<ServerServerData> servers;
private final PswgBasicScheduledThread gitScanner;
@@ -75,7 +75,7 @@ public class ServerService extends Service {
@Override
public boolean start() {
gitScanner.startWithFixedDelay(30000, 15000);
gitScanner.startWithFixedDelay(15000, 15000);
return super.start();
}
@@ -28,63 +28,99 @@
package com.projectswg.lightspeed_frontend;
import java.net.InetSocketAddress;
import com.projectswg.common.control.Assert;
import com.projectswg.common.info.Log;
import java.util.List;
import com.projectswg.common.concurrency.PswgScheduledThreadPool;
import com.projectswg.common.concurrency.PswgThreadPool;
import com.projectswg.common.data.TestDetails;
import com.projectswg.common.debug.Assert;
import com.projectswg.common.debug.Log;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.request.RequestBuildDetailedPacket;
import com.projectswg.common.network.packets.request.RequestBuildListPacket;
import com.projectswg.common.network.packets.request.RequestDeploymentDetailedPacket;
import com.projectswg.common.network.packets.request.RequestDeploymentListPacket;
import com.projectswg.common.network.packets.request.RequestPacket;
import com.projectswg.common.network.packets.request.RequestServerDetailedPacket;
import com.projectswg.common.network.packets.request.RequestServerListPacket;
import com.projectswg.common.network.packets.response.ResponsePacket;
import com.projectswg.common.network.packets.response.ResponseBuildDetailedPacket;
import com.projectswg.common.network.packets.response.ResponseBuildListPacket;
import com.projectswg.common.network.packets.response.ResponseDeploymentDetailedPacket;
import com.projectswg.common.network.packets.response.ResponseDeploymentListPacket;
import com.projectswg.common.network.packets.response.ResponseServerDetailedPacket;
import com.projectswg.common.network.packets.response.ResponseServerListPacket;
import com.projectswg.lightspeed_frontend.communication.FrontendCommunication;
import com.projectswg.lightspeed_frontend.data.SharedData;
import com.projectswg.lightspeed_frontend.communication.FrontendCommunication.ResponseCallback;
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.InboundPacketIntent;
public class Frontend {
private final PswgThreadPool threadPool;
private final PswgScheduledThreadPool scheduledUpdater;
private final FrontendCommunication communication;
private final SharedData data;
private final FrontendData data;
public Frontend() {
communication = new FrontendCommunication();
data = new SharedData();
this.threadPool = new PswgThreadPool(10, "frontend-thread-pool");
this.scheduledUpdater = new PswgScheduledThreadPool(1, "frontend-updater");
this.communication = new FrontendCommunication();
this.communication.setCallback(packet -> process(packet));
this.data = new FrontendData();
}
public void setAddress(InetSocketAddress address) {
communication.setAddress(address);
}
public void start() {
Assert.test(communication.start());
threadPool.start();
scheduledUpdater.start();
scheduledUpdater.executeWithFixedDelay(5000, 5000, () -> requestCompleteLoad());
scheduledUpdater.executeWithFixedDelay(1000, 1000, () -> requestLatestUpdates());
}
public void stop() {
Log.i("Disconnecting...");
Assert.test(communication.stop());
threadPool.stop();
scheduledUpdater.stop();
}
public FrontendCommunication getCommunication() {
return communication;
}
public SharedData getData() {
public FrontendData getData() {
return data;
}
public void connect(InetSocketAddress address) {
communication.connect(address);
}
public void disconnect() {
communication.disconnect();
}
public void send(RequestPacket p, ResponseCallback callback) {
send(p);
public void send(Packet p, ResponseCallback callback) {
threadPool.execute(() -> {
Packet response = communication.send(p);
Log.d("sendAwaitResponse response=%s callback?=%b", response, callback != null);
if (response != null)
process(response);
if (response != null && callback != null)
callback.onPacket(response);
});
}
public void send(Packet p) {
communication.send(p);
send(p, null);
}
public boolean isConnected() {
return communication.isConnected();
public void loadServerDetailed(String serverId, ResponseCallback callback) {
send(new RequestServerDetailedPacket(serverId), callback);
}
public void loadBuildDetailed(long buildId, ResponseCallback callback) {
send(new RequestBuildDetailedPacket(buildId), callback);
}
public void loadDeploymentDetailed(long deploymentId, ResponseCallback callback) {
send(new RequestDeploymentDetailedPacket(deploymentId), callback);
}
public void loadBuildHistory(String serverId, ResponseCallback callback) {
@@ -97,15 +133,112 @@ public class Frontend {
public void requestCompleteLoad() {
send(new RequestServerListPacket(), (response) -> {
for (SharedServerData server : data.getServers()) {
loadBuildHistory(server.getName(), null);
loadDeploymentHistory(server.getName(), null);
for (SharedServerData server : ((ResponseServerListPacket) response).getServerList()) {
loadBuildHistory(server.getName(), buildResponse -> {
SharedBuildData lastBuild = data.getServer(server.getName()).getLastBuild();
if (lastBuild != null)
loadBuildDetailed(lastBuild.getId(), null);
});
loadDeploymentHistory(server.getName(), deployResponse -> {
SharedDeploymentData lastDeployment = data.getServer(server.getName()).getLastDeployment();
if (lastDeployment != null)
loadDeploymentDetailed(lastDeployment.getId(), null);
});
}
});
}
public interface ResponseCallback {
void onResponse(ResponsePacket p);
public void requestLatestUpdates() {
SharedServerData server = data.getSelectedServer();
if (server == null)
return;
SharedDeploymentData lastDeployment = data.getServer(server.getName()).getLastDeployment();
if (lastDeployment != null)
loadDeploymentDetailed(lastDeployment.getId(), null);
}
private void process(Packet packet) {
new InboundPacketIntent(packet).broadcast();
if (packet instanceof ResponseServerListPacket)
processServerList((ResponseServerListPacket) packet);
else if (packet instanceof ResponseServerDetailedPacket)
processServerDetailed((ResponseServerDetailedPacket) packet);
else if (packet instanceof ResponseBuildListPacket)
processBuildList((ResponseBuildListPacket) packet);
else if (packet instanceof ResponseBuildDetailedPacket)
processBuildDetailed((ResponseBuildDetailedPacket) packet);
else if (packet instanceof ResponseDeploymentListPacket)
processDeploymentList((ResponseDeploymentListPacket) packet);
else if (packet instanceof ResponseDeploymentDetailedPacket)
processDeploymentDetailed((ResponseDeploymentDetailedPacket) packet);
}
private void processServerList(ResponseServerListPacket list) {
List<SharedServerData> current = data.getServers();
for (SharedServerData server : list.getServerList()) {
if (!current.contains(server)) {
loadServerDetailed(server.getName(), null);
data.addServer(server);
}
}
}
private void processServerDetailed(ResponseServerDetailedPacket detailed) {
SharedServerData server = detailed.getServer();
SharedServerData existing = data.getServer(server.getName());
if (existing != null) {
existing.setDirectory(detailed.getDirectory());
existing.setJvmArguments(detailed.getJvmArguments());
} else {
data.addServer(server);
}
}
private void processBuildList(ResponseBuildListPacket list) {
SharedServerData server = data.getServer(list.getServerId());
for (SharedBuildData build : list.getBuildList()) {
if (server.getBuildData(build.getId()) == null) {
server.addBuild(build);
}
}
}
private void processBuildDetailed(ResponseBuildDetailedPacket detailed) {
SharedServerData server = data.getServer(detailed.getServerId());
SharedBuildData build = server.getBuildData(detailed.getBuildId());
if (build != null) {
build.setTime(detailed.getTime());
build.setBuildString(detailed.getBuildString());
build.setTestString(detailed.getTestString());
build.setCompileTime(detailed.getCompileTime());
build.setBuildSuccess(detailed.isBuildSuccess());
build.setTestSuccess(detailed.isTestSuccess());
build.setCancelled(detailed.isCancelled());
build.setTestDetails(new TestDetails(detailed.getTestTotal(), detailed.getTestFailures()));
} else {
server.addBuild(detailed.getBuildData());
}
}
private void processDeploymentList(ResponseDeploymentListPacket list) {
SharedServerData server = data.getServer(list.getServerId());
for (SharedDeploymentData deployment : list.getDeploymentList()) {
if (server.getDeploymentData(deployment.getId()) == null) {
server.addDeployment(deployment);
}
}
}
private void processDeploymentDetailed(ResponseDeploymentDetailedPacket detailed) {
SharedServerData server = data.getServer(detailed.getServerId());
SharedDeploymentData deployment = server.getDeploymentData(detailed.getDeploymentId());
if (deployment != null) {
deployment.setStartTime(detailed.getStartTime());
deployment.setEndTime(detailed.getEndTime());
deployment.setOutput(detailed.getOutput());
} else {
server.addDeployment(detailed.getDeploymentData());
}
}
}
@@ -27,74 +27,58 @@
***********************************************************************************/
package com.projectswg.lightspeed_frontend;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import com.projectswg.common.callback.CallbackManager;
import com.projectswg.common.javafx.PSWGObjectProperty;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
import com.projectswg.lightspeed_frontend.data.SharedDeploymentData;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
public class FrontendData {
private final CallbackManager<FrontendDataUpdateCallback> updateCallbackManager;
private final CallbackManager<FrontendConnectionCallback> connectionCallbackManager;
private List<SharedServerData> servers;
private AtomicBoolean connected;
private final ObservableList<SharedServerData> servers;
private final PSWGObjectProperty<SharedServerData> selectedServer;
private final PSWGObjectProperty<SharedBuildData> selectedBuild;
private final PSWGObjectProperty<SharedDeploymentData> selectedDeployment;
public FrontendData() {
updateCallbackManager = new CallbackManager<>("frontend-data-update", 1);
connectionCallbackManager = new CallbackManager<>("frontend-data-connection", 1);
servers = new ArrayList<>();
connected = new AtomicBoolean(false);
updateCallbackManager.start();
connectionCallbackManager.start();
servers = FXCollections.observableArrayList();
selectedServer = new PSWGObjectProperty<>(null);
selectedBuild = new PSWGObjectProperty<>(null);
selectedDeployment = new PSWGObjectProperty<>(null);
}
public void close() {
updateCallbackManager.stop();
connectionCallbackManager.stop();
}
public void addDataUpdateCallback(FrontendDataUpdateCallback callback) {
updateCallbackManager.addCallback(callback);
public SharedServerData getSelectedServer() {
return selectedServer.get();
}
public void removeDataUpdateCallback(FrontendDataUpdateCallback callback) {
updateCallbackManager.removeCallback(callback);
public SharedBuildData getSelectedBuild() {
return selectedBuild.get();
}
public void addConnectionCallback(FrontendConnectionCallback callback) {
connectionCallbackManager.addCallback(callback);
public SharedDeploymentData getSelectedDeployment() {
return selectedDeployment.get();
}
public void removeConnectionCallback(FrontendConnectionCallback callback) {
connectionCallbackManager.removeCallback(callback);
public PSWGObjectProperty<SharedServerData> getSelectedServerProperty() {
return selectedServer;
}
public void setServers(List<String> servers) {
synchronized (this.servers) {
for (SharedServerData server : new ArrayList<>(this.servers)) {
if (!servers.contains(server.getName())) {
this.servers.remove(server);
} else {
servers.remove(server.getName());
}
}
for (String server : servers) {
this.servers.add(new SharedServerData(server));
}
}
notifyDataUpdated(FrontendDataType.SERVER_LIST);
public PSWGObjectProperty<SharedBuildData> getSelectedBuildProperty() {
return selectedBuild;
}
public void setConnectionStatus(boolean connected) {
if (this.connected.getAndSet(connected) != connected)
notifyConnectionUpdated(connected);
public PSWGObjectProperty<SharedDeploymentData> getSelectedDeploymentProperty() {
return selectedDeployment;
}
public List<SharedServerData> getServers() {
return Collections.unmodifiableList(servers);
public ObservableList<SharedServerData> getServers() {
return servers;
}
public SharedServerData getServer(String serverId) {
@@ -107,28 +91,44 @@ public class FrontendData {
return null;
}
public boolean isConnected() {
return connected.get();
public SharedBuildData getBuild(long buildId) {
synchronized (servers) {
for (SharedServerData server : servers) {
SharedBuildData build = server.getBuildData(buildId);
if (build != null)
return build;
}
}
return null;
}
public void notifyDataUpdated(FrontendDataType dataType) {
updateCallbackManager.callOnEach((callback) -> callback.onDataUpdated(dataType));
public SharedDeploymentData getDeployment(long deploymentId) {
synchronized (servers) {
for (SharedServerData server : servers) {
SharedDeploymentData deployment = server.getDeploymentData(deploymentId);
if (deployment != null)
return deployment;
}
}
return null;
}
private void notifyConnectionUpdated(boolean newState) {
connectionCallbackManager.callOnEach((callback) -> callback.onConnectionChanged(newState));
public void setSelectedServer(SharedServerData server) {
this.selectedServer.set(server);
}
public interface FrontendDataUpdateCallback {
void onDataUpdated(FrontendDataType dataType);
public void setSelectedBuild(SharedBuildData build) {
this.selectedBuild.set(build);
}
public interface FrontendConnectionCallback {
void onConnectionChanged(boolean connected);
public void setSelectedDeployment(SharedDeploymentData deployment) {
this.selectedDeployment.set(deployment);
}
public enum FrontendDataType {
SERVER_LIST
public void addServer(SharedServerData server) {
synchronized (servers) {
servers.add(server);
}
}
}
@@ -30,43 +30,54 @@ package com.projectswg.lightspeed_frontend;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.Map;
import com.projectswg.common.control.IntentManager;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.debug.Log.LogLevel;
import com.projectswg.common.debug.log_wrapper.ConsoleLogWrapper;
import com.projectswg.common.javafx.FXMLUtilities;
import com.projectswg.common.javafx.ResourceUtilities;
import com.projectswg.lightspeed_frontend.gui.LightspeedPrimaryView;
import com.projectswg.lightspeed_frontend.intents.ConnectionStateUpdateIntent;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class LightspeedFrontendGUI extends Application {
public static final Frontend FRONTEND = new Frontend();
public static final FrontendData DATA = FRONTEND.getData();
private final Frontend frontend;
private final LightspeedPrimaryView primaryView;
private LightspeedPrimaryView primaryView;
public LightspeedFrontendGUI() {
frontend = new Frontend();
primaryView = new LightspeedPrimaryView(frontend);
IntentManager.getInstance().registerForIntent(ConnectionStateUpdateIntent.class, i -> onConnectionUpdate(((ConnectionStateUpdateIntent) i).isConnected()));
frontend = LightspeedFrontendGUI.FRONTEND;
primaryView = null;
frontend.start();
}
public static void main(String [] args) {
ResourceUtilities.setPrimarySource(LightspeedFrontendGUI.class);
Log.addWrapper(new ConsoleLogWrapper(LogLevel.VERBOSE));
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
processConnect();
IntentManager.getInstance().initialize();
Scene scene = new Scene(primaryView, 800, 640);
primaryView = (LightspeedPrimaryView) FXMLUtilities.loadFxml("PrimaryView.fxml", Locale.ENGLISH);
processConnect();
Parent root = primaryView.getRoot();
primaryStage.setTitle("Lightspeed Frontend");
primaryStage.setScene(scene);
primaryView.setOnMouseClicked((event) -> primaryView.requestFocus());
primaryView.requestFocus();
primaryStage.setScene(new Scene(root));
root.setOnMouseClicked((event) -> root.requestFocus());
root.requestFocus();
primaryStage.show();
primaryStage.setOnCloseRequest((we) -> {
close(we);
@@ -88,9 +99,8 @@ public class LightspeedFrontendGUI extends Application {
}
}
try {
InetSocketAddress sock = new InetSocketAddress(InetAddress.getByName(address), port);
frontend.connect(sock);
primaryView.setConnectAddress(sock);
primaryView.setConnectAddress(new InetSocketAddress(InetAddress.getByName(address), port));
frontend.requestCompleteLoad();
} catch (UnknownHostException e) {
Log.e(e);
}
@@ -98,16 +108,11 @@ public class LightspeedFrontendGUI extends Application {
private void close(WindowEvent we) {
Log.i("Closing GUI...");
primaryView.close();
FXMLUtilities.terminate();
frontend.stop();
Log.i("Terminating IntentManager...");
IntentManager.getInstance().terminate();
Log.i("Closed.");
}
private void onConnectionUpdate(boolean connected) {
if (connected)
frontend.requestCompleteLoad();
}
}
@@ -34,7 +34,9 @@ import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.debug.Log.LogLevel;
import com.projectswg.common.debug.log_wrapper.ConsoleLogWrapper;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.post.PostBuildPacket;
import com.projectswg.common.network.packets.post.PostCreateServerPacket;
@@ -70,8 +72,15 @@ public class LightspeedFrontendText {
communication = new FrontendCommunication();
inbound = new ArrayDeque<>();
running = false;
communication.setAddress(new InetSocketAddress(InetAddress.getLoopbackAddress(), 44444));
communication.setCallback(packet -> {
synchronized (inbound) {
inbound.add(packet);
inbound.notify();
}
});
}
public void run() {
running = true;
communication.start();
@@ -95,11 +104,8 @@ public class LightspeedFrontendText {
case "quit":
processQuit();
break;
case "connect":
processConnect(args);
break;
case "disconnect":
processDisconnect();
case "setup":
processSetup(args);
break;
case "request":
processRequest(args);
@@ -114,7 +120,7 @@ public class LightspeedFrontendText {
running = false;
}
private void processConnect(String [] args) {
private void processSetup(String [] args) {
InetAddress addr = InetAddress.getLoopbackAddress();
int port = 44444;
try {
@@ -129,18 +135,7 @@ public class LightspeedFrontendText {
Log.e("Invalid call to connect! Invalid port: " + args[2]);
return;
}
communication.connect(new InetSocketAddress(addr, port));
try {
while (!communication.isConnected()) {
Thread.sleep(10);
}
} catch (InterruptedException e) {
Log.w(e);
}
}
private void processDisconnect() {
communication.disconnect();
communication.setAddress(new InetSocketAddress(addr, port));
}
private void processRequest(String [] args) {
@@ -320,6 +315,7 @@ public class LightspeedFrontendText {
}
public static void main(String [] args) {
Log.addWrapper(new ConsoleLogWrapper(LogLevel.VERBOSE));
LightspeedFrontendText frontend = new LightspeedFrontendText();
frontend.run();
}
@@ -28,22 +28,29 @@
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.debug.Assert;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.utilities.ThreadUtilities;
public class FrontendCommunication {
private final AtomicBoolean running;
private ExecutorService executor;
private ResponseCallback callback;
private InetSocketAddress address;
public FrontendCommunication() {
running = new AtomicBoolean(false);
callback = null;
address = null;
}
public void setCallback(ResponseCallback callback) {
this.callback = callback;
}
public void setAddress(InetSocketAddress address) {
this.address = address;
}
public boolean start() {
@@ -51,7 +58,6 @@ public class FrontendCommunication {
Assert.fail();
return false;
}
executor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory("frontend-communication"));
return true;
}
@@ -60,25 +66,18 @@ public class FrontendCommunication {
Assert.fail();
return false;
}
executor.shutdownNow();
return true;
}
public boolean isConnected() {
return false;
public Packet send(Packet packet) {
Packet response = HttpClient.requestPacket(address, packet);
if (response != null && callback != null)
callback.onPacket(response);
return response;
}
public void connect(InetSocketAddress addr) {
if (addr == null)
throw new NullPointerException();
}
public void disconnect() {
}
public void send(Packet p) {
public interface ResponseCallback {
void onPacket(Packet packet);
}
}
@@ -25,100 +25,76 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.common.network.protocol;
package com.projectswg.lightspeed_frontend.communication;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map.Entry;
import me.joshlarson.json.JSON;
import me.joshlarson.json.JSONObject;
import com.projectswg.common.info.Log;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
import com.projectswg.common.debug.Log;
import com.projectswg.common.network.packets.Packet;
import com.projectswg.common.network.packets.PacketType;
import com.projectswg.common.network.packets.post.PostPacket;
import com.projectswg.common.network.packets.request.RequestPacket;
public class AlphaProtocol extends Protocol {
public class HttpClient {
public static final String VERSION = "alpha";
private final NetBufferStream stream;
private final Queue<Packet> incoming;
protected AlphaProtocol() {
super(VERSION);
stream = new NetBufferStream(4096);
incoming = new ArrayDeque<>();
public static Packet requestPacket(InetSocketAddress address, Packet packet) {
try {
String str = requestString(address, packet);
JSONObject obj = JSON.readObject(str, true);
PacketType type = PacketType.valueOf(obj.getString("type"));
return Packet.inflate(obj, type);
} catch (IOException e) {
Log.e(e);
}
return null;
}
@Override
public ByteBuffer preparePacket(Packet p) {
String json = p.getJSON().toString();
NetBuffer buf = NetBuffer.allocate(4+json.length()*2);
buf.addUnicode(json);
buf.getBuffer().flip();
return buf.getBuffer();
}
@Override
public void onIncomingData(byte [] data) {
synchronized (stream) {
try {
stream.write(data);
while (stream.remaining() >= 4) {
stream.mark();
int length = stream.getInt();
stream.rewind();
if (stream.remaining() < length * 2 + 4)
return;
String jsonRaw = stream.getUnicode();
JSONObject json = JSON.readObject(jsonRaw, true);
if (json != null)
processPacket(json);
else
Log.d("Unknown JSON string:%n%s", jsonRaw);
}
stream.compact();
} catch (Exception e) {
Log.e(e);
public static String requestString(InetSocketAddress address, Packet packet) throws IOException {
URL url = new URL(generateURL(address, packet));
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod((packet instanceof PostPacket) ? "POST" : "GET");
con.setRequestProperty("User-Agent", "LightspeedFrontend");
int responseCode = con.getResponseCode();
if (responseCode != 200)
return "";
StringBuilder response = new StringBuilder("");
try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
}
return response.toString();
}
@Override
public Packet getNextPacket() {
synchronized (incoming) {
return incoming.poll();
}
}
@Override
public int getPacketCount() {
synchronized (incoming) {
return incoming.size();
}
}
private void processPacket(JSONObject json) {
if (!json.containsKey("type")) {
Log.e("Received invalid packet without type!");
return;
}
PacketType type = null;
try {
type = PacketType.valueOf(json.getString("type"));
} catch (IllegalArgumentException | NullPointerException e) {
Log.e("Received unknown packet! Type: " + json.getString("type"));
return;
}
Packet p = Packet.inflate(json, type);
if (p == null)
return;
synchronized (incoming) {
incoming.add(p);
private static String generateURL(InetSocketAddress address, Packet packet) throws UnsupportedEncodingException {
StringBuilder url = new StringBuilder("http://"+address.getAddress().getHostAddress()+":"+address.getPort()+"/?");
JSONObject obj = packet.getJSON();
if (packet instanceof PostPacket)
url.append("type=" + ((PostPacket) packet).getType().name().replace("POST_", "") + '&');
else if (packet instanceof RequestPacket)
url.append("type=" + ((RequestPacket) packet).getType().name().replace("REQUEST_", "") + '&');
else
return url.toString();
obj.remove("type");
for (Entry<String, Object> entry : obj.entrySet()) {
url.append(entry.getKey() + '=' + URLEncoder.encode(entry.getValue().toString(), "ASCII") + '&');
}
return url.toString();
}
}
@@ -46,7 +46,8 @@ import javafx.scene.text.FontWeight;
import javax.swing.UIManager;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
public class InternalWindow extends Region {
@@ -29,46 +29,32 @@ package com.projectswg.lightspeed_frontend.gui;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
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.control.IntentManager;
import com.projectswg.common.concurrency.PswgBasicScheduledThread;
import com.projectswg.common.javafx.FXMLController;
import com.projectswg.common.javafx.FXMLUtilities;
import com.projectswg.common.network.packets.post.PostBuildPacket;
import com.projectswg.common.utilities.ThreadUtilities;
import com.projectswg.common.network.packets.post.PostDeployPacket;
import com.projectswg.common.network.packets.post.PostStopDeployPacket;
import com.projectswg.lightspeed_frontend.Frontend;
import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
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.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.Parent;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.VBox;
public class LightspeedPrimaryView extends VBox implements Initializable {
private final ExecutorService executor;
private final Frontend frontend;
private final AtomicBoolean initialized;
public class LightspeedPrimaryView implements FXMLController {
@FXML
private GeneralTab generalTab;
@FXML
private BuildTab buildTab;
@FXML
private DeploymentTab deploymentTab;
private VBox primaryViewContainer;
@FXML
private MenuButton commonServerStatus;
@FXML
@@ -76,93 +62,82 @@ public class LightspeedPrimaryView extends VBox implements Initializable {
@FXML
private MenuButton commonDeploymentStatus;
private SharedServerData server;
private InetSocketAddress address;
private final PswgBasicScheduledThread scheduledUpdater;
private final Frontend frontend;
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.initialized = new AtomicBoolean(false);
this.server = null;
this.address = null;
IntentManager.getInstance().registerForIntent(ConnectionStateUpdateIntent.class, i -> update());
FrontendFXMLLoader.load(this, "fxml/PrimaryView.fxml");
public LightspeedPrimaryView() {
this.scheduledUpdater = new PswgBasicScheduledThread("primary-view-updater", () -> updateUi());
this.frontend = LightspeedFrontendGUI.FRONTEND;
}
public void setConnectAddress(InetSocketAddress address) {
this.address = address;
frontend.setAddress(address);
}
public void close() {
Assert.test(!executor.isShutdown());
executor.shutdownNow();
@Override
public Parent getRoot() {
return primaryViewContainer;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
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);
});
FXMLUtilities.onFxmlLoaded(this);
FXMLUtilities.loadFxml("primary_tabs/General.fxml", Locale.ENGLISH);
FXMLUtilities.loadFxml("primary_tabs/Build.fxml", Locale.ENGLISH);
FXMLUtilities.loadFxml("primary_tabs/Deployment.fxml", Locale.ENGLISH);
frontend.getData().getSelectedServerProperty().addListener((val, prev, next) -> updateUi());
updateUi();
scheduledUpdater.startWithFixedRate(1000, 1000);
}
private void update() {
@Override
public void terminate() {
scheduledUpdater.stop();
}
private void updateUi() {
Platform.runLater(() -> {
setServerStatusText(frontend.isConnected());
setBuildStatusText(server == null ? null : server.getLastBuild());
setDeploymentStatusText(server == null ? null : server.getLastDeployment());
setBuildStatusText();
setDeploymentStatusText();
});
}
private void setServerStatusText(boolean connected) {
commonServerStatus.setText(String.format("Server: %s", connected ? "Connected" : "Disconnected"));
if (connected) {
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 setBuildStatusText(SharedBuildData build) {
List<MenuItem> items = new ArrayList<>();
private void setBuildStatusText() {
SharedServerData server = frontend.getData().getSelectedServer();
SharedBuildData build = server == null ? null : server.getLastBuild();
if (build != null) {
commonBuildStatus.setText(String.format("Build: %s", (build.isBuildSuccess() && build.isTestSuccess()) ? "Success" : "Failure"));
} else {
commonBuildStatus.setText("Build: N/A");
}
if (frontend.isConnected() && server != null) {
if (server != null && commonBuildStatus.getItems().isEmpty()) {
MenuItem startBuild = new MenuItem("Start Build");
startBuild.setOnAction((event) -> frontend.send(new PostBuildPacket(server.getName())));
items.add(startBuild);
commonBuildStatus.getItems().setAll(startBuild);
} else {
if (server == null)
commonBuildStatus.getItems().clear();
}
commonBuildStatus.getItems().setAll(items);
}
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));
private void setDeploymentStatusText() {
SharedServerData server = frontend.getData().getSelectedServer();
SharedDeploymentData deployment = server == null ? null : server.getLastDeployment();
if (deployment != null) {
commonDeploymentStatus.setText("Deployment: " + (deployment.getEndTime() == 0 ? "Running" : "Stopped"));
} else {
commonDeploymentStatus.setText("Deployment: N/A");
}
if (server != null && commonDeploymentStatus.getItems().isEmpty()) {
MenuItem startDeploy = new MenuItem("Start Deployment");
MenuItem stopDeploy = new MenuItem("Stop Deployment");
startDeploy.setOnAction((event) -> frontend.send(new PostDeployPacket(server.getName())));
stopDeploy.setOnAction((event) -> frontend.send(new PostStopDeployPacket(server.getName())));
commonDeploymentStatus.getItems().setAll(startDeploy, stopDeploy);
} else {
if (server == null)
commonDeploymentStatus.getItems().clear();
}
}
}
@@ -28,30 +28,34 @@
package com.projectswg.lightspeed_frontend.gui.primary_tabs;
import java.net.URL;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import com.projectswg.common.concurrency.PswgBasicScheduledThread;
import com.projectswg.common.data.TestDetails;
import com.projectswg.common.info.Log;
import com.projectswg.common.debug.Log;
import com.projectswg.common.javafx.FXMLController;
import com.projectswg.common.javafx.FXMLUtilities;
import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed_frontend.Frontend;
import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
import com.projectswg.lightspeed_frontend.data.SharedServerData;
import com.projectswg.lightspeed_frontend.javafx.FrontendFXMLLoader;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
public class BuildTab extends GridPane implements Initializable {
public class BuildTab implements FXMLController {
@FXML
private ComboBox<String> buildComboBox;
private Parent rootBuild;
@FXML
private ComboBox<SharedBuildData> buildComboBox;
@FXML
private Label serverNameText;
@FXML
@@ -67,35 +71,22 @@ public class BuildTab extends GridPane implements Initializable {
@FXML
private Label testText;
private SelectedBuildChangedCallback callback;
private SharedServerData selectedServerData;
private SharedBuildData selectedBuildData;
private final PswgBasicScheduledThread scheduledUpdater;
private final Frontend frontend;
public BuildTab() {
callback = null;
selectedServerData = null;
selectedBuildData = null;
FrontendFXMLLoader.load(this, "fxml/primary_tabs/Build.fxml");
this.scheduledUpdater = new PswgBasicScheduledThread("build-tab-updater", () -> requestUpdate());
this.frontend = LightspeedFrontendGUI.FRONTEND;
}
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 Parent getRoot() {
return rootBuild;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
FXMLUtilities.onFxmlLoaded(this);
serverNameText.getStyleClass().setAll("white-label");
buildIdText.getStyleClass().setAll("white-label");
statusText.getStyleClass().setAll("white-label");
@@ -103,101 +94,117 @@ public class BuildTab extends GridPane implements Initializable {
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);
buildComboBox.setConverter(new StringConverter<SharedBuildData>() {
public String toString(SharedBuildData server) { return Long.toString(server.getId()); }
public SharedBuildData fromString(String string) { return frontend.getData().getBuild(Long.parseLong(string)); }
});
buildComboBox.getSelectionModel().selectedItemProperty().addListener((val, prev, next) -> {
Log.d("selected build manually '%s'", next);
frontend.getData().setSelectedBuild(next);
if (next != null)
frontend.loadBuildDetailed(next.getId(), response -> Platform.runLater(() -> updateBuildDetails()));
updateBuildDetails();
});
this.frontend.getData().getSelectedServerProperty().addListener((val, prev, next) -> updateUi());
updateUi();
scheduledUpdater.startWithFixedRate(10000, 10000);
}
private void selectBuild(SharedBuildData build) {
Log.d("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();
@Override
public void terminate() {
scheduledUpdater.stop();
}
private void requestUpdate() {
SharedBuildData selected = frontend.getData().getSelectedBuild();
if (selected != null) {
frontend.loadBuildDetailed(selected.getId(), response -> updateUi());
}
}
private void updateUi() {
Platform.runLater(() -> {
setServerName();
setBuildId();
setStatus();
setTime();
setCompileTime();
setMode();
setTests();
updateBuildList();
updateBuildDetails();
});
}
private void updateBuildList() {
List<SharedBuildData> 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());
}
Platform.runLater(() -> {
buildComboBox.setItems(FXCollections.observableArrayList(builds));
buildComboBox.getItems().add(0, "");
if (selectedBuildData != null) {
selectBuild(selectedBuildData);
SharedServerData selectedServer = frontend.getData().getSelectedServer();
if (selectedServer != null) {
List<SharedBuildData> updated = selectedServer.getBuilds();
List<SharedBuildData> original = buildComboBox.getItems();
for (SharedBuildData u : updated) {
if (!original.contains(u))
original.add(u);
}
});
Iterator<SharedBuildData> it = original.iterator();
while (it.hasNext()) {
SharedBuildData o = it.next();
if (!updated.contains(o))
it.remove();
}
original.sort((a, b) -> Long.compare(b.getId(), a.getId()));
} else {
buildComboBox.getItems().clear();
}
}
private void updateBuildDetails() {
setServerName();
setBuildId();
setStatus();
setTime();
setCompileTime();
setMode();
setTests();
}
private void setServerName() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
serverNameText.setText("N/A");
} else {
serverNameText.setText(selectedBuildData.getServer().getName());
serverNameText.setText(selectedBuild.getServer().getName());
}
}
private void setBuildId() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
buildIdText.setText("N/A");
} else {
buildIdText.setText(Long.toString(selectedBuildData.getId()));
buildIdText.setText(Long.toString(selectedBuild.getId()));
}
}
private void setStatus() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
statusText.getStyleClass().setAll("white-label");
statusText.setText("N/A");
} else {
boolean success = selectedBuildData.isBuildSuccess() && selectedBuildData.isTestSuccess();
boolean success = selectedBuild.isBuildSuccess() && selectedBuild.isTestSuccess();
statusText.getStyleClass().setAll(success ? "green-label" : "red-label");
statusText.setText(success ? "Success" : "Failure");
}
}
private void setTime() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
timeText.setText("N/A");
} else {
timeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedBuildData.getTime())));
timeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedBuild.getTime())));
}
}
private void setCompileTime() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
compileTimeText.setText("N/A");
} else {
compileTimeText.setText(getTime((long) (selectedBuildData.getCompileTime()*1E3)));
compileTimeText.setText(getTime((long) (selectedBuild.getCompileTime()*1E3)));
}
}
@@ -206,10 +213,11 @@ public class BuildTab extends GridPane implements Initializable {
}
private void setTests() {
if (selectedBuildData == null) {
SharedBuildData selectedBuild = frontend.getData().getSelectedBuild();
if (selectedBuild == null) {
testText.setText("N/A");
} else {
TestDetails details = selectedBuildData.getTestDetails();
TestDetails details = selectedBuild.getTestDetails();
int total = details.getTotal();
int passed = total-details.getFailures();
testText.setText(String.format("%d of %d passed", passed, total));
@@ -28,29 +28,34 @@
package com.projectswg.lightspeed_frontend.gui.primary_tabs;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import com.projectswg.common.concurrency.PswgScheduledThreadPool;
import com.projectswg.common.debug.Log;
import com.projectswg.common.javafx.FXMLController;
import com.projectswg.common.javafx.FXMLUtilities;
import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed_frontend.Frontend;
import com.projectswg.lightspeed_frontend.data.SharedBuildData;
import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
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.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.control.TextArea;
import javafx.util.StringConverter;
public class DeploymentTab extends GridPane implements Initializable {
public class DeploymentTab implements FXMLController {
@FXML
private ComboBox<String> deploymentComboBox;
private Parent rootDeployment;
@FXML
private ComboBox<SharedDeploymentData> deploymentComboBox;
@FXML
private Label serverNameText;
@FXML
@@ -64,51 +69,86 @@ public class DeploymentTab extends GridPane implements Initializable {
@FXML
private Label uptimeText;
@FXML
private Label logText;
private TextArea logTextArea;
private SharedServerData selectedServerData;
private SharedBuildData selectedBuildData;
private SharedDeploymentData selectedDeploymentData;
private final PswgScheduledThreadPool scheduledUpdater;
private final Frontend frontend;
public DeploymentTab() {
FrontendFXMLLoader.load(this, "fxml/primary_tabs/Deployment.fxml");
this.scheduledUpdater = new PswgScheduledThreadPool(1, "deployment-tab-updater");
this.frontend = LightspeedFrontendGUI.FRONTEND;
}
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 Parent getRoot() {
return rootDeployment;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
FXMLUtilities.onFxmlLoaded(this);
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");
deploymentComboBox.setConverter(new DeploymentStringConverter());
deploymentComboBox.getSelectionModel().selectedItemProperty().addListener((val, prev, next) -> {
Log.d("selected deployment manually '%s'", next);
frontend.getData().setSelectedDeployment(next);
if (next != null)
frontend.loadDeploymentDetailed(next.getId(), response -> Platform.runLater(() -> updateDeploymentDetails()));
updateDeploymentDetails();
});
this.frontend.getData().getSelectedServerProperty().addListener((val, prev, next) -> updateUi());
updateUi();
scheduledUpdater.start();
scheduledUpdater.executeWithFixedRate(10000, 10000, () -> requestUpdate());
scheduledUpdater.executeWithFixedRate(1000, 1000, () -> Platform.runLater(() -> updateDeploymentDetails()));
}
@Override
public void terminate() {
scheduledUpdater.stop();
}
private void requestUpdate() {
SharedDeploymentData selected = frontend.getData().getSelectedDeployment();
if (selected != null) {
frontend.loadDeploymentDetailed(selected.getId(), response -> updateUi());
}
}
private void updateUi() {
Platform.runLater(() -> {
updateDeploymentList();
updateDeploymentDetails();
});
}
private void updateDeploymentList() {
SharedServerData selectedServer = frontend.getData().getSelectedServer();
if (selectedServer != null) {
List<SharedDeploymentData> updated = selectedServer.getDeployments();
List<SharedDeploymentData> original = deploymentComboBox.getItems();
for (SharedDeploymentData u : updated) {
if (!original.contains(u))
original.add(u);
}
Iterator<SharedDeploymentData> it = original.iterator();
while (it.hasNext()) {
SharedDeploymentData o = it.next();
if (!updated.contains(o))
it.remove();
}
original.sort((a, b) -> Long.compare(b.getId(), a.getId()));
} else {
deploymentComboBox.getItems().clear();
}
}
private void updateDeploymentDetails() {
setServerName();
setBuildId();
setDeploymentId();
@@ -118,86 +158,66 @@ public class DeploymentTab extends GridPane implements Initializable {
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<SharedDeploymentData> 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) {
SharedServerData selectedServer = frontend.getData().getSelectedServer();
if (selectedServer == null) {
serverNameText.setText("N/A");
} else {
serverNameText.setText(selectedServerData.getName());
serverNameText.setText(selectedServer.getName());
}
}
private void setBuildId() {
if (selectedBuildData == null) {
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
buildIdText.setText("N/A");
} else {
buildIdText.setText(Long.toString(selectedBuildData.getId()));
buildIdText.setText(Long.toString(selectedDeployment.getBuild().getId()));
}
}
private void setDeploymentId() {
if (selectedDeploymentData == null) {
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
deploymentIdText.setText("N/A");
} else {
deploymentIdText.setText(Long.toString(selectedDeploymentData.getId()));
deploymentIdText.setText(Long.toString(selectedDeployment.getId()));
}
}
private void setStatus() {
if (selectedDeploymentData == null) {
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
statusText.getStyleClass().setAll("white-label");
statusText.setText("N/A");
} else {
if (selectedDeploymentData.getEndTime() == -1) {
if (selectedDeployment.getEndTime() == 0) {
statusText.getStyleClass().setAll("green-label");
statusText.setText("Running");
} else {
statusText.getStyleClass().setAll("white-label");
statusText.setText("Stopped at " + TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeploymentData.getEndTime())));
statusText.setText("Stopped at " + TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeployment.getEndTime())));
}
}
}
private void setStartTime() {
if (selectedDeploymentData == null) {
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
startTimeText.setText("N/A");
} else {
startTimeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeploymentData.getStartTime())));
startTimeText.setText(TimeUtilities.getDateString(TimeUtilities.convertUtcToLocal(selectedDeployment.getStartTime())));
}
}
private void setUptime() {
if (selectedDeploymentData == null) {
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
uptimeText.setText("N/A");
} else {
long start = selectedDeploymentData.getStartTime();
long end = selectedDeploymentData.getEndTime();
if (end == -1) {
long start = selectedDeployment.getStartTime();
long end = selectedDeployment.getEndTime();
if (end == 0) {
uptimeText.setText(getTime(TimeUtilities.getTime()-start));
} else {
uptimeText.setText(getTime(end-start));
@@ -206,10 +226,16 @@ public class DeploymentTab extends GridPane implements Initializable {
}
private void setLog() {
if (selectedDeploymentData == null) {
logText.setText(" ");
SharedDeploymentData selectedDeployment = frontend.getData().getSelectedDeployment();
if (selectedDeployment == null) {
logTextArea.setText("");
} else {
logText.setText(" ");
double pos = logTextArea.getScrollTop();
int anchor = logTextArea.getAnchor();
int caret = logTextArea.getCaretPosition();
logTextArea.setText(selectedDeployment.getOutput());
logTextArea.setScrollTop(pos);
logTextArea.selectRange(anchor, caret);
}
}
@@ -241,4 +267,17 @@ public class DeploymentTab extends GridPane implements Initializable {
void onDeploymentChanged(SharedDeploymentData deployment);
}
private class DeploymentStringConverter extends StringConverter<SharedDeploymentData> {
public String toString(SharedDeploymentData deployment) {
return "D " + deployment.getId() + " - B " + deployment.getBuild().getId();
}
public SharedDeploymentData fromString(String string) {
String [] parts = string.split(" ");
return frontend.getData().getDeployment(Long.parseLong(parts[1]));
}
}
}
@@ -28,27 +28,34 @@
package com.projectswg.lightspeed_frontend.gui.primary_tabs;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import com.projectswg.common.concurrency.PswgBasicScheduledThread;
import com.projectswg.common.control.IntentManager;
import com.projectswg.common.debug.Log;
import com.projectswg.common.javafx.FXMLController;
import com.projectswg.common.javafx.FXMLUtilities;
import com.projectswg.common.utilities.TimeUtilities;
import com.projectswg.lightspeed_frontend.Frontend;
import com.projectswg.lightspeed_frontend.LightspeedFrontendGUI;
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 com.projectswg.lightspeed_frontend.intents.InboundPacketIntent;
import javafx.collections.FXCollections;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
public class GeneralTab extends GridPane implements Initializable {
public class GeneralTab implements FXMLController {
@FXML
private ComboBox<String> serverComboBox;
private Parent rootGeneral;
@FXML
private ComboBox<SharedServerData> serverComboBox;
@FXML
private Label serverNameText;
@FXML
@@ -60,58 +67,76 @@ public class GeneralTab extends GridPane implements Initializable {
@FXML
private Label uptimeText;
private Frontend frontend;
private SharedServerData selectedServerData;
private SelectedServerChangedCallback callback;
private final PswgBasicScheduledThread scheduledUpdater;
private final Frontend frontend;
public GeneralTab() {
frontend = null;
selectedServerData = null;
callback = null;
FrontendFXMLLoader.load(this, "fxml/primary_tabs/General.fxml");
this.scheduledUpdater = new PswgBasicScheduledThread("general-tab-updater", () -> requestUpdate());
this.frontend = LightspeedFrontendGUI.FRONTEND;
}
public void setFrontend(Frontend frontend) {
this.frontend = frontend;
}
public void setSelectedServerChangedCallback(SelectedServerChangedCallback callback) {
this.callback = callback;
@Override
public Parent getRoot() {
return rootGeneral;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
FXMLUtilities.onFxmlLoaded(this);
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();
serverComboBox.setConverter(new StringConverter<SharedServerData>() {
public String toString(SharedServerData server) { return server.getName(); }
public SharedServerData fromString(String string) { return frontend.getData().getServer(string); }
});
serverComboBox.getSelectionModel().selectedItemProperty().addListener((val, prev, next) -> {
Log.d("selected server manually '%s'", next);
frontend.getData().setSelectedServer(next);
updateUiDetails();
});
IntentManager.getInstance().registerForIntent(InboundPacketIntent.class, ipi -> Platform.runLater(() -> updateUi()));
updateUi();
scheduledUpdater.startWithFixedRate(10000, 10000);
}
@Override
public void terminate() {
scheduledUpdater.stop();
}
private void requestUpdate() {
SharedServerData selected = frontend.getData().getSelectedServer();
if (selected != null) {
frontend.loadServerDetailed(selected.getName(), response -> updateUi());
}
}
private void updateUi() {
updateServerList();
if (selectedServerData == null) {
Platform.runLater(() -> {
updateServerList();
updateUiDetails();
});
}
private void updateServerList() {
serverComboBox.setItems(frontend.getData().getServers());
}
private void updateUiDetails() {
SharedServerData selected = frontend.getData().getSelectedServer();
if (selected == null) {
setServerName("N/A");
setEmptyBuildStatus();
setEmptyDeploymentStatus();
setEmptyPopulationText();
setEmptyUptimeText();
} else {
SharedBuildData lastBuild = selectedServerData.getLastBuild();
SharedDeploymentData lastDeployment = selectedServerData.getLastDeployment();
setServerName(selectedServerData == null ? "N/A" : selectedServerData.getName());
SharedBuildData lastBuild = selected.getLastBuild();
SharedDeploymentData lastDeployment = selected.getLastDeployment();
setServerName(selected == null ? "N/A" : selected.getName());
if (lastBuild == null)
setEmptyBuildStatus();
else
@@ -132,27 +157,6 @@ public class GeneralTab extends GridPane implements Initializable {
}
}
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<SharedServerData> 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);
}
@@ -25,16 +25,9 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package com.projectswg.lightspeed.frontend;
package com.projectswg.lightspeed_frontend.gui.primary_tabs;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
TestConnect.class
})
public class TestFrontend {
public class PrimaryTabData {
}
@@ -28,25 +28,26 @@
package com.projectswg.lightspeed_frontend.intents;
import com.projectswg.common.control.Intent;
import com.projectswg.common.network.packets.Packet;
public class ConnectionStateUpdateIntent extends Intent {
public class InboundPacketIntent extends Intent {
private boolean connected;
private Packet packet;
public ConnectionStateUpdateIntent() {
this(false);
public InboundPacketIntent() {
}
public ConnectionStateUpdateIntent(boolean connected) {
setConnected(connected);
public InboundPacketIntent(Packet packet) {
setPacket(packet);
}
public boolean isConnected() {
return connected;
public Packet getPacket() {
return packet;
}
public void setConnected(boolean connected) {
this.connected = connected;
public void setPacket(Packet packet) {
this.packet = packet;
}
}
@@ -31,11 +31,9 @@ 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 {

Some files were not shown because too many files have changed in this diff Show More