Updated jlcommon (removed networking code) and added mongodb data saving optionally

This commit is contained in:
Josh Larson
2019-01-22 19:33:04 -06:00
parent afff6430ea
commit c12c22e1c7
8 changed files with 466 additions and 7 deletions

View File

@@ -18,7 +18,8 @@ repositories {
}
dependencies {
compile group: 'me.joshlarson', name: 'jlcommon', version: '1.8.4'
compile group: 'me.joshlarson', name: 'jlcommon', version: '1.9.0'
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.60'
compileOnly group: 'org.mongodb', name: 'mongodb-driver-sync', version: '3.9.1'
testCompile 'junit:junit:4.12'
}

View File

@@ -0,0 +1,356 @@
/***********************************************************************************
* Copyright (c) 2019 /// 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.data.encodables.mongo;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Function;
public class MongoData {
private final @NotNull Document doc;
public MongoData() {
this(new Document());
}
public MongoData(Document doc) {
this.doc = doc == null ? new Document() : doc;
}
public Document toDocument() {
return new Document(doc);
}
public boolean containsKey(String key) {
return doc.containsKey(key);
}
@Nullable
public Integer getInteger(String key) {
return doc.getInteger(key);
}
public int getInteger(String key, int defaultValue) {
return doc.getInteger(key, defaultValue);
}
@Nullable
public Long getLong(String key) {
return doc.getLong(key);
}
public long getLong(String key, long defaultValue) {
Long l = doc.getLong(key);
return l == null ? defaultValue : l;
}
@Nullable
public Float getFloat(String key) {
Double f = doc.getDouble(key);
return f == null ? null : f.floatValue();
}
public float getFloat(String key, float defaultValue) {
Double f = doc.getDouble(key);
return f == null ? defaultValue : f.floatValue();
}
@Nullable
public Double getDouble(String key) {
return doc.getDouble(key);
}
public double getDouble(String key, double defaultValue) {
Double d = doc.getDouble(key);
return d == null ? defaultValue : d;
}
@Nullable
public String getString(String key) {
return doc.getString(key);
}
public String getString(String key, String defaultValue) {
String str = doc.getString(key);
return str == null ? defaultValue : str;
}
@Nullable
public Boolean getBoolean(String key) {
return doc.getBoolean(key);
}
public boolean getBoolean(String key, boolean defaultValue) {
return doc.getBoolean(key, defaultValue);
}
@Nullable
public ObjectId getObjectId(String key) {
return doc.getObjectId(key);
}
@Nullable
public Instant getDate(String key) {
@SuppressWarnings("UseOfObsoleteDateTimeApi") // forced to by MongoDB
Date d = doc.getDate(key);
return d == null ? null : d.toInstant();
}
@NotNull
public <T> List<T> getArray(String key, Class<T> klass) {
List<?> mdbArray = doc.get(key, List.class);
List<T> ret = new ArrayList<>(mdbArray.size());
if (klass == Instant.class) {
for (Object o : mdbArray) {
if (o == null)
ret.add(null);
else
//noinspection UseOfObsoleteDateTimeApi
ret.add(klass.cast(((Date) o).toInstant()));
}
} else {
for (Object o : mdbArray) {
if (o == null)
ret.add(null);
else
ret.add(klass.cast(o));
}
}
return ret;
}
@NotNull
public MongoData getDocument(String key) {
return new MongoData(doc.get(key, Document.class));
}
/**
* Attempts to parse the document at the specified key. If the document exists, it will be parsed by the specified data instance.
* @param key the key to look up
* @param dataInstance the data instance to use
* @param <T> the parser type
* @return the parsed data, or null if the value does not exist
*/
@Nullable
public <T extends MongoPersistable> T getDocument(String key, T dataInstance) {
Document doc = this.doc.get(key, Document.class);
if (doc != null)
dataInstance.read(new MongoData(doc));
return dataInstance;
}
@NotNull
public <T> Map<String, T> getMap(String key, Class<T> klass) {
Document mdbMap = doc.get(key, Document.class);
Map<String, T> ret = new HashMap<>(mdbMap.size());
if (klass == Instant.class) {
for (Entry<String, Object> e : mdbMap.entrySet()) {
Object o = e.getValue();
if (o == null)
ret.put(e.getKey(), null);
else
//noinspection UseOfObsoleteDateTimeApi
ret.put(e.getKey(), klass.cast(((Date) o).toInstant()));
}
} else {
for (Entry<String, Object> e : mdbMap.entrySet()) {
Object o = e.getValue();
if (o == null)
ret.put(e.getKey(), null);
else
ret.put(e.getKey(), klass.cast(o));
}
}
return ret;
}
public void putInteger(String key, int i) {
assert !containsKey(key) : "key already exists";
doc.put(key, i);
}
public void putLong(String key, long l) {
assert !containsKey(key) : "key already exists";
doc.put(key, l);
}
public void putFloat(String key, float f) {
assert !containsKey(key) : "key already exists";
doc.put(key, f);
}
public void putDouble(String key, double d) {
assert !containsKey(key) : "key already exists";
doc.put(key, d);
}
public void putString(String key, String str) {
assert !containsKey(key) : "key already exists";
doc.put(key, str);
}
public void putBoolean(String key, boolean bool) {
assert !containsKey(key) : "key already exists";
doc.put(key, bool);
}
public void putObjectId(String key, ObjectId id) {
assert !containsKey(key) : "key already exists";
doc.put(key, id);
}
public void putDate(String key, Instant date) {
assert !containsKey(key) : "key already exists";
doc.put(key, Date.from(date));
}
public void putArray(String key, byte [] array) {
assert !containsKey(key) : "key already exists";
List<Integer> mdbArray = new ArrayList<>(array.length);
for (byte b : array)
mdbArray.add((int) b);
doc.put(key, mdbArray);
}
public void putArray(String key, short [] array) {
assert !containsKey(key) : "key already exists";
List<Integer> mdbArray = new ArrayList<>(array.length);
for (short s : array)
mdbArray.add((int) s);
doc.put(key, mdbArray);
}
public void putArray(String key, int [] array) {
assert !containsKey(key) : "key already exists";
doc.put(key, List.of(array));
}
public void putArray(String key, long [] array) {
assert !containsKey(key) : "key already exists";
doc.put(key, List.of(array));
}
public void putArray(String key, String [] array) {
assert !containsKey(key) : "key already exists";
doc.put(key, List.of(array));
}
public void putArray(String key, ObjectId [] array) {
assert !containsKey(key) : "key already exists";
doc.put(key, List.of(array));
}
public void putArray(String key, Instant [] array) {
assert !containsKey(key) : "key already exists";
@SuppressWarnings("UseOfObsoleteDateTimeApi") // forced to by MongoDB
List<Date> mdbArray = new ArrayList<>(array.length);
for (Instant i : array)
mdbArray.add(Date.from(i));
doc.put(key, mdbArray);
}
public void putArray(String key, List<?> array) {
assert !containsKey(key) : "key already exists";
List<Object> mdbArray = new ArrayList<>(array.size());
for (Object o : array) {
mdbArray.add(translatePut(o));
}
doc.put(key, mdbArray);
}
public <T> void putArray(String key, List<T> array, Function<T, ?> converter) {
assert !containsKey(key) : "key already exists";
List<Object> mdbArray = new ArrayList<>(array.size());
for (T o : array) {
mdbArray.add(translatePut(converter.apply(o)));
}
doc.put(key, mdbArray);
}
public void putDocument(String key, @NotNull MongoData doc) {
assert !containsKey(key) : "key already exists";
this.doc.put(key, doc.doc);
}
public <T extends MongoPersistable> void putDocument(String key, T data) {
assert !containsKey(key) : "key already exists";
if (data != null) {
MongoData dataDoc = new MongoData();
data.save(dataDoc);
doc.put(key, dataDoc.doc);
}
}
public void putMap(String key, Map<String, ?> data) {
MongoData doc = new MongoData();
for (Entry<String, ?> e : data.entrySet()) {
doc.doc.put(e.getKey(), translatePut(e.getValue()));
}
putDocument(key, doc);
}
public <T, S> void putMap(String key, Map<T, S> data, Function<T, String> keyExtractor) {
MongoData doc = new MongoData();
for (Entry<T, S> e : data.entrySet()) {
doc.doc.put(keyExtractor.apply(e.getKey()), translatePut(e.getValue()));
}
putDocument(key, doc);
}
public <T, S> void putMap(String key, Map<T, S> data, Function<T, String> keyExtractor, BiFunction<T, S, ?> valueExtractor) {
MongoData doc = new MongoData();
for (Entry<T, S> e : data.entrySet()) {
doc.doc.put(keyExtractor.apply(e.getKey()), translatePut(valueExtractor.apply(e.getKey(), e.getValue())));
}
putDocument(key, doc);
}
@SuppressWarnings("UseOfObsoleteDateTimeApi")
private Object translatePut(Object input) {
if (input instanceof Instant) {
return Date.from((Instant) input);
} else if (input instanceof String || input instanceof Boolean || input instanceof Long || input instanceof Date || input instanceof Document) {
return input;
} else if (input instanceof Float || input instanceof Double) {
return ((Number) input).doubleValue();
} else if (input instanceof Number) {
return ((Number) input).intValue();
} else
assert false : "bad object type: " + input;
return null;
}
}

