Commit c015b7ff authored by Florian Schmaus's avatar Florian Schmaus Committed by flow

Moved all date parsing and formating to util.XMPPDateTimeFormat and made it more robust.

Fixes OF-600: XEP-0082 defines the fraction of seconds to be optional in a date format. Fallback to this if the first parser could not parse the date format.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13437 b35dd754-fafc-0310-a699-88a17e54d16e
parent d6dd94fe
......@@ -29,7 +29,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
......@@ -45,10 +44,10 @@ import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.event.UserEventListener;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger;
......@@ -88,8 +87,7 @@ public class OfflineMessageStore extends BasicModule implements UserEventListene
private static final int POOL_SIZE = 10;
private Cache<String, Integer> sizeCache;
private FastDateFormat dateFormat;
private FastDateFormat dateFormatOld;
/**
* Pattern to use for detecting invalid XML characters. Invalid XML characters will
* be removed from the stored offline messages.
......@@ -115,10 +113,6 @@ public class OfflineMessageStore extends BasicModule implements UserEventListene
*/
public OfflineMessageStore() {
super("Offline Message Store");
dateFormat = FastDateFormat.getInstance(JiveConstants.XMPP_DATETIME_FORMAT,
TimeZone.getTimeZone("UTC"));
dateFormatOld = FastDateFormat.getInstance(JiveConstants.XMPP_DELAY_DATETIME_FORMAT,
TimeZone.getTimeZone("UTC"));
sizeCache = CacheFactory.createCache("Offline Message Size");
}
......@@ -227,11 +221,11 @@ public class OfflineMessageStore extends BasicModule implements UserEventListene
// Add a delayed delivery (XEP-0203) element to the message.
Element delay = message.addChildElement("delay", "urn:xmpp:delay");
delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getXMPPDomain());
delay.addAttribute("stamp", dateFormat.format(creationDate));
delay.addAttribute("stamp", XMPPDateTimeFormat.format(creationDate));
// Add a legacy delayed delivery (XEP-0091) element to the message. XEP is obsolete and support should be dropped in future.
delay = message.addChildElement("x", "jabber:x:delay");
delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getXMPPDomain());
delay.addAttribute("stamp", dateFormatOld.format(creationDate));
delay.addAttribute("stamp", XMPPDateTimeFormat.formatOld(creationDate));
messages.add(message);
}
// Check if the offline messages loaded should be deleted, and that there are
......@@ -294,11 +288,11 @@ public class OfflineMessageStore extends BasicModule implements UserEventListene
// Add a delayed delivery (XEP-0203) element to the message.
Element delay = message.addChildElement("delay", "urn:xmpp:delay");
delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getXMPPDomain());
delay.addAttribute("stamp", dateFormat.format(creationDate));
delay.addAttribute("stamp", XMPPDateTimeFormat.format(creationDate));
// Add a legacy delayed delivery (XEP-0091) element to the message. XEP is obsolete and support should be dropped in future.
delay = message.addChildElement("x", "jabber:x:delay");
delay.addAttribute("from", XMPPServer.getInstance().getServerInfo().getXMPPDomain());
delay.addAttribute("stamp", dateFormatOld.format(creationDate));
delay.addAttribute("stamp", XMPPDateTimeFormat.formatOld(creationDate));
}
}
catch (Exception e) {
......
......@@ -27,9 +27,8 @@ import org.jivesoftware.openfire.commands.AdHocCommand;
import org.jivesoftware.openfire.commands.SessionData;
import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.xmpp.forms.DataForm;
import org.xmpp.forms.FormField;
import org.xmpp.packet.JID;
......@@ -46,7 +45,6 @@ import java.util.*;
* @author Gaston Dombiak
*/
public class GetServerStats extends AdHocCommand {
final private FastDateFormat dateFormat = FastDateFormat.getInstance(JiveConstants.XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
@Override
protected void addStageInformation(SessionData data, Element command) {
......@@ -92,7 +90,7 @@ public class GetServerStats extends AdHocCommand {
field = form.addField();
field.setLabel(LocaleUtils.getLocalizedString("index.uptime"));
field.setVariable("uptime");
field.addValue(dateFormat.format(XMPPServer.getInstance().getServerInfo().getLastStarted()));
field.addValue(XMPPDateTimeFormat.format(XMPPServer.getInstance().getServerInfo().getLastStarted()));
DecimalFormat mbFormat = new DecimalFormat("#0.00");
DecimalFormat percentFormat = new DecimalFormat("#0.0");
......
......@@ -21,13 +21,11 @@
package org.jivesoftware.openfire.handler;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
......@@ -45,7 +43,7 @@ import org.jivesoftware.openfire.disco.IQDiscoItemsHandler;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
import org.jivesoftware.openfire.session.LocalClientSession;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.forms.DataForm;
......@@ -67,8 +65,7 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
private static final String NAMESPACE = "http://jabber.org/protocol/offline";
final private SimpleDateFormat dateFormat =
new SimpleDateFormat(JiveConstants.XMPP_DATETIME_FORMAT);
final private XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();
private IQHandlerInfo info;
private IQDiscoInfoHandler infoHandler;
private IQDiscoItemsHandler itemsHandler;
......@@ -80,7 +77,6 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
public IQOfflineMessagesHandler() {
super("Flexible Offline Message Retrieval Handler");
info = new IQHandlerInfo("offline", NAMESPACE);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@Override
......@@ -105,13 +101,10 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
for (Iterator it = offlineRequest.elementIterator("item"); it.hasNext();) {
Element item = (Element) it.next();
Date creationDate = null;
synchronized (dateFormat) {
try {
creationDate = dateFormat.parse(item.attributeValue("node"));
}
catch (ParseException e) {
Log.error("Error parsing date", e);
}
try {
creationDate = xmppDateTime.parseString(item.attributeValue("node"));
} catch (ParseException e) {
Log.error("Error parsing date", e);
}
if ("view".equals(item.attributeValue("action"))) {
// User requested to receive specific message
......@@ -131,10 +124,8 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
private void sendOfflineMessage(JID receipient, OfflineMessage offlineMessage) {
Element offlineInfo = offlineMessage.addChildElement("offline", NAMESPACE);
synchronized (dateFormat) {
offlineInfo.addElement("item").addAttribute("node",
dateFormat.format(offlineMessage.getCreationDate()));
}
offlineInfo.addElement("item").addAttribute("node",
XMPPDateTimeFormat.format(offlineMessage.getCreationDate()));
routingTable.routePacket(receipient, offlineMessage, true);
}
......@@ -189,9 +180,8 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
stopOfflineFlooding(senderJID);
List<DiscoItem> answer = new ArrayList<DiscoItem>();
for (OfflineMessage offlineMessage : messageStore.getMessages(senderJID.getNode(), false)) {
synchronized (dateFormat) {
answer.add(new DiscoItem(new JID(senderJID.toBareJID()), offlineMessage.getFrom().toString(), dateFormat.format(offlineMessage.getCreationDate()), null));
}
answer.add(new DiscoItem(new JID(senderJID.toBareJID()), offlineMessage.getFrom().toString(),
XMPPDateTimeFormat.format(offlineMessage.getCreationDate()), null));
}
return answer.iterator();
......
......@@ -25,15 +25,13 @@ import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.xmpp.packet.IQ;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.TimeZone;
/**
* Implements the TYPE_IQ jabber:iq:time protocol (time info) as
......@@ -59,10 +57,6 @@ public class IQTimeHandler extends IQHandler implements ServerFeaturesProvider {
// todo: Make display text match the locale of user (xml:lang support)
private static final DateFormat DATE_FORMAT = DateFormat.getDateInstance(DateFormat.MEDIUM);
private static final DateFormat TIME_FORMAT = DateFormat.getTimeInstance(DateFormat.LONG);
// UTC and not JEP-0082 time format is used as per the JEP-0090 specification.
private static final FastDateFormat UTC_FORMAT =
FastDateFormat.getInstance(JiveConstants.XMPP_DELAY_DATETIME_FORMAT,
TimeZone.getTimeZone("UTC"));
private Element responseElement;
private IQHandlerInfo info;
......@@ -90,7 +84,7 @@ public class IQTimeHandler extends IQHandler implements ServerFeaturesProvider {
private Element buildResponse() {
Element response = responseElement.createCopy();
Date current = new Date();
response.element("utc").setText(UTC_FORMAT.format(current));
response.element("utc").setText(XMPPDateTimeFormat.formatOld(current));
StringBuilder display = new StringBuilder(DATE_FORMAT.format(current));
display.append(' ');
display.append(TIME_FORMAT.format(current));
......
......@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
......@@ -36,9 +35,8 @@ import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.component.ComponentEventListener;
import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
......@@ -61,8 +59,7 @@ public class PacketCopier implements PacketInterceptor, ComponentEventListener {
private static final Logger Log = LoggerFactory.getLogger(PacketCopier.class);
private final static PacketCopier instance = new PacketCopier();
private final static FastDateFormat dateFormat = FastDateFormat
.getInstance(JiveConstants.XMPP_DELAY_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private Map<String, Subscription> subscribers = new ConcurrentHashMap<String, Subscription>();
private String serverName;
......@@ -199,7 +196,7 @@ public class PacketCopier implements PacketInterceptor, ComponentEventListener {
"http://jabber.org/protocol/packet#event");
childElement.addAttribute("incoming", subscription.isIncoming() ? "true" : "false");
childElement.addAttribute("processed", subscription.isProcessed() ? "true" : "false");
childElement.addAttribute("date", dateFormat.format(interceptedPacket.getCreationDate()));
childElement.addAttribute("date", XMPPDateTimeFormat.formatOld(interceptedPacket.getCreationDate()));
childElement.add(interceptedPacket.getElement().createCopy());
// Send message notification to subscribed component
routingTable.routePacket(message.getTo(), message, true);
......
......@@ -20,18 +20,15 @@
package org.jivesoftware.openfire.muc;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.TimeZone;
import org.dom4j.Element;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.Message;
......@@ -51,14 +48,7 @@ import org.xmpp.packet.Message;
public class HistoryRequest {
private static final Logger Log = LoggerFactory.getLogger(HistoryRequest.class);
private static final DateFormat formatter = new SimpleDateFormat(JiveConstants.XMPP_DATETIME_FORMAT);
private static final DateFormat delayedFormatter = new SimpleDateFormat(
JiveConstants.XMPP_DELAY_DATETIME_FORMAT);
static {
delayedFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private static final XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();
private int maxChars = -1;
private int maxStanzas = -1;
......@@ -79,10 +69,8 @@ public class HistoryRequest {
}
if (history.attribute("since") != null) {
try {
// parse utc into Date
synchronized (formatter) {
this.since = formatter.parse(history.attributeValue("since"));
}
// parse since String into Date
this.since = xmppDateTime.parseString(history.attributeValue("since"));
}
catch(ParseException pe) {
Log.error("Error parsing date from history management", pe);
......@@ -193,11 +181,7 @@ public class HistoryRequest {
delayInformation = message.getChildElement("x", "jabber:x:delay");
try {
// Get the date when the historic message was sent
Date delayedDate;
synchronized (delayedFormatter) {
delayedDate = delayedFormatter
.parse(delayInformation.attributeValue("stamp"));
}
Date delayedDate = xmppDateTime.parseString(delayInformation.attributeValue("stamp"));
if (getSince() != null && delayedDate.before(getSince())) {
// Stop collecting history since we have exceded a limit
break;
......
......@@ -22,15 +22,13 @@ package org.jivesoftware.openfire.muc;
import org.dom4j.Element;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import java.util.Date;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.TimeZone;
/**
* Represent the data model for one <code>MUCRoom</code> history. Including chat transcript,
......@@ -40,11 +38,6 @@ import java.util.TimeZone;
*/
public final class MUCRoomHistory {
private static final FastDateFormat UTC_FORMAT = FastDateFormat
.getInstance(JiveConstants.XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private static final FastDateFormat UTC_FORMAT_OLD = FastDateFormat
.getInstance(JiveConstants.XMPP_DELAY_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private MUCRoom room;
private HistoryStrategy historyStrategy;
......@@ -110,8 +103,8 @@ public final class MUCRoomHistory {
Element delayInformation = packetToAdd.addChildElement("delay", "urn:xmpp:delay");
Element delayInformationOld = packetToAdd.addChildElement("x", "jabber:x:delay");
Date current = new Date();
delayInformation.addAttribute("stamp", UTC_FORMAT.format(current));
delayInformationOld.addAttribute("stamp", UTC_FORMAT_OLD.format(current));
delayInformation.addAttribute("stamp", XMPPDateTimeFormat.format(current));
delayInformationOld.addAttribute("stamp", XMPPDateTimeFormat.formatOld(current));
if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute
try {
......@@ -178,8 +171,8 @@ public final class MUCRoomHistory {
// Add the delay information to the message
Element delayInformation = message.addChildElement("delay", "urn:xmpp:delay");
Element delayInformationOld = message.addChildElement("x", "jabber:x:delay");
delayInformation.addAttribute("stamp", UTC_FORMAT.format(sentDate));
delayInformationOld.addAttribute("stamp", UTC_FORMAT_OLD.format(sentDate));
delayInformation.addAttribute("stamp", XMPPDateTimeFormat.format(sentDate));
delayInformationOld.addAttribute("stamp", XMPPDateTimeFormat.formatOld(sentDate));
if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute
delayInformation.addAttribute("from", senderJID);
......
......@@ -28,7 +28,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
......@@ -60,10 +59,9 @@ import org.jivesoftware.openfire.muc.cluster.GetNumberConnectedUsers;
import org.jivesoftware.openfire.muc.cluster.OccupantAddedEvent;
import org.jivesoftware.openfire.muc.cluster.RoomAvailableEvent;
import org.jivesoftware.openfire.muc.cluster.RoomRemovedEvent;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.JiveProperties;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -100,11 +98,6 @@ public class MultiUserChatServiceImpl implements Component, MultiUserChatService
private static final Logger Log = LoggerFactory.getLogger(MultiUserChatServiceImpl.class);
private static final FastDateFormat dateFormatter = FastDateFormat
.getInstance(JiveConstants.XMPP_DELAY_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
/**
* The time to elapse between clearing of idle chat users.
*/
......@@ -1340,7 +1333,7 @@ public class MultiUserChatServiceImpl implements Component, MultiUserChatService
final FormField fieldDate = dataForm.addField();
fieldDate.setVariable("x-muc#roominfo_creationdate");
fieldDate.setLabel(LocaleUtils.getLocalizedString("muc.extended.info.creationdate"));
fieldDate.addValue(dateFormatter.format(room.getCreationDate()));
fieldDate.addValue(XMPPDateTimeFormat.formatOld(room.getCreationDate()));
return dataForm;
}
......
......@@ -24,7 +24,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import org.dom4j.DocumentHelper;
......@@ -52,10 +51,9 @@ import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.jivesoftware.util.cache.Cacheable;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
......@@ -72,11 +70,6 @@ import org.xmpp.packet.PacketExtension;
* @author Armando Jagucki
*/
public class PEPService implements PubSubService, Cacheable {
/**
* Date format to use for time stamps in delayed event notifications.
*/
private static final FastDateFormat fastDateFormat;
/**
* The bare JID that this service is identified by.
......@@ -135,10 +128,6 @@ public class PEPService implements PubSubService, Cacheable {
*/
private EntityCapabilitiesManager entityCapsManager = EntityCapabilitiesManager.getInstance();
static {
fastDateFormat = FastDateFormat.getInstance(JiveConstants.XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
}
/**
* Constructs a PEPService.
*
......@@ -503,7 +492,7 @@ public class PEPService implements PubSubService, Cacheable {
notification.setBody(LocaleUtils.getLocalizedString("pubsub.notification.message.body"));
}
// Include date when published item was created
notification.getElement().addElement("delay", "urn:xmpp:delay").addAttribute("stamp", fastDateFormat.format(leafLastPublishedItem.getCreationDate()));
notification.getElement().addElement("delay", "urn:xmpp:delay").addAttribute("stamp", XMPPDateTimeFormat.format(leafLastPublishedItem.getCreationDate()));
// Send the event notification to the subscriber
this.sendNotification(subscription.getNode(), notification, subscription.getJID());
}
......
......@@ -21,18 +21,15 @@
package org.jivesoftware.openfire.pubsub;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.dom4j.Element;
import org.jivesoftware.util.FastDateFormat;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.forms.DataForm;
......@@ -67,8 +64,7 @@ public class NodeSubscription {
private static final Logger Log = LoggerFactory.getLogger(NodeSubscription.class);
private static final SimpleDateFormat dateFormat;
private static final FastDateFormat fastDateFormat;
private static final XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();
/**
* The node to which this subscription is interested in.
......@@ -140,13 +136,6 @@ public class NodeSubscription {
*/
private boolean savedToDB = false;
static {
dateFormat = new SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.SSS'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
fastDateFormat = FastDateFormat
.getInstance(JiveConstants.XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
}
/**
* Creates a new subscription of the specified user with the node.
*
......@@ -464,13 +453,10 @@ public class NodeSubscription {
}
else if ("pubsub#expire".equals(field.getVariable())) {
values = field.getValues();
synchronized (dateFormat) {
try {
expire = dateFormat.parse(values.get(0));
}
catch (ParseException e) {
Log.error("Error parsing date", e);
}
try {
expire = xmppDateTime.parseString(values.get(0));
} catch (ParseException e) {
Log.error("Error parsing date", e);
}
}
else if ("pubsub#include_body".equals(field.getVariable())) {
......@@ -564,7 +550,7 @@ public class NodeSubscription {
formField.setType(FormField.Type.text_single);
formField.setLabel(LocaleUtils.getLocalizedString("pubsub.form.subscription.expire"));
if (expire != null) {
formField.addValue(fastDateFormat.format(expire));
formField.addValue(XMPPDateTimeFormat.format(expire));
}
formField = form.addField();
......@@ -829,7 +815,7 @@ public class NodeSubscription {
}
// Include date when published item was created
notification.getElement().addElement("delay", "urn:xmpp:delay")
.addAttribute("stamp", fastDateFormat.format(publishedItem.getCreationDate()));
.addAttribute("stamp", XMPPDateTimeFormat.format(publishedItem.getCreationDate()));
// Send the event notification to the subscriber
node.getService().sendNotification(node, notification, jid);
}
......
......@@ -37,18 +37,4 @@ public class JiveConstants {
public static final long HOUR = 60 * MINUTE;
public static final long DAY = 24 * HOUR;
public static final long WEEK = 7 * DAY;
/**
* Date/time format for use by SimpleDateFormat. The format conforms to
* <a href="http://www.xmpp.org/extensions/xep-0082.html">XEP-0082</a>, which defines
* a unified date/time format for XMPP.
*/
public static final String XMPP_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/**
* Date/time format for use by SimpleDateFormat. The format conforms to the format
* defined in <a href="http://www.xmpp.org/extensions/xep-0091.html">XEP-0091</a>,
* a specialized date format for historical XMPP usage.
*/
public static final String XMPP_DELAY_DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss";
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2013 Florian Schmaus
*
* 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.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import net.jcip.annotations.ThreadSafe;
/**
*
* Utility class for date/time format conversions as specified in
* <a href="http://www.xmpp.org/extensions/xep-0082.html">XEP-0082</a> and
* <a href="http://www.xmpp.org/extensions/xep-0090.html">XEP-0090</a> and
* For Date -> String converstion FastDateFormat is used
*
*/
//@ThreadSafe
public class XMPPDateTimeFormat {
/**
* Date/time format for use by SimpleDateFormat. The format conforms to
* <a href="http://www.xmpp.org/extensions/xep-0082.html">XEP-0082</a>, which defines
* a unified date/time format for XMPP.
*/
public static final String XMPP_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
public static final String XMPP_DATETIME_FORMAT_WO_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ss.SSS";
public static final String XMPP_DATETIME_FORMAT_WO_MILLIS_WO_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ss";
public static final String XMPP_DATE_FORMAT = "yyyy-MM-dd";
public static final String XMPP_TIME_FORMAT = "HH:mm:ss.SSS";
public static final String XMPP_TIME_FORMAT_WO_MILLIS = "HH:mm:ss";
/**
* Date/time format for use by SimpleDateFormat. The format conforms to the format
* defined in <a href="http://www.xmpp.org/extensions/xep-0091.html">XEP-0091</a>,
* a specialized date format for historical XMPP usage.
*/
public static final String XMPP_DELAY_DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss";
// matches CCYY-MM-DDThh:mm:ss.SSS(Z|(+|-)hh:mm))
private static final Pattern xep80DateTimePattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+.\\d+(Z|([+-](\\d+:\\d+)))?$");
// matches CCYY-MM-DDThh:mm:ss(Z|(+|-)hh:mm))
private static final Pattern xep80DateTimeWoMillisPattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+(Z|([+-](\\d+:\\d+)))?$");
// matches CCYYMMDDThh:mm:ss
@SuppressWarnings("unused")
private static final Pattern xep91Pattern = Pattern.compile("^\\d+T\\d+:\\d+:\\d+$");
private static final FastDateFormat FAST_FORMAT = FastDateFormat.getInstance(
XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private static final FastDateFormat FAST_FORMAT_OLD = FastDateFormat.getInstance(
XMPP_DELAY_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private final DateFormat dateTimeFormat = new SimpleDateFormat(XMPP_DATETIME_FORMAT_WO_TIMEZONE + 'Z');
private final DateFormat dateTimeFormatWoMillies = new SimpleDateFormat(XMPP_DATETIME_FORMAT_WO_MILLIS_WO_TIMEZONE + 'Z');
private final DateFormat dateTimeFormatOld = new SimpleDateFormat(XMPP_DELAY_DATETIME_FORMAT);
/**
* Create a new thread-safe instance of this utility class
*/
public XMPPDateTimeFormat() {
TimeZone utc = TimeZone.getTimeZone("UTC");
dateTimeFormat.setTimeZone(utc);
dateTimeFormatWoMillies.setTimeZone(utc);
dateTimeFormatOld.setTimeZone(utc);
}
/**
* Tries to convert a given string to a Date object.
* This method supports the format types defined by XEP-0082 and the format defined in legacy protocols
* XEP-0082: CCYY-MM-DDThh:mm:ss[.sss]TZD
* legacy: CCYYMMDDThh:mm:ss
*
* @param dateStr
* @return
* @throws ParseException
*/
public synchronized Date parseString(String dateString) throws ParseException {
Matcher xep82WoMillisMatcher = xep80DateTimePattern.matcher(dateString);
Matcher xep82Matcher = xep80DateTimeWoMillisPattern.matcher(dateString);
if (xep82WoMillisMatcher.matches() || xep82Matcher.matches()) {
String rfc822Date;
// Convert the ISO 8601 time zone string to a RFC822 compatible format
// since SimpleDateFormat supports ISO8601 only with Java7 or higher
if (dateString.charAt(dateString.length() - 1) == 'Z') {
rfc822Date = dateString.replace("Z", "+0000");
} else {
// If the time zone wasn't specified with 'Z', then it's in
// ISO8601 format (i.e. '(+|-)HH:mm')
// RFC822 needs a similar format just without the colon (i.e.
// '(+|-)HHmm)'), so remove it
int lastColon = dateString.lastIndexOf(':');
rfc822Date = dateString.substring(0, lastColon) + dateString.substring(lastColon + 1);
}
if (xep82WoMillisMatcher.matches()) {
return dateTimeFormatWoMillies.parse(rfc822Date);
} else {
return dateTimeFormat.parse(rfc822Date);
}
} else {
// at last try with the legacy format
return dateTimeFormatOld.parse(dateString);
}
}
/**
* Tries to convert a given string to a Date object.
* This method only supports the legacy XMPP time format: CCYYMMDDThh:mm:ss
*
* @param dateStr
* @return
* @throws ParseException
*/
public synchronized Date parseOldDate(String dateStr) throws ParseException {
return dateTimeFormatOld.parse(dateStr);
}
/**
* Formats a Date object to String as defined in XEP-0082.
*
* The resulting String will have the timezone set to UTC ('Z') and includes milliseconds:
* CCYY-MM-DDThh:mm:ss.sssZ
*
* @param date
* @return
*/
public static String format(Date date) {
return FAST_FORMAT.format(date);
}
/**
* Formats a Date object to String as defined in legacy XMPP protocols (e.g. XEP-0090)
*
* CCYYMMDDThh:mm:ss
*
* @param date
* @return
*/
public static String formatOld(Date date) {
return FAST_FORMAT_OLD.format(date);
}
}
package com.reucon.openfire.plugin.archive.util;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.XMPPDateTimeFormat;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
* Utility class to parse and format dates in UTC that adhere to the DateTime format specified
......@@ -14,61 +11,15 @@ import java.util.TimeZone;
*/
public class XmppDateUtil
{
private static final DateFormat dateFormat;
private static final DateFormat dateFormatWithoutMillis;
static
{
dateFormat = new SimpleDateFormat(JiveConstants.XMPP_DATETIME_FORMAT);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
dateFormatWithoutMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
dateFormatWithoutMillis.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private XmppDateUtil()
{
}
private static final XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();
public static Date parseDate(String dateString)
{
Date date = null;
if (dateString == null)
{
try {
return xmppDateTime.parseString(dateString);
} catch (ParseException e) {
return null;
}
synchronized(dateFormat)
{
try
{
date = dateFormat.parse(dateString);
}
catch (ParseException e)
{
// ignore
}
}
if (date != null)
{
return date;
}
synchronized(dateFormatWithoutMillis)
{
try
{
date = dateFormatWithoutMillis.parse(dateString);
}
catch (ParseException e)
{
// ignore
}
}
return date;
}
public static String formatDate(Date date)
......@@ -77,10 +28,6 @@ public class XmppDateUtil
{
return null;
}
synchronized(dateFormat)
{
return dateFormat.format(date);
}
return XMPPDateTimeFormat.format(date);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment