From bf5a6e09f8bc15c84473f8b5a198067a75beb34d Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Wed, 22 Dec 2021 12:05:08 +0100 Subject: [PATCH] For #120 / #170: Make XmlSerializer plugin-specific The XmlSerializer was intended to be generic, but is used in only one invocation. To make it easier to test the implementation, this commit turns the generic implementation into something that is specific to this plugin. --- .../openfire/archive/Conversation.java | 10 ++-- .../openfire/archive/ConversationManager.java | 16 ------ .../openfire/archive/UserParticipations.java | 4 +- .../openfire/archive/XmlSerializer.java | 32 +++++++----- .../cluster/SendConversationEventsTask.java | 5 +- .../archive/ConversationManagerTest.java | 32 ------------ .../openfire/archive/XmlSerializerTest.java | 50 +++++++++++++++++++ 7 files changed, 80 insertions(+), 69 deletions(-) delete mode 100644 src/test/java/org/jivesoftware/openfire/archive/ConversationManagerTest.java create mode 100644 src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java diff --git a/src/java/org/jivesoftware/openfire/archive/Conversation.java b/src/java/org/jivesoftware/openfire/archive/Conversation.java index 5af78d73c..18dabe71e 100644 --- a/src/java/org/jivesoftware/openfire/archive/Conversation.java +++ b/src/java/org/jivesoftware/openfire/archive/Conversation.java @@ -593,7 +593,7 @@ private void loadFromDb() throws NotFoundException { } /** - * Notification message inficating that conversation has finished so remaining participants should be marked that they left the conversation. + * Notification message implicating that conversation has finished so remaining participants should be marked that they left the conversation. * * @param nowDate * the date when the conversation was finished @@ -616,7 +616,7 @@ void conversationEnded(Date nowDate) { * @throws IOException On any issue that occurs when marshalling this instance to XML. */ public String toXml() throws IOException { - return ConversationManager.getXmlSerializer().marshall(this); + return XmlSerializer.getInstance().marshall(this); } /** @@ -627,7 +627,7 @@ public String toXml() throws IOException { * @throws IOException On any issue that occurs when unmarshalling XML to an instance of Conversation. */ public static Conversation fromXml(final String xmlString) throws IOException { - final Conversation unmarshalled = (Conversation) ConversationManager.getXmlSerializer().unmarshall(xmlString); + final Conversation unmarshalled = (Conversation) XmlSerializer.getInstance().unmarshall(xmlString); final Optional plugin = XMPPServer.getInstance().getPluginManager().getPluginByName(MonitoringConstants.PLUGIN_NAME); if (!plugin.isPresent()) { // Highly unlikely, as this code is _part_ of the Monitoring plugin. If this occurs something is very wrong. @@ -649,7 +649,7 @@ public void writeExternal(ObjectOutput out) throws IOException { ExternalizableUtil.getInstance().writeInt(out, participants.size()); for (Map.Entry e : participants.entrySet()) { ExternalizableUtil.getInstance().writeSafeUTF(out, e.getKey()); - ExternalizableUtil.getInstance().writeSafeUTF(out, ConversationManager.getXmlSerializer().marshall(e.getValue())); + ExternalizableUtil.getInstance().writeSafeUTF(out, XmlSerializer.getInstance().marshall(e.getValue())); } ExternalizableUtil.getInstance().writeBoolean(out, external); ExternalizableUtil.getInstance().writeLong(out, startDate.getTime()); @@ -680,7 +680,7 @@ public void readExternal(ObjectInput in) throws IOException { for (int i = 0; i < participantsCount; i++) { String participantName = ExternalizableUtil.getInstance().readSafeUTF(in); String marshalledParticipations = ExternalizableUtil.getInstance().readSafeUTF(in); - final UserParticipations unmarshalledParticipations = (UserParticipations)ConversationManager.getXmlSerializer().unmarshall(marshalledParticipations); + final UserParticipations unmarshalledParticipations = (UserParticipations)XmlSerializer.getInstance().unmarshall(marshalledParticipations); participants.put(participantName, unmarshalledParticipations); } diff --git a/src/java/org/jivesoftware/openfire/archive/ConversationManager.java b/src/java/org/jivesoftware/openfire/archive/ConversationManager.java index 87043dc70..92047b849 100644 --- a/src/java/org/jivesoftware/openfire/archive/ConversationManager.java +++ b/src/java/org/jivesoftware/openfire/archive/ConversationManager.java @@ -1164,22 +1164,6 @@ public Duration availabilityETAOnLocalNode( Instant instant ) .orElse( Duration.ZERO ); } - /** - * Returns an XML serializer that can be used to marshall and unmarshall conversation objects. - * @return The XML serializer. - */ - public static synchronized XmlSerializer getXmlSerializer() { - if (ConversationManager.xmlSerializer == null) { - ConversationManager.xmlSerializer = new XmlSerializer( - Conversation.class, - UserParticipations.class, - ConversationParticipation.class, - ConversationEvent.class - ); - } - return ConversationManager.xmlSerializer; - } - /** * Stores Conversations in the database. */ diff --git a/src/java/org/jivesoftware/openfire/archive/UserParticipations.java b/src/java/org/jivesoftware/openfire/archive/UserParticipations.java index c2d0a225a..cba0e27f3 100644 --- a/src/java/org/jivesoftware/openfire/archive/UserParticipations.java +++ b/src/java/org/jivesoftware/openfire/archive/UserParticipations.java @@ -85,7 +85,7 @@ public void writeExternal(ObjectOutput out) throws IOException { ExternalizableUtil.getInstance().writeBoolean(out, roomParticipation); ExternalizableUtil.getInstance().writeInt(out, participations.size()); for (ConversationParticipation cp : participations) { - ExternalizableUtil.getInstance().writeSafeUTF(out, ConversationManager.getXmlSerializer().marshall(cp)); + ExternalizableUtil.getInstance().writeSafeUTF(out, XmlSerializer.getInstance().marshall(cp)); } } @@ -104,7 +104,7 @@ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundExcept int participationCount = ExternalizableUtil.getInstance().readInt(in); for (int i = 0; i < participationCount; i++) { String marshalledConversationParticipation = ExternalizableUtil.getInstance().readSafeUTF(in); - final ConversationParticipation unmarshalledParticipation = (ConversationParticipation)ConversationManager.getXmlSerializer().unmarshall(marshalledConversationParticipation); + final ConversationParticipation unmarshalledParticipation = (ConversationParticipation)XmlSerializer.getInstance().unmarshall(marshalledConversationParticipation); participations.add(unmarshalledParticipation); } } diff --git a/src/java/org/jivesoftware/openfire/archive/XmlSerializer.java b/src/java/org/jivesoftware/openfire/archive/XmlSerializer.java index 611958f66..a61ad99f2 100644 --- a/src/java/org/jivesoftware/openfire/archive/XmlSerializer.java +++ b/src/java/org/jivesoftware/openfire/archive/XmlSerializer.java @@ -39,33 +39,41 @@ import java.util.stream.Stream; /** - * The XmlSerializer assists in converting objects from and to XML representation. Classes of all involved objects need - * to be bound upon instantiation. A number of generally used collection classes is bound by default. + * The XmlSerializer assists in converting selected Monitoring plugin objects from and to XML representation. */ public class XmlSerializer { private static final Logger Log = LoggerFactory.getLogger(XmlSerializer.class); - private static final Class[] defaultClassesToBind = { + private static final Class[] classesToBind = { ArrayList.class, HashMap.class, HashSet.class, - ConcurrentHashMap.class + ConcurrentHashMap.class, + Conversation.class, + UserParticipations.class, + ConversationParticipation.class, + ConversationEvent.class }; - private final Marshaller marshaller; - private final Unmarshaller unmarshaller; + private static XmlSerializer instance; + public static synchronized XmlSerializer getInstance() { + if (instance == null) { + instance = new XmlSerializer(); + } - public XmlSerializer(Class... classesToBind) { - final Class[] allClassesToBind = Stream.concat(Arrays.stream(defaultClassesToBind), Arrays.stream(classesToBind)) - .toArray(size -> (Class[]) Array.newInstance(Class.class, size)); + return instance; + } - Log.trace("Binding classes: {}", Arrays.stream(allClassesToBind).map(Class::toString).collect(Collectors.joining(", "))); + private final Marshaller marshaller; + private final Unmarshaller unmarshaller; + private XmlSerializer() { + Log.trace("Binding classes: {}", Arrays.stream(classesToBind).map(Class::toString).collect(Collectors.joining(", "))); try { - JAXBContext jaxbContext = JAXBContext.newInstance(allClassesToBind); + JAXBContext jaxbContext = JAXBContext.newInstance(classesToBind); this.marshaller = jaxbContext.createMarshaller(); this.unmarshaller = jaxbContext.createUnmarshaller(); } catch (JAXBException e) { - throw new IllegalArgumentException("Unable to create xml serializer using classes " + Arrays.stream(allClassesToBind).map(Class::toString).collect(Collectors.joining(", ")), e); + throw new IllegalArgumentException("Unable to create xml serializer using classes " + Arrays.stream(classesToBind).map(Class::toString).collect(Collectors.joining(", ")), e); } } diff --git a/src/java/org/jivesoftware/openfire/archive/cluster/SendConversationEventsTask.java b/src/java/org/jivesoftware/openfire/archive/cluster/SendConversationEventsTask.java index 21f030cf9..c5b1de3f5 100644 --- a/src/java/org/jivesoftware/openfire/archive/cluster/SendConversationEventsTask.java +++ b/src/java/org/jivesoftware/openfire/archive/cluster/SendConversationEventsTask.java @@ -20,6 +20,7 @@ import org.jivesoftware.openfire.archive.ConversationEvent; import org.jivesoftware.openfire.archive.ConversationManager; import org.jivesoftware.openfire.archive.MonitoringConstants; +import org.jivesoftware.openfire.archive.XmlSerializer; import org.jivesoftware.openfire.container.Plugin; import org.jivesoftware.openfire.plugin.MonitoringPlugin; import org.jivesoftware.util.cache.ClusterTask; @@ -84,7 +85,7 @@ public void writeExternal(ObjectOutput out) throws IOException { // and https://github.com/igniterealtime/openfire-monitoring-plugin/issues/156 ExternalizableUtil.getInstance().writeInt(out, events.size()); for (ConversationEvent event : events) { - ExternalizableUtil.getInstance().writeSafeUTF(out, ConversationManager.getXmlSerializer().marshall(event)); + ExternalizableUtil.getInstance().writeSafeUTF(out, XmlSerializer.getInstance().marshall(event)); } } @@ -97,7 +98,7 @@ public void readExternal(ObjectInput in) throws IOException { int eventCount = ExternalizableUtil.getInstance().readInt(in); for (int i = 0; i < eventCount; i++) { String marshalledConversationEvent = ExternalizableUtil.getInstance().readSafeUTF(in); - final ConversationEvent unmarshalledEvent = (ConversationEvent)ConversationManager.getXmlSerializer().unmarshall(marshalledConversationEvent); + final ConversationEvent unmarshalledEvent = (ConversationEvent)XmlSerializer.getInstance().unmarshall(marshalledConversationEvent); events.add(unmarshalledEvent); } } diff --git a/src/test/java/org/jivesoftware/openfire/archive/ConversationManagerTest.java b/src/test/java/org/jivesoftware/openfire/archive/ConversationManagerTest.java deleted file mode 100644 index d9199d093..000000000 --- a/src/test/java/org/jivesoftware/openfire/archive/ConversationManagerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.jivesoftware.openfire.archive; - -import org.junit.Test; -import org.xmpp.packet.JID; - -import java.util.Date; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ConversationManagerTest { - - @Test - public void testXmlMarshallingConversationEventTest() throws Exception { - // Setup test fixture. - final ConversationEvent input = ConversationEvent.chatMessageReceived(new JID("a@b.c"), new JID("d@e.f/g"), "body", "stanza", new Date(1)); - final XmlSerializer serializer = new XmlSerializer( - Conversation.class, - UserParticipations.class, - ConversationParticipation.class, - ConversationEvent.class - ); - - // Execute system under test. - final String xml = serializer.marshall(input); - final Object result = serializer.unmarshall(xml); - - // Verify result. - assertTrue(result instanceof ConversationEvent); - assertEquals("Marshalled content didn't unmarshall as equal object. Marshalled content: " + xml, input, result); - } -} diff --git a/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java b/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java new file mode 100644 index 000000000..34acedab0 --- /dev/null +++ b/src/test/java/org/jivesoftware/openfire/archive/XmlSerializerTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Ignite Realtime Foundation. All rights reserved. + * + * 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 org.jivesoftware.openfire.archive; + +import org.junit.Test; +import org.xmpp.packet.JID; + +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Verifies the implementation of {@link XmlSerializer} + * + * @author Guus der Kinderen, guus.der.kinderen@gmail.com + */ +public class XmlSerializerTest { + + /** + * 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. + */ + @Test + public void testXmlMarshallingConversationEventTest() throws Exception { + // Setup test fixture. + final ConversationEvent input = ConversationEvent.chatMessageReceived(new JID("a@b.c"), new JID("d@e.f/g"), "body", "stanza", new Date(1)); + + // Execute system under test. + final String xml = XmlSerializer.getInstance().marshall(input); + final Object result = XmlSerializer.getInstance().unmarshall(xml); + + // Verify result. + assertTrue(result instanceof ConversationEvent); + assertEquals("Marshalled content didn't unmarshall as equal object. Marshalled content: " + xml, input, result); + } +}