View File

@@ -0,0 +1,35 @@
/***********************************************************************************
* Copyright (c) 2019 /// 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.data.encodables.mongo;
public interface MongoPersistable {
void read(MongoData data);
void save(MongoData data);
}

View File

@@ -26,12 +26,14 @@
***********************************************************************************/
package com.projectswg.common.data.encodables.oob;
import com.projectswg.common.data.encodables.mongo.MongoData;
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
import me.joshlarson.jlcommon.log.Log;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
import com.projectswg.common.persistable.Persistable;
public class StringId implements OutOfBandData, Persistable {
public class StringId implements OutOfBandData, Persistable, MongoPersistable {
private String key;
private String file;
@@ -94,6 +96,18 @@ public class StringId implements OutOfBandData, Persistable {
key = stream.getAscii();
}
@Override
public void read(MongoData data) {
file = data.getString("file");
key = data.getString("key");
}
@Override
public void save(MongoData data) {
data.putString("file", file);
data.putString("key", key);
}
@Override
public OutOfBandPackage.Type getOobType() {
return OutOfBandPackage.Type.STRING_ID;

View File

@@ -26,12 +26,14 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import com.projectswg.common.data.encodables.mongo.MongoData;
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
import com.projectswg.common.persistable.Persistable;
public class Location implements Encodable, Persistable {
public class Location implements Encodable, Persistable, MongoPersistable {
private static final Location ZERO = new Location(0, 0, 0, Terrain.GONE);
@@ -243,6 +245,21 @@ public class Location implements Encodable, Persistable {
terrain = Terrain.valueOf(stream.getAscii());
}
@Override
public void read(MongoData data) {
data.getDocument("orientation", orientation);
data.getDocument("point", point);
terrain = data.containsKey("terrain") ? Terrain.valueOf(data.getString("terrain")) : null;
}
@Override
public void save(MongoData data) {
data.putDocument("orientation", orientation);
data.putDocument("point", point);
if (terrain != null)
data.putString("terrain", terrain.name());
}
@Override
public String toString() {
return String.format("Location[TRN=%s, %s %s]", terrain, point, orientation);

View File

@@ -26,12 +26,14 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import com.projectswg.common.data.encodables.mongo.MongoData;
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
import com.projectswg.common.persistable.Persistable;
public class Point3D implements Encodable, Persistable {
public class Point3D implements Encodable, Persistable, MongoPersistable {
private double x;
private double y;
@@ -202,7 +204,21 @@ public class Point3D implements Encodable, Persistable {
y = stream.getFloat();
z = stream.getFloat();
}
@Override
public void read(MongoData data) {
x = data.getDouble("x", 0);
y = data.getDouble("y", 0);
z = data.getDouble("z", 0);
}
@Override
public void save(MongoData data) {
data.putDouble("x", x);
data.putDouble("y", y);
data.putDouble("z", z);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Point3D))

View File

@@ -26,13 +26,15 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import com.projectswg.common.data.encodables.mongo.MongoData;
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
import com.projectswg.common.persistable.Persistable;
import me.joshlarson.jlcommon.utilities.Arguments;
public class Quaternion implements Encodable, Persistable {
public class Quaternion implements Encodable, Persistable, MongoPersistable {
private final double [][] rotationMatrix;
private double x;
@@ -236,7 +238,23 @@ public class Quaternion implements Encodable, Persistable {
w = stream.getFloat();
updateRotationMatrix();
}
@Override
public void read(MongoData data) {
x = data.getDouble("x", 0);
y = data.getDouble("y", 0);
z = data.getDouble("z", 0);
w = data.getDouble("w", 1);
}
@Override
public void save(MongoData data) {
data.putDouble("x", x);
data.putDouble("y", y);
data.putDouble("z", z);
data.putDouble("w", w);
}
@Override
public String toString() {
return String.format("Quaternion[%.3f, %.3f, %.3f, %.3f]", x, y, z, w);

View File

@@ -2,6 +2,7 @@ module com.projectswg.common {
requires transitive me.joshlarson.jlcommon;
requires static java.sql;
requires static java.desktop;
requires static org.mongodb.bson;
requires org.jetbrains.annotations;
requires org.bouncycastle.provider;
@@ -11,6 +12,7 @@ module com.projectswg.common {
exports com.projectswg.common.data.encodables.chat;
exports com.projectswg.common.data.encodables.galaxy;
exports com.projectswg.common.data.encodables.map;
exports com.projectswg.common.data.encodables.mongo;
exports com.projectswg.common.data.encodables.oob;
exports com.projectswg.common.data.encodables.oob.waypoint;
exports com.projectswg.common.data.encodables.player;