Skip to content

Commit

Permalink
For #120 / #170: Make XmlSerializer plugin-specific
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
guusdk committed Dec 23, 2021
1 parent 269dc89 commit bf5a6e0
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 69 deletions.
10 changes: 5 additions & 5 deletions src/java/org/jivesoftware/openfire/archive/Conversation.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

/**
Expand All @@ -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> 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.
Expand All @@ -649,7 +649,7 @@ public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeInt(out, participants.size());
for (Map.Entry<String, UserParticipations> 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());
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand All @@ -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);
}
}
Expand Down
32 changes: 20 additions & 12 deletions src/java/org/jivesoftware/openfire/archive/XmlSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}

Expand All @@ -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);
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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, [email protected]
*/
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("[email protected]"), new JID("[email protected]/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);
}
}

0 comments on commit bf5a6e0

Please sign in to comment.