Message listener in progress with a refactoring still

This commit is contained in:
Norbi Peti 2016-08-11 13:31:11 +02:00
parent b81f1b2a81
commit 319a2a9aa1
12 changed files with 96 additions and 95 deletions

View file

@ -100,6 +100,12 @@
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.7</version> <version>2.7</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/io.vertx/vertx-core -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>

View file

@ -19,6 +19,8 @@ import io.github.norbipeti.chat.server.data.*;
import io.github.norbipeti.chat.server.db.domain.*; import io.github.norbipeti.chat.server.db.domain.*;
import io.github.norbipeti.chat.server.io.DataType; import io.github.norbipeti.chat.server.io.DataType;
import io.github.norbipeti.chat.server.page.*; import io.github.norbipeti.chat.server.page.*;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServerOptions;
public class Main { public class Main {
public static Gson gson; public static Gson gson;
@ -30,10 +32,10 @@ public class Main {
LogManager.getLogger().log(Level.INFO, "Loading files..."); LogManager.getLogger().log(Level.INFO, "Loading files...");
DataManager.init(); DataManager.init();
final GsonBuilder gsonBuilder = new GsonBuilder(); final GsonBuilder gsonBuilder = new GsonBuilder();
Reflections rf = new Reflections( Reflections rf = new Reflections(new ConfigurationBuilder()
new ConfigurationBuilder().setUrls(ClasspathHelper.forClassLoader(ManagedData.class.getClassLoader())) .setUrls(ClasspathHelper.forClassLoader(ManagedData.class.getClassLoader()))
.addClassLoader(ManagedData.class.getClassLoader()).addScanners(new SubTypesScanner()) .addClassLoader(ManagedData.class.getClassLoader()).addScanners(new SubTypesScanner())
.filterInputsBy((String pkg) -> pkg.contains(ManagedData.class.getPackage().getName()))); .filterInputsBy((String pkg) -> pkg.contains(ManagedData.class.getPackage().getName())));
Set<Class<? extends ManagedData>> datas = rf.getSubTypesOf(ManagedData.class); Set<Class<? extends ManagedData>> datas = rf.getSubTypesOf(ManagedData.class);
for (Class<? extends ManagedData> data : datas) { for (Class<? extends ManagedData> data : datas) {
if (Modifier.isAbstract(data.getModifiers())) if (Modifier.isAbstract(data.getModifiers()))
@ -75,6 +77,13 @@ public class Main {
} }
} }
server.start(); server.start();
LogManager.getLogger().info("Starting websocket server...");
Vertx vertx = Vertx.vertx();
io.vertx.core.http.HttpServer socketserver = vertx.createHttpServer();
socketserver.websocketHandler(websocket -> {
websocket.writeFinalTextFrame("Hello"); // TODO
});
socketserver.listen(8180);
LogManager.getLogger().log(Level.INFO, "Ready... Press Enter to stop."); LogManager.getLogger().log(Level.INFO, "Ready... Press Enter to stop.");
System.in.read(); System.in.read();
LogManager.getLogger().log(Level.INFO, "Stopping..."); LogManager.getLogger().log(Level.INFO, "Stopping...");

View file

@ -12,7 +12,7 @@ import java.util.Map.Entry;
import com.google.common.io.Files; import com.google.common.io.Files;
import io.github.norbipeti.chat.server.Main; import io.github.norbipeti.chat.server.Main;
import io.github.norbipeti.chat.server.db.domain.ManagedData; import io.github.norbipeti.chat.server.db.domain.SavedData;
public final class DataManager { public final class DataManager {
private DataManager() { private DataManager() {
@ -20,7 +20,7 @@ public final class DataManager {
private static final File datafolder = new File("data"); private static final File datafolder = new File("data");
public static <T extends ManagedData> void save(T object) { public static <T extends SavedData> void save(T object) {
try { try {
File file = new File(datafolder, getFileName(object.getClass(), object.getId())); File file = new File(datafolder, getFileName(object.getClass(), object.getId()));
cache.put(file, object); cache.put(file, object);
@ -30,11 +30,11 @@ public final class DataManager {
} }
} }
public static <T extends ManagedData> T load(Class<T> cl, long id) { public static <T extends SavedData> T load(Class<T> cl, long id) {
return loadFromFile(new File(datafolder, getFileName(cl, id)), cl); return loadFromFile(new File(datafolder, getFileName(cl, id)), cl);
} }
public static <T extends ManagedData> LoaderCollection<T> getAll(Class<T> cl) { public static <T extends SavedData> LoaderCollection<T> getAll(Class<T> cl) {
String[] filenames = datafolder.list(new FilenameFilter() { String[] filenames = datafolder.list(new FilenameFilter() {
@Override @Override
@ -59,10 +59,10 @@ public final class DataManager {
// TODO: Handle unloading of used objects (prevent detached objects) // TODO: Handle unloading of used objects (prevent detached objects)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <T extends ManagedData> T loadFromFile(File file, Class<T> cl) { private static <T extends SavedData> T loadFromFile(File file, Class<T> cl) {
try { try {
if (!file.exists()) { if (!file.exists()) {
T obj = ManagedData.create(cl); T obj = SavedData.create(cl);
return obj; return obj;
} }
if (cache.containsKey(file)) if (cache.containsKey(file))
@ -83,18 +83,18 @@ public final class DataManager {
return null; return null;
} }
public static <T extends ManagedData> boolean remove(T obj) { public static <T extends SavedData> boolean remove(T obj) {
if (cache.containsValue(obj)) if (cache.containsValue(obj))
cache.values().remove(obj); cache.values().remove(obj);
return new File(obj.getClass().getSimpleName() + "-" + obj.getId()).delete(); return new File(obj.getClass().getSimpleName() + "-" + obj.getId()).delete();
} }
public static <T extends ManagedData> boolean remove(Class<T> cl, Long id) { public static <T extends SavedData> boolean remove(Class<T> cl, Long id) {
return new File(cl.getName() + "-" + id).delete(); return new File(cl.getName() + "-" + id).delete();
} }
public static void init() { public static void init() {
packagename = ManagedData.class.getPackage().getName(); packagename = SavedData.class.getPackage().getName();
datafolder.mkdir(); datafolder.mkdir();
nextids = loadNextIDs(); nextids = loadNextIDs();
} }
@ -108,32 +108,32 @@ public final class DataManager {
public static void save() { public static void save() {
saveNextIDs(nextids); saveNextIDs(nextids);
for (Entry<File, Object> item : cache.entrySet()) { for (Entry<File, Object> item : cache.entrySet()) {
DataManager.save((ManagedData) item.getValue()); DataManager.save((SavedData) item.getValue());
} }
} }
private static HashMap<Class<? extends ManagedData>, Long> nextids; private static HashMap<Class<? extends SavedData>, Long> nextids;
public static Map<Class<? extends ManagedData>, Long> getNextIDs() { public static Map<Class<? extends SavedData>, Long> getNextIDs() {
return Collections.unmodifiableMap(nextids); return Collections.unmodifiableMap(nextids);
} }
public static void setNextID(Class<? extends ManagedData> cl, Long id) { public static void setNextID(Class<? extends SavedData> cl, Long id) {
nextids.put(cl, id); nextids.put(cl, id);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static HashMap<Class<? extends ManagedData>, Long> loadNextIDs() { private static HashMap<Class<? extends SavedData>, Long> loadNextIDs() {
try { try {
File file = new File("data", "idlist.ini"); File file = new File("data", "idlist.ini");
if (!file.exists()) if (!file.exists())
return new HashMap<>(); return new HashMap<>();
BufferedReader reader = Files.newReader(file, StandardCharsets.UTF_8); BufferedReader reader = Files.newReader(file, StandardCharsets.UTF_8);
String line; String line;
HashMap<Class<? extends ManagedData>, Long> ret = new HashMap<>(); HashMap<Class<? extends SavedData>, Long> ret = new HashMap<>();
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
String[] spl = line.split("\\="); String[] spl = line.split("\\=");
ret.put((Class<? extends ManagedData>) Class.forName(packagename + "." + spl[0]), Long.parseLong(spl[1])); ret.put((Class<? extends SavedData>) Class.forName(packagename + "." + spl[0]), Long.parseLong(spl[1]));
} }
return ret; return ret;
} catch (Exception e) { } catch (Exception e) {
@ -142,11 +142,11 @@ public final class DataManager {
return new HashMap<>(); return new HashMap<>();
} }
private static void saveNextIDs(HashMap<Class<? extends ManagedData>, Long> ids) { private static void saveNextIDs(HashMap<Class<? extends SavedData>, Long> ids) {
try { try {
File file = new File("data", "idlist.ini"); File file = new File("data", "idlist.ini");
String contents = ""; String contents = "";
for (Entry<Class<? extends ManagedData>, Long> item : ids.entrySet()) { for (Entry<Class<? extends SavedData>, Long> item : ids.entrySet()) {
contents += item.getKey().getSimpleName() + "=" + item.getValue() + "\n"; contents += item.getKey().getSimpleName() + "=" + item.getValue() + "\n";
} }
Files.write(contents, file, StandardCharsets.UTF_8); Files.write(contents, file, StandardCharsets.UTF_8);
@ -155,7 +155,7 @@ public final class DataManager {
} }
} }
private static <T extends ManagedData> String getFileName(Class<T> cl, Long id) { private static <T extends SavedData> String getFileName(Class<T> cl, Long id) {
if (id != null) if (id != null)
return cl.getSimpleName() + "-" + id + ".json"; return cl.getSimpleName() + "-" + id + ".json";
else else

View file

@ -6,7 +6,7 @@ import io.github.norbipeti.chat.server.data.LoaderCollection;
@Entity @Entity
@Table(name = "CONVERSATION") @Table(name = "CONVERSATION")
public class Conversation extends ManagedData { public class Conversation extends SavedData {
private static final long serialVersionUID = 5058682475353799722L; private static final long serialVersionUID = 5058682475353799722L;
// @Id // @Id
// @GeneratedValue(strategy = GenerationType.IDENTITY) // @GeneratedValue(strategy = GenerationType.IDENTITY)
@ -46,7 +46,7 @@ public class Conversation extends ManagedData {
} }
@Override @Override
public void setId(long id) { protected void setId(long id) {
this.id = id; this.id = id;
} }

View file

@ -9,14 +9,14 @@ import io.github.norbipeti.chat.server.data.DataManager;
public abstract class ManagedData implements Serializable { public abstract class ManagedData implements Serializable {
public abstract long getId(); public abstract long getId();
public abstract void setId(long id); protected abstract void setId(long id);
protected abstract void init(); protected abstract void init();
protected ManagedData() { protected ManagedData() {
} }
static <T extends ManagedData> T create(Class<T> cl) { public static <T extends ManagedData> T create(Class<T> cl) {
T obj; T obj;
try { try {
Constructor<T> constructor = cl.getDeclaredConstructor(new Class<?>[0]); Constructor<T> constructor = cl.getDeclaredConstructor(new Class<?>[0]);

View file

@ -9,7 +9,7 @@ import io.github.norbipeti.chat.server.data.LoaderRef;
@Entity @Entity
@Table(name = "MESSAGE") @Table(name = "MESSAGE")
public class Message implements Serializable { public class Message extends ManagedData {
private static final int MESSAGE_LIMIT_PER_CHUNK = 50; private static final int MESSAGE_LIMIT_PER_CHUNK = 50;
private static final long serialVersionUID = 6345941601716826570L; private static final long serialVersionUID = 6345941601716826570L;
private static Long nextid = 0L; private static Long nextid = 0L;
@ -58,27 +58,16 @@ public class Message implements Serializable {
return messagechunk; return messagechunk;
} }
public void setMessageChunk(LoaderRef<MessageChunk> messagechunk) { public void setConversation(LoaderRef<Conversation> conversation) {
this.messagechunk = messagechunk; setConv(conversation.get());
} }
public void setMessageChunk(MessageChunk messagechunk) { public void setConversation(Conversation conversation) {
this.messagechunk = new LoaderRef<MessageChunk>(messagechunk); setConv(conversation);
} }
public Long getId() { private void setConv(Conversation parent) {
return id; Message msg = this;
}
public void setId(Long id) {
this.id = id;
}
private Message() {
}
public static Message create(Conversation parent) {
Message msg = new Message();
int size = parent.getMesssageChunks().size(); int size = parent.getMesssageChunks().size();
MessageChunk chunk; MessageChunk chunk;
if (size == 0 || parent.getMesssageChunks().get(size - 1).getMessages().size() >= MESSAGE_LIMIT_PER_CHUNK) { if (size == 0 || parent.getMesssageChunks().get(size - 1).getMessages().size() >= MESSAGE_LIMIT_PER_CHUNK) {
@ -87,7 +76,21 @@ public class Message implements Serializable {
parent.getMesssageChunks().add(chunk); parent.getMesssageChunks().add(chunk);
} else } else
chunk = parent.getMesssageChunks().get(size - 1); chunk = parent.getMesssageChunks().get(size - 1);
msg.setMessageChunk(chunk); msg.messagechunk = new LoaderRef<MessageChunk>(chunk);
return msg; }
public long getId() {
return id;
}
protected void setId(long id) {
this.id = id;
}
private Message() {
}
@Override
protected void init() {
} }
} }

View file

@ -5,7 +5,7 @@ import java.util.List;
import io.github.norbipeti.chat.server.data.LoaderRef; import io.github.norbipeti.chat.server.data.LoaderRef;
public class MessageChunk extends ManagedData { public class MessageChunk extends SavedData {
private static final long serialVersionUID = -1665300779209348467L; private static final long serialVersionUID = -1665300779209348467L;
private Long id; private Long id;
@ -39,10 +39,14 @@ public class MessageChunk extends ManagedData {
} }
@Override @Override
public void setId(long id) { protected void setId(long id) {
this.id = id; this.id = id;
} }
private MessageChunk() { private MessageChunk() {
} }
@Override
public void init() {
}
} }

View file

@ -0,0 +1,6 @@
package io.github.norbipeti.chat.server.db.domain;
@SuppressWarnings("serial")
public abstract class SavedData extends ManagedData {
}

View file

@ -9,7 +9,7 @@ import io.github.norbipeti.chat.server.data.LoaderCollection;
@Entity @Entity
@Table(name = "\"USER\"") @Table(name = "\"USER\"")
public class User extends ManagedData { public class User extends SavedData {
private static final long serialVersionUID = 2862762084164225666L; private static final long serialVersionUID = 2862762084164225666L;
private Long id; private Long id;
private String name; private String name;
@ -105,11 +105,11 @@ public class User extends ManagedData {
} }
@Override @Override
public void setId(long id) { protected void setId(long id) {
this.id = id; this.id = id;
} }
public static User createUser() { @Override
return ManagedData.create(User.class); public void init() {
} }
} }

View file

@ -45,7 +45,7 @@ public class IndexPage extends Page {
if (user.getConversations().size() == 0) { if (user.getConversations().size() == 0) {
LoaderCollection<Conversation> convs = DataManager.getAll(Conversation.class); LoaderCollection<Conversation> convs = DataManager.getAll(Conversation.class);
if (convs.size() == 0) { if (convs.size() == 0) {
Conversation c = Conversation.create(); Conversation c = ManagedData.create(Conversation.class);
convs.add(c); // TODO: Handle no conversation open convs.add(c); // TODO: Handle no conversation open
} }
user.getConversations().add(convs.get(0)); user.getConversations().add(convs.get(0));

View file

@ -7,6 +7,7 @@ import org.apache.logging.log4j.LogManager;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import io.github.norbipeti.chat.server.Main;
import io.github.norbipeti.chat.server.data.DataManager; import io.github.norbipeti.chat.server.data.DataManager;
import io.github.norbipeti.chat.server.data.LoaderCollection; import io.github.norbipeti.chat.server.data.LoaderCollection;
import io.github.norbipeti.chat.server.db.domain.Conversation; import io.github.norbipeti.chat.server.db.domain.Conversation;
@ -18,6 +19,7 @@ import io.github.norbipeti.chat.server.io.IOHelper;
public class ReceiveMessageAjaxPage extends Page { public class ReceiveMessageAjaxPage extends Page {
// http://stackoverflow.com/questions/9242404/javascript-listen-to-server // http://stackoverflow.com/questions/9242404/javascript-listen-to-server
// https://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery
@Override @Override
public String GetName() { public String GetName() {
return "receivemessage"; return "receivemessage";
@ -30,40 +32,16 @@ public class ReceiveMessageAjaxPage extends Page {
IOHelper.SendResponse(403, "<p>Please log in to receive messages</p>", exchange); IOHelper.SendResponse(403, "<p>Please log in to receive messages</p>", exchange);
return; return;
} }
JsonObject obj = new JsonObject(); JsonObject obj = new JsonObject(); // TODO
String message = obj.get("message").getAsString().trim(); /*
int conversation = obj.get("conversation").getAsInt(); * String message = obj.get("message").getAsString().trim(); int conversation = obj.get("conversation").getAsInt(); if (message.trim().length() == 0) { IOHelper.SendResponse(400,
if (message.trim().length() == 0) { * "<h1>400 Bad request</h1><p>The message cannot be empty.</p>", exchange); return; } LoaderCollection<Conversation> convos = user.getConversations(); Conversation conv = null;
IOHelper.SendResponse(400, "<h1>400 Bad request</h1><p>The message cannot be empty.</p>", exchange); * LogManager.getLogger().log(Level.DEBUG, "Len: " + convos.size()); for (Conversation con : convos) { LogManager.getLogger().log(Level.DEBUG, con.getId()); if (con.getId() == conversation) {
return; * conv = con; break; } } if (conv == null) { IOHelper.SendResponse(400, "<h1>400 Conversation not found</h1><p>The conversation with the id " + conversation + " is not found.</p>", exchange);
} * return; } MessageChunk chunk = ManagedData.create(MessageChunk.class); chunk.setConversation(conv); Message msg = new Message(); msg.setSender(user); msg.setMessage(message);
LoaderCollection<Conversation> convos = user.getConversations(); * msg.setTime(new Date()); msg.setMessageChunk(chunk); chunk.getMessages().add(msg); conv.getMesssageChunks().add(chunk); DataManager.save(conv); LogManager.getLogger().log(Level.DEBUG,
Conversation conv = null; * "Added conversation's message count: " + conv.getMesssageChunks().size());
LogManager.getLogger().log(Level.DEBUG, "Len: " + convos.size()); */
for (Conversation con : convos) {
LogManager.getLogger().log(Level.DEBUG, con.getId());
if (con.getId() == conversation) {
conv = con;
break;
}
}
if (conv == null) {
IOHelper.SendResponse(400, "<h1>400 Conversation not found</h1><p>The conversation with the id "
+ conversation + " is not found.</p>", exchange);
return;
}
MessageChunk chunk = ManagedData.create(MessageChunk.class);
chunk.setConversation(conv);
Message msg = new Message();
msg.setSender(user);
msg.setMessage(message);
msg.setTime(new Date());
msg.setMessageChunk(chunk);
chunk.getMessages().add(msg);
conv.getMesssageChunks().add(chunk);
DataManager.save(conv);
LogManager.getLogger().log(Level.DEBUG,
"Added conversation's message count: " + conv.getMesssageChunks().size());
IOHelper.SendResponse(200, "Success", exchange); IOHelper.SendResponse(200, "Success", exchange);
} }

View file

@ -64,16 +64,11 @@ public class SendMessageAjaxPage extends Page {
+ conversation + " is not found.</p>", exchange); + conversation + " is not found.</p>", exchange);
return; return;
} }
MessageChunk chunk = ManagedData.create(MessageChunk.class); // TODO: Automatize Message msg = ManagedData.create(Message.class);
chunk.setConversation(conv); msg.setConversation(conv);
Message msg = new Message();
msg.setSender(user); msg.setSender(user);
LogManager.getLogger().debug(message);
msg.setMessage(message); msg.setMessage(message);
msg.setTime(new Date()); msg.setTime(new Date());
msg.setMessageChunk(chunk); // TODO: Store relations at one side or both
chunk.getMessages().add(msg);
conv.getMesssageChunks().add(chunk);
DataManager.save(conv); DataManager.save(conv);
LogManager.getLogger().log(Level.DEBUG, LogManager.getLogger().log(Level.DEBUG,
"Added conversation's message count: " + conv.getMesssageChunks().size()); "Added conversation's message count: " + conv.getMesssageChunks().size());