001/*
002 *
003 * Copyright 2003-2007 Jive Software, 2014-2025 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.time.packet;
018
019import java.time.ZonedDateTime;
020import java.util.Calendar;
021import java.util.Date;
022
023import org.jivesoftware.smack.XMPPConnection;
024import org.jivesoftware.smack.packet.IQ;
025import org.jivesoftware.smack.packet.IqData;
026import org.jivesoftware.smack.util.Objects;
027
028/**
029 * A Time IQ packet, which is used by XMPP clients to exchange their respective local
030 * times. Clients that wish to fully support the entity time protocol should register
031 * a PacketListener for incoming time requests that then respond with the local time.
032 *
033 * @see <a href="http://www.xmpp.org/extensions/xep-0202.html">XEP-202</a>
034 * @author Florian Schmaus
035 */
036public class Time extends IQ implements TimeView {
037
038    public static final String NAMESPACE = "urn:xmpp:time";
039    public static final String ELEMENT = "time";
040
041    private final ZonedDateTime zonedDateTime;
042
043    @SuppressWarnings("this-escape")
044    public Time(TimeBuilder timeBuilder) {
045        super(timeBuilder, ELEMENT, NAMESPACE);
046        zonedDateTime = timeBuilder.getZonedDateTime();
047
048        Type type = getType();
049        switch (type) {
050        case get:
051            if (zonedDateTime != null) {
052                throw new IllegalArgumentException("Time requests must not have time set");
053            }
054            break;
055        case result:
056            Objects.requireNonNull(zonedDateTime, "Must have set a time value");
057            break;
058        case error:
059            // Nothing to check.
060            break;
061        case set:
062            throw new IllegalArgumentException("Invalid IQ type");
063        }
064    }
065
066    @Override
067    public ZonedDateTime getZonedDateTime() {
068        return zonedDateTime;
069    }
070
071    /**
072     * Returns the local time or <code>null</code> if the time hasn't been set.
073     *
074     * @return the local time.
075     * @deprecated use {@link #getZonedDateTime()} instead.
076     */
077    // TODO: Remove in Smack 4.6
078    @Deprecated
079    public Date getTime() {
080        if (zonedDateTime == null) return null;
081
082        return Date.from(zonedDateTime.toInstant());
083    }
084
085    @Override
086    protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder buf) {
087        if (zonedDateTime != null) {
088            buf.rightAngleBracket();
089            buf.element("utc", getUtc());
090            buf.element("tzo", getTzo());
091        } else {
092            buf.setEmptyElement();
093        }
094
095        return buf;
096    }
097
098    public static TimeBuilder builder(XMPPConnection connection) {
099        return new TimeBuilder(connection);
100    }
101
102    public static TimeBuilder builder(IqData iqData) {
103        return new TimeBuilder(iqData);
104    }
105
106    public static TimeBuilder builder(String stanzaId) {
107        return new TimeBuilder(stanzaId);
108    }
109
110    public static TimeBuilder builder(Time timeRequest, Calendar calendar) {
111        IqData iqData = IqData.createResponseData(timeRequest);
112        return builder(iqData).setTime(calendar);
113    }
114
115    public static TimeBuilder builder(Time timeRequest) {
116        return builder(timeRequest, Calendar.getInstance());
117    }
118}