Fixed LoaderCollection serialization

This commit is contained in:
Norbi Peti 2016-08-03 12:55:23 +02:00
parent 8068b292cf
commit 3a1f2a65e1
8 changed files with 125 additions and 95 deletions

View file

@ -4,6 +4,7 @@ import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.Level;
@ -12,18 +13,34 @@ import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.sun.net.httpserver.HttpServer;
import io.github.norbipeti.chat.server.data.DataManager;
import io.github.norbipeti.chat.server.data.LoaderCollection;
import io.github.norbipeti.chat.server.data.LoaderCollectionSerializer;
import io.github.norbipeti.chat.server.db.domain.*;
import io.github.norbipeti.chat.server.page.*;
public class Main {
public static Gson gson;
public static void main(String[] args) { // http://stackoverflow.com/questions/9266632/access-restriction-is-not-accessible-due-to-restriction-on-required-library/10642163#10642163
try { // rt.jar Javadoc:
// https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/
// https://docs.oracle.com/javase/8/docs/api/
LogManager.getLogger().log(Level.INFO, "Loading database...");
LogManager.getLogger().log(Level.INFO, "Loading files...");
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(new TypeToken<LoaderCollection<Conversation>>() {
}.getType(), new LoaderCollectionSerializer<Conversation>());
gsonBuilder.registerTypeAdapter(new TypeToken<LoaderCollection<Message>>() {
}.getType(), new LoaderCollectionSerializer<Message>());
gsonBuilder.registerTypeAdapter(new TypeToken<LoaderCollection<User>>() {
}.getType(), new LoaderCollectionSerializer<User>());
gson = gsonBuilder.create();
User user = new User();
user.setName("asd");
user.setEmail("test@test.com");

View file

@ -6,7 +6,7 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.google.common.io.Files;
import com.google.gson.Gson;
import io.github.norbipeti.chat.server.Main;
import io.github.norbipeti.chat.server.db.domain.ChatDatabaseEntity;
public final class DataManager {
@ -14,8 +14,7 @@ public final class DataManager {
}
public static <T extends ChatDatabaseEntity> void save(T object) throws IOException {
Gson gson = new Gson();
Files.write(gson.toJson(object), new File(object.getClass().getName() + "-" + object.getId()),
Files.write(Main.gson.toJson(object), new File(object.getClass().getName() + "-" + object.getId()),
StandardCharsets.UTF_8);
}
@ -47,8 +46,7 @@ public final class DataManager {
String line;
while ((line = reader.readLine()) != null)
objstr += line;
Gson gson = new Gson();
return gson.fromJson(objstr, cl);
return Main.gson.fromJson(objstr, cl);
} catch (Exception e) {
e.printStackTrace();
}

View file

@ -12,9 +12,8 @@ import io.github.norbipeti.chat.server.db.domain.ChatDatabaseEntity;
public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>, Serializable {
private static final long serialVersionUID = 5426152406394894301L;
private List<Long> contacts;
private Class<T> cl;
private transient boolean forsave = false;
List<Long> idlist;
Class<T> cl;
/**
* Only used for serialization
@ -25,92 +24,89 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
public LoaderCollection(Class<T> cl) {
this.cl = cl;
contacts = new ArrayList<>();
idlist = new ArrayList<>();
}
public LoaderCollection(LoaderCollection<T> parentofsub, int fromIndex, int toIndex) {
this.cl = parentofsub.cl;
contacts = parentofsub.contacts.subList(fromIndex, toIndex);
idlist = parentofsub.idlist.subList(fromIndex, toIndex);
}
public LoaderCollection(Class<T> cl, int capacity) {
this.cl = cl;
contacts = new ArrayList<>(capacity);
idlist = new ArrayList<>(capacity);
}
@Override
public Iterator<T> iterator() {
if (forsave)
return contacts.iterator(); // TODO: Fix
else
return new LoaderIterator<T>(contacts.iterator(), cl);
return new LoaderIterator<T>(idlist.iterator(), cl);
}
@Override
public boolean add(T e) {
return contacts.add(e.getId());
return idlist.add(e.getId());
}
@Override
public void add(int index, T element) {
contacts.add(index, element.getId());
idlist.add(index, element.getId());
}
@Override
public boolean addAll(Collection<? extends T> c) {
return contacts
return idlist
.addAll(c.stream().map((data) -> ((ChatDatabaseEntity) data).getId()).collect(Collectors.toList()));
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
return contacts.addAll(index,
return idlist.addAll(index,
c.stream().map((data) -> ((ChatDatabaseEntity) data).getId()).collect(Collectors.toList()));
}
@Override
public void clear() {
contacts.clear();
idlist.clear();
}
@Override
public boolean contains(Object o) {
return contacts.contains(o);
return idlist.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return contacts.containsAll(c);
return idlist.containsAll(c);
}
@Override
public T get(int index) {
return DataManager.load(cl, contacts.get(index));
return DataManager.load(cl, idlist.get(index));
}
@Override
public int indexOf(Object o) {
return contacts.indexOf(o);
return idlist.indexOf(o);
}
@Override
public boolean isEmpty() {
return contacts.isEmpty();
return idlist.isEmpty();
}
@Override
public int lastIndexOf(Object o) {
return contacts.lastIndexOf(o);
return idlist.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return new LoaderListIterator<T>(contacts.listIterator(), cl);
return new LoaderListIterator<T>(idlist.listIterator(), cl);
}
@Override
public ListIterator<T> listIterator(int index) {
return new LoaderListIterator<T>(contacts.listIterator(index), cl);
return new LoaderListIterator<T>(idlist.listIterator(index), cl);
}
/**
@ -122,13 +118,13 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
@Override
public boolean remove(Object o) {
if (ChatDatabaseEntity.class.isAssignableFrom(o.getClass()))
return contacts.remove(((ChatDatabaseEntity) o).getId());
return contacts.remove(o);
return idlist.remove(((ChatDatabaseEntity) o).getId());
return idlist.remove(o);
}
@Override
public T remove(int index) {
return DataManager.load(cl, contacts.remove(index));
return DataManager.load(cl, idlist.remove(index));
}
@Override
@ -136,12 +132,12 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
boolean success = false;
for (Object item : c) {
if (ChatDatabaseEntity.class.isAssignableFrom(item.getClass())) {
if (contacts.remove(((ChatDatabaseEntity) item).getId())) {
if (idlist.remove(((ChatDatabaseEntity) item).getId())) {
success = true;
break;
}
} else {
if (contacts.remove(item)) {
if (idlist.remove(item)) {
success = true;
break;
}
@ -160,17 +156,17 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
list.add((Long) item);
}
}
return contacts.retainAll(list);
return idlist.retainAll(list);
}
@Override
public T set(int index, T element) {
return DataManager.load(cl, contacts.set(index, element.getId()));
return DataManager.load(cl, idlist.set(index, element.getId()));
}
@Override
public int size() {
return contacts.size();
return idlist.size();
}
@Override
@ -181,14 +177,14 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
@Override
public Object[] toArray() {
return contacts.stream().map((data) -> {
return idlist.stream().map((data) -> {
return DataManager.load(cl, data);
}).collect(Collectors.toList()).toArray();
}
@Override
public <U> U[] toArray(U[] a) {
return contacts.stream().map((data) -> {
return idlist.stream().map((data) -> {
return DataManager.load(cl, data);
}).collect(Collectors.toList()).toArray(a);
}
@ -200,7 +196,7 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
public String toString(boolean loaditems) {
StringBuilder sb = new StringBuilder("[");
for (Long item : contacts) {
for (Long item : idlist) {
if (loaditems)
sb.append(DataManager.load(cl, item));
else
@ -209,12 +205,4 @@ public class LoaderCollection<T extends ChatDatabaseEntity> implements List<T>,
sb.append("]");
return sb.toString();
}
public boolean isForsave() {
return forsave;
}
public void setForsave(boolean forsave) {
this.forsave = forsave;
}
}

View file

@ -0,0 +1,52 @@
package io.github.norbipeti.chat.server.data;
import java.io.IOException;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.github.norbipeti.chat.server.db.domain.ChatDatabaseEntity;
//@SuppressWarnings("rawtypes")
public class LoaderCollectionSerializer<T extends ChatDatabaseEntity> extends TypeAdapter<LoaderCollection<T>> {
@Override
public void write(JsonWriter out, LoaderCollection<T> value) throws IOException {
out.beginObject();
out.name("items");
new Gson().toJson(value.idlist, new TypeToken<List<Long>>() {
}.getType(), out);
out.name("class").value(value.cl.getName());
out.endObject();
}
// @SuppressWarnings("unchecked")
@SuppressWarnings("unchecked")
@Override
public LoaderCollection<T> read(JsonReader in) throws IOException {
in.beginObject();
in.nextName();
List<Long> list = new Gson().fromJson(in, new TypeToken<List<Long>>() {
}.getType());
if (!in.nextName().equals("class")) {
new Exception("Error: Next isn't \"class\"").printStackTrace();
return null;
}
Class<T> cl;
try {
cl = (Class<T>) Class.forName(in.nextString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
LoaderCollection<T> col = new LoaderCollection<T>(cl); // TODO
col.idlist.addAll(list);
in.endObject();
return col;
}
}

View file

@ -1,23 +1,20 @@
package io.github.norbipeti.chat.server.db.domain;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
import io.github.norbipeti.chat.server.data.LoaderCollection;
@Entity
@Table(name = "CONVERSATION")
public class Conversation extends ChatDatabaseEntity {
private static final long serialVersionUID = 5058682475353799722L;
//@Id
//@GeneratedValue(strategy = GenerationType.IDENTITY)
//@Column(name = "ID", unique = true, nullable = false)
//private Long id;
// @Id
// @GeneratedValue(strategy = GenerationType.IDENTITY)
// @Column(name = "ID", unique = true, nullable = false)
// private Long id;
@ElementCollection(fetch = FetchType.EAGER)
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "conversation")
private List<Message> messsages;
private LoaderCollection<Message> messsages = new LoaderCollection<>(Message.class);
@ElementCollection(fetch = FetchType.EAGER)
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
// @JoinTable(name = "User_Conversation", joinColumns = @JoinColumn(name =
@ -29,33 +26,23 @@ public class Conversation extends ChatDatabaseEntity {
// "conversation_id", referencedColumnName = "id"), inverseJoinColumns =
// @JoinColumn(name = "user_id", referencedColumnName = "id"))
// @JoinTable(name = "User_Conversation")
private Set<User> users;
private LoaderCollection<User> users = new LoaderCollection<>(User.class);
public List<Message> getMesssages() {
if (messsages == null)
messsages = new ArrayList<>();
public LoaderCollection<Message> getMesssages() {
return messsages;
}
public void setMesssages(List<Message> messsages) {
public void setMesssages(LoaderCollection<Message> messsages) {
this.messsages = messsages;
}
public Set<User> getUsers() {
if (users == null)
users = new HashSet<>();
public LoaderCollection<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
/*public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}*/
/*
* public Long getId() { return id; }
*
* public void setId(Long id) { this.id = id; }
*/
}

View file

@ -1,10 +1,7 @@
package io.github.norbipeti.chat.server.db.domain;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
import io.github.norbipeti.chat.server.data.DataManager;
@ -23,7 +20,7 @@ public class User extends ChatDatabaseEntity {
private String password;
@ElementCollection(fetch = FetchType.EAGER)
@OneToOne(cascade = CascadeType.ALL)
private LoaderCollection<User> contacts;
private LoaderCollection<User> contacts = new LoaderCollection<User>(User.class);
private String salt;
// @Column(columnDefinition = "CHAR(16) FOR BIT DATA")
@Column(columnDefinition = "VARCHAR(64)")
@ -36,7 +33,7 @@ public class User extends ChatDatabaseEntity {
// @JoinColumn(referencedColumnName = "id", unique = false),
// inverseJoinColumns = @JoinColumn(referencedColumnName = "id", unique =
// false))
private Set<Conversation> conversations;
private LoaderCollection<Conversation> conversations = new LoaderCollection<>(Conversation.class);
/**
* Loads all contact data
@ -45,8 +42,6 @@ public class User extends ChatDatabaseEntity {
* @throws IOException
*/
public List<User> getContacts() throws IOException {
if (contacts == null)
contacts = new LoaderCollection<User>(User.class);
return contacts;
}
@ -96,16 +91,10 @@ public class User extends ChatDatabaseEntity {
this.sessionid = sessionid;
}
public Set<Conversation> getConversations() {
if (conversations == null)
conversations = new HashSet<>();
public LoaderCollection<Conversation> getConversations() {
return conversations;
}
public void setConversations(Set<Conversation> conversations) {
this.conversations = conversations;
}
public User() {
}

View file

@ -37,7 +37,7 @@ public class IndexPage extends Page {
Element channelmessages = doc.getElementById("channelmessages");
LogManager.getLogger().log(Level.INFO, "Conversations: " + DataManager.load(Conversation.class).size());
LogManager.getLogger().log(Level.INFO, "User conversations: " + user.getConversations().size());
Conversation convo = user.getConversations().iterator().next();
Conversation convo = user.getConversations().get(0);
LogManager.getLogger().log(Level.INFO, "Messages: " + convo.getMesssages().size());
for (Message message : convo.getMesssages()) {
Element msgelement = channelmessages.appendElement("div");

View file

@ -2,8 +2,6 @@ package io.github.norbipeti.chat.server.page;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import com.google.gson.JsonObject;
@ -11,6 +9,7 @@ import com.sun.net.httpserver.HttpExchange;
import io.github.norbipeti.chat.server.IOHelper;
import io.github.norbipeti.chat.server.data.DataManager;
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.Message;
import io.github.norbipeti.chat.server.db.domain.User;
@ -49,7 +48,7 @@ public class MessageAjaxPage extends Page {
IOHelper.SendResponse(400, "<h1>400 Bad request</h1><p>The message cannot be empty,</p>", exchange);
return;
}
Set<Conversation> convos = user.getConversations();
LoaderCollection<Conversation> convos = user.getConversations();
Conversation conv = null;
LogManager.getLogger().log(Level.DEBUG, "Len: " + convos.size());
for (Conversation con : convos) {