type)
{
+ if (serializedData == null) return null;
+
return _gson.fromJson(serializedData, type);
}
diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java
new file mode 100644
index 000000000..5a6238618
--- /dev/null
+++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/serialization/RuntimeTypeAdapterFactory.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package mineplex.serverdata.serialization;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.internal.Streams;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+
+/**
+ * Adapts values whose runtime type may differ from their declaration type. This
+ * is necessary when a field's type is not the same type that GSON should create
+ * when deserializing that field. For example, consider these types:
+ * {@code
+ * abstract class Shape {
+ * int x;
+ * int y;
+ * }
+ * class Circle extends Shape {
+ * int radius;
+ * }
+ * class Rectangle extends Shape {
+ * int width;
+ * int height;
+ * }
+ * class Diamond extends Shape {
+ * int width;
+ * int height;
+ * }
+ * class Drawing {
+ * Shape bottomShape;
+ * Shape topShape;
+ * }
+ * }
+ * Without additional type information, the serialized JSON is ambiguous. Is
+ * the bottom shape in this drawing a rectangle or a diamond?
{@code
+ * {
+ * "bottomShape": {
+ * "width": 10,
+ * "height": 5,
+ * "x": 0,
+ * "y": 0
+ * },
+ * "topShape": {
+ * "radius": 2,
+ * "x": 4,
+ * "y": 1
+ * }
+ * }}
+ * This class addresses this problem by adding type information to the
+ * serialized JSON and honoring that type information when the JSON is
+ * deserialized: {@code
+ * {
+ * "bottomShape": {
+ * "type": "Diamond",
+ * "width": 10,
+ * "height": 5,
+ * "x": 0,
+ * "y": 0
+ * },
+ * "topShape": {
+ * "type": "Circle",
+ * "radius": 2,
+ * "x": 4,
+ * "y": 1
+ * }
+ * }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code
+ * "Rectangle"}) are configurable.
+ *
+ * Registering Types
+ * Create a {@code RuntimeTypeAdapter} by passing the base type and type field
+ * name to the {@link #of} factory method. If you don't supply an explicit type
+ * field name, {@code "type"} will be used. {@code
+ * RuntimeTypeAdapter shapeAdapter
+ * = RuntimeTypeAdapter.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly
+ * registered. This protects your application from injection attacks. If you
+ * don't supply an explicit type label, the type's simple name will be used.
+ * {@code
+ * shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
+ * shapeAdapter.registerSubtype(Circle.class, "Circle");
+ * shapeAdapter.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter in your application's GSON builder:
+ * {@code
+ * Gson gson = new GsonBuilder()
+ * .registerTypeAdapter(Shape.class, shapeAdapter)
+ * .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining: {@code
+ * RuntimeTypeAdapter shapeAdapter = RuntimeTypeAdapterFactory.of(Shape.class)
+ * .registerSubtype(Rectangle.class)
+ * .registerSubtype(Circle.class)
+ * .registerSubtype(Diamond.class);
+ * }
+ */
+public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory {
+ private final Class> baseType;
+ private final String typeFieldName;
+ private final Map> labelToSubtype = new LinkedHashMap>();
+ private final Map, String> subtypeToLabel = new LinkedHashMap, String>();
+
+ private RuntimeTypeAdapterFactory(Class> baseType, String typeFieldName) {
+ if (typeFieldName == null || baseType == null) {
+ throw new NullPointerException();
+ }
+ this.baseType = baseType;
+ this.typeFieldName = typeFieldName;
+ }
+
+ /**
+ * Creates a new runtime type adapter using for {@code baseType} using {@code
+ * typeFieldName} as the type field name. Type field names are case sensitive.
+ */
+ public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) {
+ return new RuntimeTypeAdapterFactory(baseType, typeFieldName);
+ }
+
+ /**
+ * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as
+ * the type field name.
+ */
+ public static RuntimeTypeAdapterFactory of(Class baseType) {
+ return new RuntimeTypeAdapterFactory(baseType, "type");
+ }
+
+ /**
+ * Registers {@code type} identified by {@code label}. Labels are case
+ * sensitive.
+ *
+ * @throws IllegalArgumentException if either {@code type} or {@code label}
+ * have already been registered on this type adapter.
+ */
+ public RuntimeTypeAdapterFactory registerSubtype(Class extends T> type, String label) {
+ if (type == null || label == null) {
+ throw new NullPointerException();
+ }
+ if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {
+ throw new IllegalArgumentException("types and labels must be unique");
+ }
+ labelToSubtype.put(label, type);
+ subtypeToLabel.put(type, label);
+ return this;
+ }
+
+ /**
+ * Registers {@code type} identified by its {@link Class#getSimpleName simple
+ * name}. Labels are case sensitive.
+ *
+ * @throws IllegalArgumentException if either {@code type} or its simple name
+ * have already been registered on this type adapter.
+ */
+ public RuntimeTypeAdapterFactory registerSubtype(Class extends T> type) {
+ return registerSubtype(type, type.getSimpleName());
+ }
+
+ public TypeAdapter create(Gson gson, TypeToken type) {
+ if (type.getRawType() != baseType) {
+ return null;
+ }
+
+ final Map> labelToDelegate
+ = new LinkedHashMap>();
+ final Map, TypeAdapter>> subtypeToDelegate
+ = new LinkedHashMap, TypeAdapter>>();
+ for (Map.Entry> entry : labelToSubtype.entrySet()) {
+ TypeAdapter> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
+ labelToDelegate.put(entry.getKey(), delegate);
+ subtypeToDelegate.put(entry.getValue(), delegate);
+ }
+
+ return new TypeAdapter() {
+ @Override public R read(JsonReader in) throws IOException {
+ JsonElement jsonElement = Streams.parse(in);
+ JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
+ if (labelJsonElement == null) {
+ throw new JsonParseException("cannot deserialize " + baseType
+ + " because it does not define a field named " + typeFieldName);
+ }
+ String label = labelJsonElement.getAsString();
+ @SuppressWarnings("unchecked") // registration requires that subtype extends T
+ TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label);
+ if (delegate == null) {
+ throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
+ + label + "; did you forget to register a subtype?");
+ }
+ return delegate.fromJsonTree(jsonElement);
+ }
+
+ @Override public void write(JsonWriter out, R value) throws IOException {
+ if(value!=null) {
+ Class> srcType = value.getClass();
+ String label = subtypeToLabel.get(srcType);
+ @SuppressWarnings("unchecked") // registration requires that subtype extends T
+ TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType);
+ if (delegate == null) {
+ throw new JsonParseException("cannot serialize " + srcType.getName()
+ + "; did you forget to register a subtype?");
+ }
+ JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
+ if (jsonObject.has(typeFieldName)) {
+ throw new JsonParseException("cannot serialize " + srcType.getName()
+ + " because it already defines a field named " + typeFieldName);
+ }
+ JsonObject clone = new JsonObject();
+ clone.add(typeFieldName, new JsonPrimitive(label));
+ for (Map.Entry e : jsonObject.entrySet()) {
+ clone.add(e.getKey(), e.getValue());
+ }
+ Streams.write(clone, out);
+ }else{
+ out.nullValue();
+ }
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java
index 889dd4ef4..d54b23935 100644
--- a/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java
+++ b/Plugins/Mineplex.ServerMonitor/src/mineplex/servermonitor/ServerMonitor.java
@@ -29,13 +29,15 @@ import mineplex.serverdata.data.ServerGroup;
import mineplex.serverdata.servers.DedicatedServerSorter;
import mineplex.serverdata.servers.ServerManager;
import mineplex.serverdata.servers.ServerRepository;
+import mineplex.serverprocesses.GenericRunnable;
+import mineplex.serverprocesses.ProcessManager;
+import mineplex.serverprocesses.ProcessRunner;
public class ServerMonitor
{
private static ServerRepository _repository = null;
private static StatusHistoryRepository _historyRepository = null;
private static int _count = 0;
- private static HashSet _processes = new HashSet();
private static HashMap _badServers = new HashMap();
private static Collection _serverStatuses = null;
private static Collection _serverGroups = null;
@@ -54,18 +56,6 @@ public class ServerMonitor
public static void main (String args[])
{
- /*
- MinecraftPingReply data = null;
- try
- {
- data = new MinecraftPing().getPing(new MinecraftPingOptions().setHostname("127.0.0.1").setPort(25565));
- }
- catch (IOException e2)
- {
- e2.printStackTrace();
- }
- System.out.println(data.getDescription() + " " + data.getPlayers().getOnline());
- */
_region = !new File("eu.dat").exists() ? Region.US : Region.EU;
_debug = new File("debug.dat").exists();
_repository = ServerManager.getServerRepository(_region); // Fetches and connects to server repo
@@ -286,55 +276,7 @@ public class ServerMonitor
}
}
- int processWaits = 0;
-
- while (_processes.size() > 0)
- {
- for (Iterator iterator = _processes.iterator(); iterator.hasNext();)
- {
- ProcessRunner pr = iterator.next();
-
- try
- {
- pr.join(100);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
-
- if (pr.isDone())
- iterator.remove();
- }
-
- if (_processes.size() > 0)
- {
- try
- {
- log("Sleeping while processes run...");
- Thread.sleep(6000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- }
-
- if (processWaits >= 10)
- {
- log("Killing stale processes.");
-
- for (Iterator iterator = _processes.iterator(); iterator.hasNext();)
- {
- iterator.next().abort();
- iterator.remove();
- }
- }
-
- processWaits++;
- }
-
- processWaits = 0;
+ ProcessManager.getInstance().updateProcesses();
try
{
@@ -571,7 +513,9 @@ public class ServerMonitor
if (!pr.isDone())
- _processes.add(pr);
+ {
+ ProcessManager.getInstance().addProcess(pr);
+ }
}
private static boolean isServerOffline(DedicatedServer serverData)
@@ -672,7 +616,9 @@ public class ServerMonitor
serverSpace.incrementServerCount(serverGroup);
if (!pr.isDone())
- _processes.add(pr);
+ {
+ ProcessManager.getInstance().addProcess(pr);
+ }
}
private static void log(String message)
diff --git a/Plugins/Mineplex.ServerProcesses/.project b/Plugins/Mineplex.ServerProcesses/.project
new file mode 100644
index 000000000..66b31cde0
--- /dev/null
+++ b/Plugins/Mineplex.ServerProcesses/.project
@@ -0,0 +1,17 @@
+
+
+