diff --git a/src/java/org/jivesoftware/openfire/archive/Conversation.java b/src/java/org/jivesoftware/openfire/archive/Conversation.java index 3c8f33f04..47e80f53b 100644 --- a/src/java/org/jivesoftware/openfire/archive/Conversation.java +++ b/src/java/org/jivesoftware/openfire/archive/Conversation.java @@ -311,6 +311,19 @@ void conversationEnded(ConversationManager conversationManager, Date nowDate) { } } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Conversation that = (Conversation) o; + return conversationID == that.conversationID && external == that.external && messageCount == that.messageCount && Objects.equals(participants, that.participants) && Objects.equals(startDate, that.startDate) && Objects.equals(lastActivity, that.lastActivity) && Objects.equals(room, that.room); + } + + @Override + public int hashCode() { + return Objects.hash(conversationID, participants, external, startDate, lastActivity, messageCount, room); + } + /** * Convert the conversation to an XML representation. * diff --git a/src/java/org/jivesoftware/openfire/archive/ConversationManager.java b/src/java/org/jivesoftware/openfire/archive/ConversationManager.java index 4f3fc6170..f89d9af85 100644 --- a/src/java/org/jivesoftware/openfire/archive/ConversationManager.java +++ b/src/java/org/jivesoftware/openfire/archive/ConversationManager.java @@ -94,9 +94,6 @@ public class ConversationManager implements ComponentEventListener{ private ConversationEventsQueue conversationEventsQueue; private TaskEngine taskEngine; - private static XmlSerializer xmlSerializer; - - private Map conversations = new ConcurrentHashMap<>(); private boolean metadataArchivingEnabled; /** diff --git a/src/java/org/jivesoftware/openfire/archive/ConversationParticipation.java b/src/java/org/jivesoftware/openfire/archive/ConversationParticipation.java index 80f9d3c2c..f8b4dbad6 100644 --- a/src/java/org/jivesoftware/openfire/archive/ConversationParticipation.java +++ b/src/java/org/jivesoftware/openfire/archive/ConversationParticipation.java @@ -16,15 +16,10 @@ package org.jivesoftware.openfire.archive; -import org.jivesoftware.util.cache.ExternalizableUtil; - import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.Date; +import java.util.Objects; /** * Participation of a user, connected from a specific resource, in a conversation. If @@ -34,11 +29,14 @@ * @author Gaston Dombiak */ @XmlRootElement -public class ConversationParticipation implements Externalizable { +public class ConversationParticipation { + @XmlElement private Date joined = new Date(); + @XmlElement private Date left; + @XmlElement private String nickname; @@ -86,25 +84,16 @@ public String getNickname() { return nickname; } - public void writeExternal(ObjectOutput out) throws IOException { - ExternalizableUtil.getInstance().writeLong(out, joined.getTime()); - ExternalizableUtil.getInstance().writeBoolean(out, nickname != null); - if (nickname != null) { - ExternalizableUtil.getInstance().writeSafeUTF(out, nickname); - } - ExternalizableUtil.getInstance().writeBoolean(out, left != null); - if (left != null) { - ExternalizableUtil.getInstance().writeLong(out, left.getTime()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConversationParticipation that = (ConversationParticipation) o; + return Objects.equals(joined, that.joined) && Objects.equals(left, that.left) && Objects.equals(nickname, that.nickname); } - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - joined = new Date(ExternalizableUtil.getInstance().readLong(in)); - if (ExternalizableUtil.getInstance().readBoolean(in)) { - nickname = ExternalizableUtil.getInstance().readSafeUTF(in); - } - if (ExternalizableUtil.getInstance().readBoolean(in)) { - left = new Date(ExternalizableUtil.getInstance().readLong(in)); - } + @Override + public int hashCode() { + return Objects.hash(joined, left, nickname); } } diff --git a/src/java/org/jivesoftware/openfire/archive/UserParticipations.java b/src/java/org/jivesoftware/openfire/archive/UserParticipations.java index cba0e27f3..72014b1f5 100644 --- a/src/java/org/jivesoftware/openfire/archive/UserParticipations.java +++ b/src/java/org/jivesoftware/openfire/archive/UserParticipations.java @@ -26,23 +26,21 @@ import java.io.ObjectOutput; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; /** - * Created by IntelliJ IDEA. - * User: gato - * Date: Oct 9, 2007 - * Time: 11:59:42 PM - * To change this template use File | Settings | File Templates. + * @author Gastion Dombiak */ @XmlRootElement -public class UserParticipations implements Externalizable { +public class UserParticipations { /** * Flag that indicates if the participations of the user were in a group chat conversation or a one-to-one * chat. */ @XmlElement private boolean roomParticipation; + /** * Participations of the same user in a groupchat or one-to-one chat. In a group chat conversation * a user may leave the conversation and return later so for each time the user joined the room a new @@ -58,10 +56,10 @@ public UserParticipations() { public UserParticipations(boolean roomParticipation) { this.roomParticipation = roomParticipation; if (roomParticipation) { - participations = new ArrayList(); + participations = new ArrayList<>(); } else { - participations = new CopyOnWriteArrayList(); + participations = new CopyOnWriteArrayList<>(); } } @@ -77,35 +75,16 @@ public void addParticipation(ConversationParticipation participation) { participations.add(0, participation); } - public void writeExternal(ObjectOutput out) throws IOException { - // ClassCastExceptions occur when using classes provided by a plugin during serialization (sometimes only after - // reloading the plugin without restarting Openfire. This is why this implementation marshalls data as XML when - // serializing. See https://github.com/igniterealtime/openfire-monitoring-plugin/issues/120 - // and https://github.com/igniterealtime/openfire-monitoring-plugin/issues/156 - ExternalizableUtil.getInstance().writeBoolean(out, roomParticipation); - ExternalizableUtil.getInstance().writeInt(out, participations.size()); - for (ConversationParticipation cp : participations) { - ExternalizableUtil.getInstance().writeSafeUTF(out, XmlSerializer.getInstance().marshall(cp)); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UserParticipations that = (UserParticipations) o; + return roomParticipation == that.roomParticipation && Objects.equals(participations, that.participations); } - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - // ClassCastExceptions occur when using classes provided by a plugin during serialization (sometimes only after - // reloading the plugin without restarting Openfire. This is why this implementation marshalls data as XML when - // serializing. See https://github.com/igniterealtime/openfire-monitoring-plugin/issues/120 - // and https://github.com/igniterealtime/openfire-monitoring-plugin/issues/156 - roomParticipation = ExternalizableUtil.getInstance().readBoolean(in); - if (roomParticipation) { - participations = new ArrayList<>(); - } - else { - participations = new CopyOnWriteArrayList<>(); - } - int participationCount = ExternalizableUtil.getInstance().readInt(in); - for (int i = 0; i < participationCount; i++) { - String marshalledConversationParticipation = ExternalizableUtil.getInstance().readSafeUTF(in); - final ConversationParticipation unmarshalledParticipation = (ConversationParticipation)XmlSerializer.getInstance().unmarshall(marshalledConversationParticipation); - participations.add(unmarshalledParticipation); - } + @Override + public int hashCode() { + return Objects.hash(roomParticipation, participations); } } diff --git a/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java b/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java index 34acedab0..912f01994 100644 --- a/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java +++ b/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java @@ -19,6 +19,8 @@ import org.xmpp.packet.JID; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -30,6 +32,74 @@ */ public class XmlSerializerTest { + /** + * Checks that an instance of {@link Conversation} can be marshalled to XML, and back to an object again, + * verifying that the resulting object is equal to the original input. + */ + @Test + public void testXmlMarshallingConversationTest() throws Exception { + // Setup test fixture. + final Map participations = new HashMap<>(); + final UserParticipations userParticipations = new UserParticipations(true); + userParticipations.addParticipation(new ConversationParticipation(new Date(2), "unittest")); + userParticipations.addParticipation(new ConversationParticipation(new Date(3))); + final ConversationParticipation participation = new ConversationParticipation(new Date(4), "unittest"); + participation.participationEnded(new Date(5)); + userParticipations.addParticipation(participation); + participations.put("g@d", userParticipations); + participations.put("a@s/f", userParticipations); + final Conversation input = new Conversation(new JID("a@b.c"), true, new Date(1), new Date(2), 8, participations); + + // Execute system under test. + final String xml = XmlSerializer.getInstance().marshall(input); + final Object result = XmlSerializer.getInstance().unmarshall(xml); + + // Verify result. + assertTrue(result instanceof Conversation); + assertEquals("Marshalled content didn't unmarshall as equal object. Marshalled content: " + xml, input, result); + } + + /** + * Checks that an instance of {@link UserParticipations} can be marshalled to XML, and back to an object again, + * verifying that the resulting object is equal to the original input. + */ + @Test + public void testXmlMarshallingUserParticipationsTest() throws Exception { + // Setup test fixture. + final UserParticipations input = new UserParticipations(true); + input.addParticipation(new ConversationParticipation(new Date(2), "unittest")); + input.addParticipation(new ConversationParticipation(new Date(3))); + final ConversationParticipation participation = new ConversationParticipation(new Date(4), "unittest"); + participation.participationEnded(new Date(5)); + input.addParticipation(participation); + + // Execute system under test. + final String xml = XmlSerializer.getInstance().marshall(input); + final Object result = XmlSerializer.getInstance().unmarshall(xml); + + // Verify result. + assertTrue(result instanceof UserParticipations); + assertEquals("Marshalled content didn't unmarshall as equal object. Marshalled content: " + xml, input, result); + } + + /** + * Checks that an instance of {@link ConversationParticipation} can be marshalled to XML, and back to an object again, + * verifying that the resulting object is equal to the original input. + */ + @Test + public void testXmlMarshallingConversationParticipationTest() throws Exception { + // Setup test fixture. + final ConversationParticipation input = new ConversationParticipation(new Date(2), "unittest"); + + // Execute system under test. + final String xml = XmlSerializer.getInstance().marshall(input); + final Object result = XmlSerializer.getInstance().unmarshall(xml); + + // Verify result. + assertTrue(result instanceof ConversationParticipation); + assertEquals("Marshalled content didn't unmarshall as equal object. Marshalled content: " + xml, input, result); + } + /** * Checks that an instance of {@link ConversationEvent} can be marshalled to XML, and back to an object again, * verifying that the resulting object is equal to the original input.