Initial Commit

This commit is contained in:
Josh Larson
2017-04-11 15:01:35 -05:00
commit af7c39c374
48 changed files with 6066 additions and 0 deletions

6
.classpath Normal file
View 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
View File

@@ -0,0 +1,2 @@
.settings
bin

17
.project Normal file
View 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

Binary file not shown.

View 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);
}
}

View 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();
}
}

View File

@@ -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!");
}
}

View 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!");
}
}

View File

@@ -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);
}
}
}

View 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.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);
}
}

View 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);
}
}
}

View 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();
}
}
}

View 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();
}
}

View 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);
}
}

View 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();
}
}

View 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();
}
}

View 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);
}
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}
}

View 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);
}

View 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);
}
}
}
}

View 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;
}
}

View 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
}
}

View 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; }
}
}

View 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);
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View 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();
}
}

View 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);
}
}
}

View 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, "");
}
}

View 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;
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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() {
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}
}

View 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));
}
}
}

View 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);
}
}
}

View 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);
}
}