mirror of
https://github.com/ProjectSWGCore/pswgcommon.git
synced 2026-01-17 00:04:25 -05:00
Initial Commit
This commit is contained in:
6
.classpath
Normal file
6
.classpath
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.settings
|
||||
bin
|
||||
17
.project
Normal file
17
.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>PSWGCommon</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
BIN
PSWGCommon.jar
Normal file
BIN
PSWGCommon.jar
Normal file
Binary file not shown.
120
src/com/projectswg/common/callback/CallbackManager.java
Normal file
120
src/com/projectswg/common/callback/CallbackManager.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/***********************************************************************************
|
||||
* 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 java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.projectswg.common.concurrency.PswgThreadPool;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
|
||||
public class CallbackManager<T> {
|
||||
|
||||
private final PswgThreadPool executor;
|
||||
private final List<T> callbacks;
|
||||
private final AtomicInteger runningTasks;
|
||||
|
||||
public CallbackManager(String name) {
|
||||
this(name, 1);
|
||||
}
|
||||
|
||||
public CallbackManager(String name, int threadCount) {
|
||||
this.executor = new PswgThreadPool(threadCount, name);
|
||||
this.callbacks = new ArrayList<>();
|
||||
this.runningTasks = new AtomicInteger(0);
|
||||
}
|
||||
|
||||
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 void start() {
|
||||
executor.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
executor.stop();
|
||||
}
|
||||
|
||||
public boolean awaitTermination(long timeout, TimeUnit unit) {
|
||||
return executor.awaitTermination(unit.toMillis(timeout));
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return executor.isRunning();
|
||||
}
|
||||
|
||||
public boolean isQueueEmpty() {
|
||||
return runningTasks.get() == 0;
|
||||
}
|
||||
|
||||
public boolean callOnEach(CallCallback<T> call) {
|
||||
runningTasks.incrementAndGet();
|
||||
return executor.execute(() -> {
|
||||
synchronized (callbacks) {
|
||||
for (T callback : callbacks) {
|
||||
try {
|
||||
call.run(callback);
|
||||
} catch (Throwable t) {
|
||||
Log.e(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
runningTasks.decrementAndGet();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public interface CallCallback<T> {
|
||||
void run(T callback);
|
||||
}
|
||||
}
|
||||
64
src/com/projectswg/common/concurrency/Delay.java
Normal file
64
src/com/projectswg/common/concurrency/Delay.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/***********************************************************************************
|
||||
* 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.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
public class Delay {
|
||||
|
||||
public static boolean sleepNano(long nanos) {
|
||||
LockSupport.parkNanos(nanos);
|
||||
return isInterrupted();
|
||||
}
|
||||
|
||||
public static boolean sleepMicro(long micro) {
|
||||
return sleepNano(micro * 1000);
|
||||
}
|
||||
|
||||
public static boolean sleepMilli(long milli) {
|
||||
return sleepNano(milli * 1000000);
|
||||
}
|
||||
|
||||
public static boolean sleepSeconds(long sec) {
|
||||
return sleepNano(sec * 1000000000);
|
||||
}
|
||||
|
||||
public static boolean sleep(long time, TimeUnit unit) {
|
||||
return sleepNano(unit.toNanos(time));
|
||||
}
|
||||
|
||||
public static boolean isInterrupted() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
public static void clearInterrupted() {
|
||||
Thread.interrupted();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/***********************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
public void execute(long delay, Runnable runnable) {
|
||||
throw new UnsupportedOperationException("Runnable is defined in the constructor!");
|
||||
}
|
||||
|
||||
@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!");
|
||||
}
|
||||
|
||||
}
|
||||
65
src/com/projectswg/common/concurrency/PswgBasicThread.java
Normal file
65
src/com/projectswg/common/concurrency/PswgBasicThread.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/***********************************************************************************
|
||||
* 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 boolean execute(Runnable runnable) {
|
||||
throw new UnsupportedOperationException("Runnable is defined in the constructor!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <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.debug.Assert;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
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) {
|
||||
Log.e(t);
|
||||
}
|
||||
}, 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) {
|
||||
Log.e(t);
|
||||
}
|
||||
}, initialDelay, time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void execute(long delay, Runnable runnable) {
|
||||
Assert.test(running.get());
|
||||
executor.schedule(() -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable t) {
|
||||
Log.e(t);
|
||||
}
|
||||
}, delay, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/***********************************************************************************
|
||||
* 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.Queue;
|
||||
|
||||
public class PswgTaskThreadPool<T> extends PswgThreadPool {
|
||||
|
||||
private final Queue<T> tasks;
|
||||
private final Runnable runner;
|
||||
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(Runnable runnable) {
|
||||
throw new UnsupportedOperationException("Runnable are posted automatically by addTask!");
|
||||
}
|
||||
|
||||
public void addTask(T t) {
|
||||
synchronized (tasks) {
|
||||
tasks.add(t);
|
||||
}
|
||||
super.execute(runner);
|
||||
}
|
||||
|
||||
public interface TaskExecutor<T> {
|
||||
void run(T t);
|
||||
}
|
||||
|
||||
}
|
||||
120
src/com/projectswg/common/concurrency/PswgThreadPool.java
Normal file
120
src/com/projectswg/common/concurrency/PswgThreadPool.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug.Assert;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
public class PswgThreadPool {
|
||||
|
||||
private final AtomicBoolean running;
|
||||
private final int nThreads;
|
||||
private final ThreadFactory threadFactory;
|
||||
private ExecutorService executor;
|
||||
private volatile boolean interruptOnStop;
|
||||
|
||||
public PswgThreadPool(int nThreads, String nameFormat) {
|
||||
this.running = new AtomicBoolean(false);
|
||||
this.nThreads = nThreads;
|
||||
this.threadFactory = new CustomThreadFactory(nameFormat);
|
||||
this.executor = null;
|
||||
this.interruptOnStop = false;
|
||||
}
|
||||
|
||||
public void setInterruptOnStop(boolean interrupt) {
|
||||
this.interruptOnStop = interrupt;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
Assert.test(!running.getAndSet(true));
|
||||
executor = Executors.newFixedThreadPool(nThreads, threadFactory);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
Assert.test(running.getAndSet(false));
|
||||
if (interruptOnStop)
|
||||
executor.shutdownNow();
|
||||
else
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
public boolean execute(Runnable runnable) {
|
||||
if (!running.get())
|
||||
return false;
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable t) {
|
||||
Log.e(t);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
129
src/com/projectswg/common/concurrency/SmartLock.java
Normal file
129
src/com/projectswg/common/concurrency/SmartLock.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/***********************************************************************************
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
182
src/com/projectswg/common/concurrency/SynchronizedList.java
Normal file
182
src/com/projectswg/common/concurrency/SynchronizedList.java
Normal file
@@ -0,0 +1,182 @@
|
||||
/************************************************************************************
|
||||
* 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 synchronized 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 synchronized License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General public synchronized License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.concurrency;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SynchronizedList<E> implements List<E> {
|
||||
|
||||
private final List<E> list;
|
||||
|
||||
public SynchronizedList() {
|
||||
this.list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public SynchronizedList(List<E> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public synchronized void forEach(Consumer<? super E> action) {
|
||||
list.forEach(action);
|
||||
}
|
||||
|
||||
public synchronized int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized boolean contains(Object o) {
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
public synchronized Iterator<E> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public synchronized Object[] toArray() {
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
public synchronized <T> T[] toArray(T[] a) {
|
||||
return list.toArray(a);
|
||||
}
|
||||
|
||||
public synchronized boolean add(E e) {
|
||||
return list.add(e);
|
||||
}
|
||||
|
||||
public synchronized boolean remove(Object o) {
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
public synchronized boolean containsAll(Collection<?> c) {
|
||||
return list.containsAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean addAll(Collection<? extends E> c) {
|
||||
return list.addAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean addAll(int index, Collection<? extends E> c) {
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
|
||||
public synchronized boolean removeAll(Collection<?> c) {
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean retainAll(Collection<?> c) {
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
public synchronized void replaceAll(UnaryOperator<E> operator) {
|
||||
list.replaceAll(operator);
|
||||
}
|
||||
|
||||
public synchronized boolean removeIf(Predicate<? super E> filter) {
|
||||
return list.removeIf(filter);
|
||||
}
|
||||
|
||||
public synchronized void sort(Comparator<? super E> c) {
|
||||
list.sort(c);
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
list.clear();
|
||||
}
|
||||
|
||||
public synchronized boolean equals(Object o) {
|
||||
return list.equals(o);
|
||||
}
|
||||
|
||||
public synchronized int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
public synchronized E get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public synchronized E set(int index, E element) {
|
||||
return list.set(index, element);
|
||||
}
|
||||
|
||||
public synchronized void add(int index, E element) {
|
||||
list.add(index, element);
|
||||
}
|
||||
|
||||
public synchronized Stream<E> stream() {
|
||||
return list.stream();
|
||||
}
|
||||
|
||||
public synchronized E remove(int index) {
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
public synchronized Stream<E> parallelStream() {
|
||||
return list.parallelStream();
|
||||
}
|
||||
|
||||
public synchronized int indexOf(Object o) {
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
public synchronized int lastIndexOf(Object o) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public synchronized ListIterator<E> listIterator() {
|
||||
return list.listIterator();
|
||||
}
|
||||
|
||||
public synchronized ListIterator<E> listIterator(int index) {
|
||||
return list.listIterator(index);
|
||||
}
|
||||
|
||||
public synchronized List<E> subList(int fromIndex, int toIndex) {
|
||||
return list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
public synchronized Spliterator<E> spliterator() {
|
||||
return list.spliterator();
|
||||
}
|
||||
|
||||
}
|
||||
111
src/com/projectswg/common/concurrency/SynchronizedMap.java
Normal file
111
src/com/projectswg/common/concurrency/SynchronizedMap.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/************************************************************************************
|
||||
* 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 synchronized 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 synchronized License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General public synchronized License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.concurrency;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SynchronizedMap<K, V> implements Map<K, V> {
|
||||
|
||||
private final Map<K, V> map;
|
||||
|
||||
public SynchronizedMap() {
|
||||
this.map = new HashMap<>();
|
||||
}
|
||||
|
||||
public SynchronizedMap(Map<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public synchronized int hashCode() {
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
public synchronized boolean equals(Object o) {
|
||||
return map.equals(o);
|
||||
}
|
||||
|
||||
public synchronized String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
public synchronized int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized V get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public synchronized boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public synchronized V put(K key, V value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
public synchronized void putAll(Map<? extends K, ? extends V> m) {
|
||||
map.putAll(m);
|
||||
}
|
||||
|
||||
public synchronized V remove(Object key) {
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public synchronized boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
public synchronized Set<K> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public synchronized Collection<V> values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
public synchronized Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public synchronized V replace(K key, V value) {
|
||||
return map.replace(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
151
src/com/projectswg/common/concurrency/SynchronizedQueue.java
Normal file
151
src/com/projectswg/common/concurrency/SynchronizedQueue.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/***********************************************************************************
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
131
src/com/projectswg/common/concurrency/SynchronizedSet.java
Normal file
131
src/com/projectswg/common/concurrency/SynchronizedSet.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/************************************************************************************
|
||||
* 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 synchronized 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 synchronized License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General public synchronized License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.concurrency;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SynchronizedSet<E> implements Set<E> {
|
||||
|
||||
private final Set<E> set;
|
||||
|
||||
public SynchronizedSet() {
|
||||
this.set = new HashSet<>();
|
||||
}
|
||||
|
||||
public SynchronizedSet(Set<E> set) {
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
public synchronized void forEach(Consumer<? super E> action) {
|
||||
set.forEach(action);
|
||||
}
|
||||
|
||||
public synchronized int size() {
|
||||
return set.size();
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized boolean contains(Object o) {
|
||||
return set.contains(o);
|
||||
}
|
||||
|
||||
public synchronized Iterator<E> iterator() {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public synchronized Object[] toArray() {
|
||||
return set.toArray();
|
||||
}
|
||||
|
||||
public synchronized <T> T[] toArray(T[] a) {
|
||||
return set.toArray(a);
|
||||
}
|
||||
|
||||
public synchronized boolean add(E e) {
|
||||
return set.add(e);
|
||||
}
|
||||
|
||||
public synchronized boolean remove(Object o) {
|
||||
return set.remove(o);
|
||||
}
|
||||
|
||||
public synchronized boolean containsAll(Collection<?> c) {
|
||||
return set.containsAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean addAll(Collection<? extends E> c) {
|
||||
return set.addAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean retainAll(Collection<?> c) {
|
||||
return set.retainAll(c);
|
||||
}
|
||||
|
||||
public synchronized boolean removeAll(Collection<?> c) {
|
||||
return set.removeAll(c);
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
set.clear();
|
||||
}
|
||||
|
||||
public synchronized boolean equals(Object o) {
|
||||
return set.equals(o);
|
||||
}
|
||||
|
||||
public synchronized int hashCode() {
|
||||
return set.hashCode();
|
||||
}
|
||||
|
||||
public synchronized Spliterator<E> spliterator() {
|
||||
return set.spliterator();
|
||||
}
|
||||
|
||||
public synchronized boolean removeIf(Predicate<? super E> filter) {
|
||||
return set.removeIf(filter);
|
||||
}
|
||||
|
||||
public synchronized Stream<E> stream() {
|
||||
return set.stream();
|
||||
}
|
||||
|
||||
public synchronized Stream<E> parallelStream() {
|
||||
return set.parallelStream();
|
||||
}
|
||||
|
||||
}
|
||||
168
src/com/projectswg/common/control/Intent.java
Normal file
168
src/com/projectswg/common/control/Intent.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/***********************************************************************************
|
||||
* 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
|
||||
*/
|
||||
protected synchronized void markAsComplete(IntentManager intentManager) {
|
||||
this.complete = true;
|
||||
if (sequential != null)
|
||||
sequential.broadcast(intentManager);
|
||||
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) {
|
||||
broadcastAfterIntent(i, IntentManager.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the intent as the parameter to finish before this intent
|
||||
* starts
|
||||
* @param i the intent to execute after
|
||||
* @param intentManager the intent manager to broadcast this intent on
|
||||
*/
|
||||
public synchronized void broadcastAfterIntent(Intent i, IntentManager intentManager) {
|
||||
if (i == null) {
|
||||
broadcast(intentManager);
|
||||
return;
|
||||
}
|
||||
synchronized (i) {
|
||||
if (i.isComplete())
|
||||
broadcast(intentManager);
|
||||
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) {
|
||||
broadcastWithIntent(i, IntentManager.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the intent as the parameter to start before this intent starts
|
||||
* @param i the intent to execute with
|
||||
* @param intentManager the intent manager to broadcast this intent on
|
||||
*/
|
||||
public synchronized void broadcastWithIntent(Intent i, IntentManager intentManager) {
|
||||
if (i == null) {
|
||||
broadcast(intentManager);
|
||||
return;
|
||||
}
|
||||
synchronized (i) {
|
||||
if (!isComplete()) {
|
||||
setAsParallel(i);
|
||||
}
|
||||
broadcast(intentManager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts this node to the system
|
||||
*/
|
||||
public synchronized void broadcast() {
|
||||
broadcast(IntentManager.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts this node to the system with the specified intent manager
|
||||
*
|
||||
* @param intentManager the intent manager to broadcast this intent on
|
||||
*/
|
||||
public synchronized void broadcast(IntentManager intentManager) {
|
||||
if (broadcasted)
|
||||
throw new IllegalStateException("Intent has already been broadcasted!");
|
||||
broadcasted = true;
|
||||
intentManager.broadcastIntent(this);
|
||||
if (parallel != null)
|
||||
parallel.broadcast(intentManager);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
67
src/com/projectswg/common/control/IntentChain.java
Normal file
67
src/com/projectswg/common/control/IntentChain.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/************************************************************************************
|
||||
* 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 IntentManager intentManager;
|
||||
private final Object mutex;
|
||||
private Intent i;
|
||||
|
||||
public IntentChain() {
|
||||
this(IntentManager.getInstance());
|
||||
}
|
||||
|
||||
public IntentChain(IntentManager intentManager) {
|
||||
this(intentManager, null);
|
||||
}
|
||||
|
||||
public IntentChain(Intent i) {
|
||||
this(IntentManager.getInstance(), i);
|
||||
}
|
||||
|
||||
public IntentChain(IntentManager intentManager, Intent i) {
|
||||
this.intentManager = intentManager;
|
||||
this.mutex = new Object();
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
synchronized (mutex) {
|
||||
i = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcastAfter(Intent i) {
|
||||
synchronized (mutex) {
|
||||
i.broadcastAfterIntent(this.i, intentManager);
|
||||
this.i = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
134
src/com/projectswg/common/control/IntentManager.java
Normal file
134
src/com/projectswg/common/control/IntentManager.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/***********************************************************************************
|
||||
* 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.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.projectswg.common.concurrency.PswgTaskThreadPool;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
public class IntentManager {
|
||||
|
||||
private static final IntentManager INSTANCE = new IntentManager();
|
||||
|
||||
private final Map <Class<Intent>, List<Consumer<Intent>>> intentRegistrations;
|
||||
private final PswgTaskThreadPool<Intent> broadcastThreads;
|
||||
private final AtomicBoolean initialized;
|
||||
|
||||
public IntentManager() {
|
||||
this.intentRegistrations = new HashMap<>();
|
||||
int threadCount = Runtime.getRuntime().availableProcessors() * 10;
|
||||
this.broadcastThreads = new PswgTaskThreadPool<>(threadCount, "intent-processor-%d", i -> broadcast(i));
|
||||
this.broadcastThreads.setInterruptOnStop(true);
|
||||
this.initialized = new AtomicBoolean(false);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (initialized.getAndSet(true))
|
||||
return;
|
||||
broadcastThreads.start();
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
if (!initialized.getAndSet(false))
|
||||
return;
|
||||
broadcastThreads.stop();
|
||||
}
|
||||
|
||||
public void broadcastIntent(Intent i) {
|
||||
if (i == null)
|
||||
throw new NullPointerException("Intent cannot be null!");
|
||||
broadcastThreads.addTask(i);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Intent> void registerForIntent(Class<T> c, Consumer<T> r) {
|
||||
if (r == null)
|
||||
throw new NullPointerException("Cannot register a null consumer for an intent");
|
||||
synchronized (intentRegistrations) {
|
||||
List <Consumer<Intent>> intents = intentRegistrations.get(c);
|
||||
if (intents == null) {
|
||||
intents = new CopyOnWriteArrayList<>();
|
||||
intentRegistrations.put((Class<Intent>) c, intents);
|
||||
}
|
||||
synchronized (intents) {
|
||||
intents.add((Consumer<Intent>) r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Intent> void unregisterForIntent(Class<T> c, Consumer<T> r) {
|
||||
if (r == null)
|
||||
throw new NullPointerException("Cannot register a null consumer for an intent");
|
||||
synchronized (intentRegistrations) {
|
||||
List <Consumer<Intent>> intents = intentRegistrations.get(c);
|
||||
if (intents == null)
|
||||
return;
|
||||
synchronized (intents) {
|
||||
intents.remove(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcast(Intent i) {
|
||||
List <Consumer<Intent>> receivers;
|
||||
synchronized (intentRegistrations) {
|
||||
receivers = intentRegistrations.get(i.getClass());
|
||||
}
|
||||
try {
|
||||
if (receivers == null)
|
||||
return;
|
||||
|
||||
for (Consumer<Intent> r : receivers) {
|
||||
broadcast(r, i);
|
||||
}
|
||||
} finally {
|
||||
i.markAsComplete(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcast(Consumer<Intent> r, Intent i) {
|
||||
try {
|
||||
r.accept(i);
|
||||
} catch (Throwable t) {
|
||||
Log.e("Fatal Exception while processing intent: " + i);
|
||||
Log.e(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntentManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
235
src/com/projectswg/common/control/IntentQueue.java
Normal file
235
src/com/projectswg/common/control/IntentQueue.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/************************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
41
src/com/projectswg/common/control/IntentReceiver.java
Normal file
41
src/com/projectswg/common/control/IntentReceiver.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.control;
|
||||
|
||||
|
||||
public interface IntentReceiver {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void onIntentReceived(Intent i);
|
||||
|
||||
}
|
||||
198
src/com/projectswg/common/control/Manager.java
Normal file
198
src/com/projectswg/common/control/Manager.java
Normal file
@@ -0,0 +1,198 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug.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);
|
||||
s.setIntentManager(getIntentManager());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIntentManager(IntentManager intentManager) {
|
||||
super.setIntentManager(intentManager);
|
||||
synchronized (children) {
|
||||
for (Service s : children) {
|
||||
s.setIntentManager(intentManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
117
src/com/projectswg/common/control/Service.java
Normal file
117
src/com/projectswg/common/control/Service.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/***********************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A Service is a class that does a specific job for the application
|
||||
*/
|
||||
public abstract class Service {
|
||||
|
||||
private IntentManager intentManager;
|
||||
|
||||
public Service() {
|
||||
this.intentManager = IntentManager.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers for the intent using the specified consumer
|
||||
* @param c the class of intent to register for
|
||||
* @param consumer the consumer to run when the intent is fired
|
||||
*/
|
||||
protected <T extends Intent> void registerForIntent(Class<T> c, Consumer<T> consumer) {
|
||||
intentManager.registerForIntent(c, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters for the intent using the specified consumer
|
||||
* @param c the class of intent to unregister
|
||||
* @param consumer the consumer that was previous registered
|
||||
*/
|
||||
protected <T extends Intent> void unregisterForIntent(Class<T> c, Consumer<T> consumer) {
|
||||
intentManager.unregisterForIntent(c, consumer);
|
||||
}
|
||||
|
||||
public void setIntentManager(IntentManager intentManager) {
|
||||
if (intentManager == null)
|
||||
throw new NullPointerException("IntentManager cannot be null!");
|
||||
this.intentManager = intentManager;
|
||||
}
|
||||
|
||||
public IntentManager getIntentManager() {
|
||||
return intentManager;
|
||||
}
|
||||
|
||||
}
|
||||
111
src/com/projectswg/common/debug/Assert.java
Normal file
111
src/com/projectswg/common/debug/Assert.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
225
src/com/projectswg/common/debug/Log.java
Normal file
225
src/com/projectswg/common/debug/Log.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class Log {
|
||||
|
||||
private static Log INSTANCE = null;
|
||||
|
||||
private final List<LogWrapper> wrappers;
|
||||
private final Lock logLock;
|
||||
private final DateFormat timeFormat;
|
||||
|
||||
private Log() {
|
||||
this.wrappers = new ArrayList<>();
|
||||
this.logLock = new ReentrantLock(true);
|
||||
this.timeFormat = new SimpleDateFormat("dd-MM-yy HH:mm:ss.SSS");
|
||||
}
|
||||
|
||||
private void logAddWrapper(LogWrapper wrapper) {
|
||||
wrappers.add(wrapper);
|
||||
}
|
||||
|
||||
private void logImplementation(LogLevel level, String str, Object ... args) {
|
||||
String date = timeFormat.format(System.currentTimeMillis());
|
||||
String logStr;
|
||||
if (args.length == 0)
|
||||
logStr = date + ' ' + level.getChar() + ": " + str;
|
||||
else
|
||||
logStr = date + ' ' + level.getChar() + ": " + String.format(str, args);
|
||||
for (LogWrapper wrapper : wrappers) {
|
||||
wrapper.onLog(level, logStr);
|
||||
}
|
||||
}
|
||||
|
||||
private void lock() {
|
||||
logLock.lock();
|
||||
}
|
||||
|
||||
private void unlock() {
|
||||
logLock.unlock();
|
||||
}
|
||||
|
||||
private static synchronized final Log getInstance() {
|
||||
if (INSTANCE == null)
|
||||
INSTANCE = new Log();
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static final void addWrapper(LogWrapper wrapper) {
|
||||
getInstance().logAddWrapper(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
try {
|
||||
getInstance().lock();
|
||||
getInstance().logImplementation(level, str, args);
|
||||
} finally {
|
||||
getInstance().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
Log instance = getInstance();
|
||||
try {
|
||||
String header1 = String.format("Exception in thread \"%s\" %s: %s", Thread.currentThread().getName(), exception.getClass().getName(), exception.getMessage());
|
||||
String header2 = String.format("Caused by: %s: %s", exception.getClass().getCanonicalName(), exception.getMessage());
|
||||
StackTraceElement [] elements = exception.getStackTrace();
|
||||
instance.lock();
|
||||
instance.logImplementation(level, header1);
|
||||
instance.logImplementation(level, header2);
|
||||
for (StackTraceElement e : elements) {
|
||||
instance.logImplementation(level, " " + e.toString());
|
||||
}
|
||||
} finally {
|
||||
instance.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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; }
|
||||
}
|
||||
|
||||
}
|
||||
36
src/com/projectswg/common/debug/LogWrapper.java
Normal file
36
src/com/projectswg/common/debug/LogWrapper.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug;
|
||||
|
||||
import com.projectswg.common.debug.Log.LogLevel;
|
||||
|
||||
public interface LogWrapper {
|
||||
|
||||
void onLog(LogLevel level, String str);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.projectswg.common.debug.log_wrapper;
|
||||
|
||||
import com.projectswg.common.debug.Log.LogLevel;
|
||||
import com.projectswg.common.debug.LogWrapper;
|
||||
|
||||
public class ConsoleLogWrapper implements LogWrapper {
|
||||
|
||||
private final LogLevel level;
|
||||
|
||||
public ConsoleLogWrapper(LogLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLog(LogLevel level, String str) {
|
||||
if (this.level.compareTo(level) > 0)
|
||||
return;
|
||||
if (level.compareTo(LogLevel.WARN) >= 0)
|
||||
System.err.println(str);
|
||||
else
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.projectswg.common.debug.log_wrapper;
|
||||
|
||||
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 com.projectswg.common.debug.LogWrapper;
|
||||
import com.projectswg.common.debug.Log.LogLevel;
|
||||
|
||||
public class FileLogWrapper implements LogWrapper {
|
||||
|
||||
private final BufferedWriter writer;
|
||||
|
||||
public FileLogWrapper(File file) throws IOException {
|
||||
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws IOException {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLog(LogLevel level, String str) {
|
||||
try {
|
||||
writer.write(str);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
183
src/com/projectswg/common/info/Config.java
Normal file
183
src/com/projectswg/common/info/Config.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/***********************************************************************************
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
154
src/com/projectswg/common/info/ConfigData.java
Normal file
154
src/com/projectswg/common/info/ConfigData.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/***********************************************************************************
|
||||
* 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;
|
||||
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
36
src/com/projectswg/common/info/PostgresqlDatabase.java
Normal file
36
src/com/projectswg/common/info/PostgresqlDatabase.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/***********************************************************************************
|
||||
* 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;
|
||||
|
||||
public class PostgresqlDatabase extends RelationalDatabase {
|
||||
|
||||
public PostgresqlDatabase(String host, String db, String user, String pass) {
|
||||
super("org.postgresql.Driver", "postgresql", host, db, user, pass, "");
|
||||
}
|
||||
|
||||
}
|
||||
192
src/com/projectswg/common/info/RelationalDatabase.java
Normal file
192
src/com/projectswg/common/info/RelationalDatabase.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/***********************************************************************************
|
||||
* 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;
|
||||
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
447
src/com/projectswg/common/info/RelationalServerData.java
Normal file
447
src/com/projectswg/common/info/RelationalServerData.java
Normal file
@@ -0,0 +1,447 @@
|
||||
/***********************************************************************************
|
||||
* 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;
|
||||
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
278
src/com/projectswg/common/info/RelationalServerFactory.java
Normal file
278
src/com/projectswg/common/info/RelationalServerFactory.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/************************************************************************************
|
||||
* 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;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
public class RelationalServerFactory {
|
||||
|
||||
private static final RelationalServerFactory INSTANCE = new RelationalServerFactory();
|
||||
private static final AtomicReference<String> BASE_PATH = new AtomicReference<>("");
|
||||
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);
|
||||
}
|
||||
|
||||
public static void setBasePath(String basePath) {
|
||||
BASE_PATH.set(basePath);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
40
src/com/projectswg/common/javafx/FXMLController.java
Normal file
40
src/com/projectswg/common/javafx/FXMLController.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Parent;
|
||||
|
||||
public interface FXMLController extends Initializable {
|
||||
|
||||
Parent getRoot();
|
||||
default void terminate() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
88
src/com/projectswg/common/javafx/FXMLUtilities.java
Normal file
88
src/com/projectswg/common/javafx/FXMLUtilities.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
import javafx.fxml.FXMLLoader;
|
||||
|
||||
public class FXMLUtilities {
|
||||
|
||||
private static final Set<FXMLController> CONTROLLERS = new HashSet<>();
|
||||
|
||||
public static void terminate() {
|
||||
synchronized (CONTROLLERS) {
|
||||
Log.i("Terminating FXML controllers");
|
||||
for (FXMLController controller : CONTROLLERS) {
|
||||
controller.terminate();
|
||||
}
|
||||
CONTROLLERS.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static ResourceBundle getResourceBundle(Locale locale) {
|
||||
return ResourceBundle.getBundle("bundles.strings.strings", locale);
|
||||
}
|
||||
|
||||
public static void onFxmlLoaded(FXMLController controller) {
|
||||
synchronized (CONTROLLERS) {
|
||||
CONTROLLERS.add(controller);
|
||||
}
|
||||
}
|
||||
|
||||
public static FXMLController loadFxml(String fxml, Locale locale) {
|
||||
try {
|
||||
File file = ResourceUtilities.getResource("fxml/" + fxml);
|
||||
if (file == null || !file.isFile()) {
|
||||
Log.e("Unable to load fxml - doesn't exist: %s", file);
|
||||
return null;
|
||||
}
|
||||
Log.i("Loading fxml: %s", file);
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(file.toURI().toURL());
|
||||
fxmlLoader.setResources(getResourceBundle(locale));
|
||||
fxmlLoader.load();
|
||||
onFxmlLoaded(fxmlLoader.getController());
|
||||
synchronized (CONTROLLERS) {
|
||||
CONTROLLERS.add(fxmlLoader.getController());
|
||||
}
|
||||
return fxmlLoader.getController();
|
||||
} catch (IOException e) {
|
||||
Log.e("Error loading fmxl: %s", fxml);
|
||||
Log.e(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
85
src/com/projectswg/common/javafx/PSWGBooleanProperty.java
Normal file
85
src/com/projectswg/common/javafx/PSWGBooleanProperty.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class PSWGBooleanProperty extends SimpleBooleanProperty {
|
||||
|
||||
private final Set<ChangeListener<? super Boolean>> listeners;
|
||||
private final Set<Property<Boolean>> properties;
|
||||
|
||||
public PSWGBooleanProperty() {
|
||||
super();
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public PSWGBooleanProperty(boolean initialValue) {
|
||||
super(initialValue);
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super Boolean> listener) {
|
||||
listeners.add(listener);
|
||||
super.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super Boolean> listener) {
|
||||
listeners.remove(listener);
|
||||
super.removeListener(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
for (ChangeListener<? super Boolean> listener : listeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindBidirectional(Property<Boolean> property) {
|
||||
super.bindBidirectional(property);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void unbindAll() {
|
||||
unbind();
|
||||
for (Property<Boolean> property : properties) {
|
||||
super.unbindBidirectional(property);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
85
src/com/projectswg/common/javafx/PSWGDoubleProperty.java
Normal file
85
src/com/projectswg/common/javafx/PSWGDoubleProperty.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class PSWGDoubleProperty extends SimpleDoubleProperty {
|
||||
|
||||
private final Set<ChangeListener<? super Number>> listeners;
|
||||
private final Set<Property<Number>> properties;
|
||||
|
||||
public PSWGDoubleProperty() {
|
||||
super();
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public PSWGDoubleProperty(double initialValue) {
|
||||
super(initialValue);
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super Number> listener) {
|
||||
listeners.add(listener);
|
||||
super.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super Number> listener) {
|
||||
listeners.remove(listener);
|
||||
super.removeListener(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
for (ChangeListener<? super Number> listener : listeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindBidirectional(Property<Number> property) {
|
||||
super.bindBidirectional(property);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void unbindAll() {
|
||||
unbind();
|
||||
for (Property<Number> property : properties) {
|
||||
super.unbindBidirectional(property);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
85
src/com/projectswg/common/javafx/PSWGIntegerProperty.java
Normal file
85
src/com/projectswg/common/javafx/PSWGIntegerProperty.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class PSWGIntegerProperty extends SimpleIntegerProperty {
|
||||
|
||||
private final Set<ChangeListener<? super Number>> listeners;
|
||||
private final Set<Property<Number>> properties;
|
||||
|
||||
public PSWGIntegerProperty() {
|
||||
super();
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public PSWGIntegerProperty(int initialValue) {
|
||||
super(initialValue);
|
||||
listeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super Number> listener) {
|
||||
listeners.add(listener);
|
||||
super.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super Number> listener) {
|
||||
listeners.remove(listener);
|
||||
super.removeListener(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
for (ChangeListener<? super Number> listener : listeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindBidirectional(Property<Number> property) {
|
||||
super.bindBidirectional(property);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void unbindAll() {
|
||||
unbind();
|
||||
for (Property<Number> property : properties) {
|
||||
super.unbindBidirectional(property);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
104
src/com/projectswg/common/javafx/PSWGObjectProperty.java
Normal file
104
src/com/projectswg/common/javafx/PSWGObjectProperty.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class PSWGObjectProperty<T> extends SimpleObjectProperty<T> {
|
||||
|
||||
private final Set<ChangeListener<? super T>> listeners;
|
||||
private final Set<InvalidationListener> invalidationListeners;
|
||||
private final Set<Property<T>> properties;
|
||||
|
||||
public PSWGObjectProperty() {
|
||||
super();
|
||||
listeners = new HashSet<>();
|
||||
invalidationListeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public PSWGObjectProperty(T initialValue) {
|
||||
super(initialValue);
|
||||
listeners = new HashSet<>();
|
||||
invalidationListeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super T> listener) {
|
||||
super.addListener(listener);
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(InvalidationListener listener) {
|
||||
super.addListener(listener);
|
||||
invalidationListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super T> listener) {
|
||||
super.removeListener(listener);
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(InvalidationListener listener) {
|
||||
super.removeListener(listener);
|
||||
invalidationListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
for (ChangeListener<? super T> listener : listeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
for (InvalidationListener listener : invalidationListeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindBidirectional(Property<T> property) {
|
||||
super.bindBidirectional(property);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void unbindAll() {
|
||||
unbind();
|
||||
for (Property<T> property : properties) {
|
||||
super.unbindBidirectional(property);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
109
src/com/projectswg/common/javafx/PSWGStringProperty.java
Normal file
109
src/com/projectswg/common/javafx/PSWGStringProperty.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/***********************************************************************************
|
||||
* 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.javafx;
|
||||
|
||||
import java.text.Format;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public class PSWGStringProperty extends SimpleStringProperty {
|
||||
|
||||
private final Set<ChangeListener<? super String>> listeners;
|
||||
private final Set<InvalidationListener> invalidationListeners;
|
||||
private final Set<Property<?>> properties;
|
||||
|
||||
public PSWGStringProperty() {
|
||||
super();
|
||||
listeners = new HashSet<>();
|
||||
invalidationListeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
public PSWGStringProperty(String initialValue) {
|
||||
super(initialValue);
|
||||
listeners = new HashSet<>();
|
||||
invalidationListeners = new HashSet<>();
|
||||
properties = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ChangeListener<? super String> listener) {
|
||||
super.addListener(listener);
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(InvalidationListener listener) {
|
||||
super.addListener(listener);
|
||||
invalidationListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ChangeListener<? super String> listener) {
|
||||
super.removeListener(listener);
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
for (ChangeListener<? super String> listener : listeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
for (InvalidationListener listener : invalidationListeners) {
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void bindBidirectional(Property<String> property) {
|
||||
super.bindBidirectional(property);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void bindBidirectional(Property<?> property, Format format) {
|
||||
super.bindBidirectional(property, format);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public <T> void bindBidirectional(Property<T> property, StringConverter<T> converter) {
|
||||
super.bindBidirectional(property, converter);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public void unbindAll() {
|
||||
unbind();
|
||||
for (Property<?> property : properties) {
|
||||
super.unbindBidirectional(property);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
93
src/com/projectswg/common/javafx/ResourceUtilities.java
Normal file
93
src/com/projectswg/common/javafx/ResourceUtilities.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.javafx;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class ResourceUtilities {
|
||||
|
||||
private static final AtomicReference<String> THEME = new AtomicReference<>(".");
|
||||
private static final AtomicReference<Class<?>> SRC = new AtomicReference<>(ResourceUtilities.class);
|
||||
private static final String RESOURCES_PATH = "/res/";
|
||||
|
||||
public static void setTheme(String theme) {
|
||||
THEME.set(theme);
|
||||
}
|
||||
|
||||
public static void setPrimarySource(Class<?> c) {
|
||||
SRC.set(c);
|
||||
}
|
||||
|
||||
public static File getSourceDirectory() {
|
||||
try {
|
||||
return new File(SRC.get().getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static File getResourcesDirectory() {
|
||||
File source = getSourceDirectory();
|
||||
if (source == null)
|
||||
return null;
|
||||
return new File(source, RESOURCES_PATH);
|
||||
}
|
||||
|
||||
public static URI getResourceURI(String path) {
|
||||
File file = getResource(path);
|
||||
if (file == null)
|
||||
return null;
|
||||
return file.toURI();
|
||||
}
|
||||
|
||||
public static File getResource(String path) {
|
||||
try {
|
||||
String parent = new File(SRC.get().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent();
|
||||
return new File(parent, cleanupPath(RESOURCES_PATH + THEME.get() + '/' + path));
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static File getGeneralResource(String path) {
|
||||
try {
|
||||
String parent = new File(SRC.get().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent();
|
||||
return new File(parent, cleanupPath(RESOURCES_PATH + "common/" + path));
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String cleanupPath(String path) {
|
||||
return path.replace('/', File.separatorChar);
|
||||
}
|
||||
|
||||
}
|
||||
241
src/com/projectswg/common/network/NetBuffer.java
Normal file
241
src/com/projectswg/common/network/NetBuffer.java
Normal file
@@ -0,0 +1,241 @@
|
||||
/************************************************************************************
|
||||
* 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 boolean hasRemaining() {
|
||||
return data.hasRemaining();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
435
src/com/projectswg/common/network/NetBufferStream.java
Normal file
435
src/com/projectswg/common/network/NetBufferStream.java
Normal file
@@ -0,0 +1,435 @@
|
||||
/************************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
278
src/com/projectswg/common/network/TCPServer.java
Normal file
278
src/com/projectswg/common/network/TCPServer.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug.Assert;
|
||||
import com.projectswg.common.debug.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 final TCPServerListener listener;
|
||||
private ServerSocketChannel channel;
|
||||
|
||||
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 TCPServerListener();
|
||||
}
|
||||
|
||||
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 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 {
|
||||
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 TCPServerListener implements Runnable {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
private Thread thread;
|
||||
private boolean running;
|
||||
|
||||
public TCPServerListener() {
|
||||
buffer = ByteBuffer.allocateDirect(bufferSize);
|
||||
running = false;
|
||||
thread = null;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
running = true;
|
||||
thread = new Thread(this, "TCPServerListener-" + 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
222
src/com/projectswg/common/network/TCPSocket.java
Normal file
222
src/com/projectswg/common/network/TCPSocket.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/***********************************************************************************
|
||||
* 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.EOFException;
|
||||
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.concurrency.Delay;
|
||||
import com.projectswg.common.debug.Assert;
|
||||
import com.projectswg.common.debug.Log;
|
||||
|
||||
public class TCPSocket {
|
||||
|
||||
private final CallbackManager<TCPSocketCallback> callbackManager;
|
||||
private final TCPSocketListener listener;
|
||||
private final InetSocketAddress address;
|
||||
private final int bufferSize;
|
||||
private SocketChannel socket;
|
||||
|
||||
public TCPSocket(InetSocketAddress address, int bufferSize) {
|
||||
this.callbackManager = new CallbackManager<>("tcpsocket-"+address, 1);
|
||||
this.listener = new TCPSocketListener();
|
||||
this.address = address;
|
||||
this.bufferSize = bufferSize;
|
||||
this.socket = null;
|
||||
}
|
||||
|
||||
public int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public SocketChannel getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return socket != null && listener.isAlive();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return socket != null && socket.isConnected();
|
||||
}
|
||||
|
||||
public void setCallback(TCPSocketCallback callback) {
|
||||
callbackManager.setCallback(callback);
|
||||
}
|
||||
|
||||
public void removeCallback() {
|
||||
callbackManager.clearCallbacks();
|
||||
}
|
||||
|
||||
public boolean connect() {
|
||||
Assert.isNull(socket, "Socket must be null! Cannot connect twice!");
|
||||
Assert.test(!listener.isAlive(), "Listener must not be alive! Cannot connect twice!");
|
||||
try {
|
||||
callbackManager.start();
|
||||
socket = SocketChannel.open(address);
|
||||
if (socket.finishConnect()) {
|
||||
listener.start();
|
||||
callbackManager.callOnEach((callback) -> callback.onConnected(this));
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
callbackManager.stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean disconnect() {
|
||||
if (socket == null)
|
||||
return true;
|
||||
try {
|
||||
socket.close();
|
||||
if (listener.isAlive()) {
|
||||
listener.stop();
|
||||
listener.awaitTermination();
|
||||
}
|
||||
if (callbackManager.isRunning()) {
|
||||
callbackManager.callOnEach((callback) -> callback.onDisconnected(this));
|
||||
callbackManager.stop();
|
||||
}
|
||||
socket = null;
|
||||
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;
|
||||
private final AtomicBoolean alive;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
public TCPSocketListener() {
|
||||
this.running = new AtomicBoolean(false);
|
||||
this.alive = new AtomicBoolean(false);
|
||||
this.thread = null;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
Assert.test(!running.get(), "Cannot start listener! Already started!");
|
||||
Assert.isNull(thread, "Cannot start listener! Already started!");
|
||||
thread = new Thread(this);
|
||||
running.set(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
Assert.test(running.get(), "Cannot stop listener! Already stopped!");
|
||||
Assert.notNull(thread, "Cannot stop listener! Already stopped!");
|
||||
running.set(false);
|
||||
if (thread != null)
|
||||
thread.interrupt();
|
||||
thread = null;
|
||||
}
|
||||
|
||||
public void awaitTermination() {
|
||||
while (isAlive()) {
|
||||
if (!Delay.sleepMicro(5))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return alive.get();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
alive.set(true);
|
||||
SocketChannel sc = TCPSocket.this.socket;
|
||||
int bufferSize = TCPSocket.this.bufferSize;
|
||||
Assert.notNull(sc, "SocketChannel is null at start of listener run()!");
|
||||
Assert.test(bufferSize > 0, "Buffer size is <= 0 at start of listener run()!");
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize);
|
||||
while (running.get()) {
|
||||
waitIncoming(sc, buf, bufferSize);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
|
||||
} finally {
|
||||
running.set(false);
|
||||
alive.set(false);
|
||||
thread = null;
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void waitIncoming(SocketChannel sc, ByteBuffer buf, int bufferSize) throws IOException {
|
||||
buf.position(0);
|
||||
buf.limit(bufferSize);
|
||||
int n = sc.read(buf);
|
||||
buf.flip();
|
||||
if (n == 0)
|
||||
return;
|
||||
if (n < 0)
|
||||
throw new EOFException();
|
||||
byte [] data = new byte[n];
|
||||
buf.position(0);
|
||||
buf.get(data, 0, n);
|
||||
callbackManager.callOnEach((callback) -> callback.onIncomingData(TCPSocket.this, data));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
60
src/com/projectswg/common/utilities/ThreadUtilities.java
Normal file
60
src/com/projectswg/common/utilities/ThreadUtilities.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/***********************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
98
src/com/projectswg/common/utilities/TimeUtilities.java
Normal file
98
src/com/projectswg/common/utilities/TimeUtilities.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/***********************************************************************************
|
||||
* 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.debug.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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user