diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/EntityTimeManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/EntityTimeManager.java
index 11d195b67..4262d8213 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/EntityTimeManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/EntityTimeManager.java
@@ -21,6 +21,8 @@ import java.util.WeakHashMap;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
@@ -75,12 +77,13 @@ public final class EntityTimeManager extends Manager {
Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
- if (enabled) {
- return Time.createResponse(iqRequest);
- }
- else {
+ if (!enabled) {
return IQ.createErrorResponse(iqRequest, Condition.not_acceptable);
}
+
+ Time timeRequest = (Time) iqRequest;
+ Time timeResponse = Time.builder(timeRequest).build();
+ return timeResponse;
}
});
}
@@ -105,13 +108,16 @@ public final class EntityTimeManager extends Manager {
return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, Time.NAMESPACE);
}
- public Time getTime(Jid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
- if (!isTimeSupported(jid))
- return null;
+ public Time getTime(Jid jid) throws NoResponseException, XMPPErrorException, NotConnectedException,
+ InterruptedException, FeatureNotSupportedException {
+ if (!isTimeSupported(jid)) {
+ throw new SmackException.FeatureNotSupportedException(Time.NAMESPACE);
+ }
- Time request = new Time();
- // TODO Add Time(Jid) constructor and use this constructor instead
- request.setTo(jid);
- return connection().createStanzaCollectorAndSend(request).nextResultOrThrow();
+ XMPPConnection connection = connection();
+ Time request = Time.builder(connection)
+ .to(jid)
+ .build();
+ return connection.createStanzaCollectorAndSend(request).nextResultOrThrow();
}
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/Time.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/Time.java
index 98189c312..bb7632210 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/Time.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/Time.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2003-2007 Jive Software, 2014 Florian Schmaus
+ * Copyright 2003-2007 Jive Software, 2014-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,10 @@ import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.IqData;
+import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.util.XmppDateTime;
@@ -33,31 +36,41 @@ import org.jxmpp.util.XmppDateTime;
* @see XEP-202
* @author Florian Schmaus
*/
-public class Time extends IQ {
+public class Time extends IQ implements TimeView {
+
public static final String NAMESPACE = "urn:xmpp:time";
public static final String ELEMENT = "time";
private static final Logger LOGGER = Logger.getLogger(Time.class.getName());
- private String utc;
- private String tzo;
+ private final String utc;
+ private final String tzo;
- public Time() {
- super(ELEMENT, NAMESPACE);
- setType(Type.get);
- }
+ public Time(TimeBuilder timeBuilder) {
+ super(timeBuilder, ELEMENT, NAMESPACE);
+ utc = timeBuilder.getUtc();
+ tzo = timeBuilder.getTzo();
- /**
- * Creates a new Time instance using the specified calendar instance as
- * the time value to send.
- *
- * @param cal the time value.
- */
- public Time(Calendar cal) {
- super(ELEMENT, NAMESPACE);
- tzo = XmppDateTime.asString(cal.getTimeZone());
- // Convert local time to the UTC time.
- utc = XmppDateTime.formatXEP0082Date(cal.getTime());
+ Type type = getType();
+ switch (type) {
+ case get:
+ if (utc != null) {
+ throw new IllegalArgumentException("Time requests must not have utc set");
+ }
+ if (tzo != null) {
+ throw new IllegalArgumentException("Time requests must not have tzo set");
+ }
+ break;
+ case result:
+ StringUtils.requireNotNullNorEmpty(utc, "Must have set a utc value");
+ StringUtils.requireNotNullNorEmpty(tzo, "Must have set a tzo value");
+ break;
+ case error:
+ // Nothing to check.
+ break;
+ case set:
+ throw new IllegalArgumentException("Invalid IQ type");
+ }
}
/**
@@ -79,67 +92,47 @@ public class Time extends IQ {
return date;
}
- /**
- * Sets the time using the local time.
- *
- * @param time the current local time.
- */
- public void setTime(Date time) {
- }
-
- /**
- * Returns the time as a UTC formatted String using the format CCYY-MM-DDThh:mm:ssZ.
- *
- * @return the time as a UTC formatted String.
- */
+ @Override
public String getUtc() {
return utc;
}
- /**
- * Sets the time using UTC formatted String in the format CCYY-MM-DDThh:mm:ssZ.
- *
- * @param utc the time using a formatted String.
- */
- public void setUtc(String utc) {
- this.utc = utc;
- }
-
- /**
- * Returns the time zone.
- *
- * @return the time zone.
- */
+ @Override
public String getTzo() {
return tzo;
}
- /**
- * Sets the time zone offset.
- *
- * @param tzo the time zone offset.
- */
- public void setTzo(String tzo) {
- this.tzo = tzo;
- }
-
- public static Time createResponse(IQ request) {
- Time time = new Time(Calendar.getInstance());
- time.setType(Type.result);
- time.setTo(request.getFrom());
- return time;
- }
-
@Override
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder buf) {
if (utc != null) {
buf.rightAngleBracket();
- buf.append("").append(utc).append("");
- buf.append("").append(tzo).append("");
+ buf.element("utc", utc);
+ buf.element("tzo", tzo);
} else {
buf.setEmptyElement();
}
return buf;
}
+
+ public static TimeBuilder builder(XMPPConnection connection) {
+ return new TimeBuilder(connection);
+ }
+
+ public static TimeBuilder builder(IqData iqData) {
+ return new TimeBuilder(iqData);
+ }
+
+ public static TimeBuilder builder(String stanzaId) {
+ return new TimeBuilder(stanzaId);
+ }
+
+ public static TimeBuilder builder(Time timeRequest, Calendar calendar) {
+ IqData iqData = IqData.createResponseData(timeRequest);
+ return builder(iqData).setTime(calendar);
+ }
+
+ public static TimeBuilder builder(Time timeRequest) {
+ return builder(timeRequest, Calendar.getInstance());
+ }
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeBuilder.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeBuilder.java
new file mode 100644
index 000000000..6b3332085
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeBuilder.java
@@ -0,0 +1,94 @@
+/**
+ *
+ * Copyright 2021 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.smackx.time.packet;
+
+import java.text.ParseException;
+import java.util.Calendar;
+
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.packet.IqBuilder;
+import org.jivesoftware.smack.packet.IqData;
+import org.jivesoftware.smack.util.StringUtils;
+
+import org.jxmpp.util.XmppDateTime;
+
+// TODO: Use java.time.ZonedDataTime once Smack's minimum Android SDK API level is 26 or higher.
+public class TimeBuilder extends IqBuilder implements TimeView {
+
+ private String utc;
+ private String tzo;
+
+ TimeBuilder(IqData iqCommon) {
+ super(iqCommon);
+ }
+
+ TimeBuilder(XMPPConnection connection) {
+ super(connection);
+ }
+
+ TimeBuilder(String stanzaId) {
+ super(stanzaId);
+ }
+
+ /**
+ * Sets the time using UTC formatted String, in the format CCYY-MM-DDThh:mm:ssZ, and the provided timezone
+ * definition in the format (+|-)hh:mm.
+ *
+ * @param utc the time using a formatted String.
+ * @param tzo the time zone definition.
+ * @return a reference to this builder.
+ * @throws ParseException if the provided string is not parsable (e.g. because it does not follow the expected
+ * format).
+ */
+ public TimeBuilder setUtcAndTzo(String utc, String tzo) throws ParseException {
+ this.utc = StringUtils.requireNotNullNorEmpty(utc, "Must provide utc argument");
+ // Sanity check the provided string.
+ XmppDateTime.parseDate(utc);
+
+ this.tzo = StringUtils.requireNotNullNorEmpty(tzo, "Must provide tzo argument");
+
+ return getThis();
+ }
+
+ public TimeBuilder setTime(Calendar calendar) {
+ // Convert local time to the UTC time.
+ utc = XmppDateTime.formatXEP0082Date(calendar.getTime());
+ tzo = XmppDateTime.asString(calendar.getTimeZone());
+
+ return getThis();
+ }
+
+ @Override
+ public String getUtc() {
+ return utc;
+ }
+
+ @Override
+ public String getTzo() {
+ return tzo;
+ }
+
+ @Override
+ public Time build() {
+ return new Time(this);
+ }
+
+ @Override
+ public TimeBuilder getThis() {
+ return this;
+ }
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeView.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeView.java
new file mode 100644
index 000000000..7ce47adce
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/packet/TimeView.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2021 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.smackx.time.packet;
+
+import org.jivesoftware.smack.packet.IqView;
+
+public interface TimeView extends IqView {
+
+ /**
+ * Returns the time as a UTC formatted String using the format CCYY-MM-DDThh:mm:ssZ.
+ *
+ * @return the time as a UTC formatted String.
+ */
+ String getUtc();
+
+ /**
+ * Returns the time zone.
+ *
+ * @return the time zone.
+ */
+ String getTzo();
+
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/provider/TimeProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/provider/TimeProvider.java
index 09ff3e4d2..d6c68e33c 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/time/provider/TimeProvider.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/time/provider/TimeProvider.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright © 2014 Florian Schmaus
+ * Copyright © 2014-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,55 @@
*/
package org.jivesoftware.smackx.time.provider;
-import org.jivesoftware.smack.provider.IntrospectionProvider.IQIntrospectionProvider;
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.jivesoftware.smack.packet.IqData;
+import org.jivesoftware.smack.packet.XmlEnvironment;
+import org.jivesoftware.smack.provider.IqProvider;
+import org.jivesoftware.smack.xml.XmlPullParser;
+import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.time.packet.Time;
+import org.jivesoftware.smackx.time.packet.TimeBuilder;
-public class TimeProvider extends IQIntrospectionProvider