001/**
002 *
003 * Copyright © 2016 Fernando Ramirez
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.push_notifications;
018
019import java.util.Map;
020import java.util.WeakHashMap;
021
022import org.jivesoftware.smack.ConnectionCreationListener;
023import org.jivesoftware.smack.Manager;
024import org.jivesoftware.smack.SmackException.NoResponseException;
025import org.jivesoftware.smack.SmackException.NotConnectedException;
026import org.jivesoftware.smack.XMPPConnection;
027import org.jivesoftware.smack.XMPPConnectionRegistry;
028import org.jivesoftware.smack.XMPPException.XMPPErrorException;
029import org.jivesoftware.smack.packet.IQ;
030
031import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
032import org.jivesoftware.smackx.push_notifications.element.DisablePushNotificationsIQ;
033import org.jivesoftware.smackx.push_notifications.element.EnablePushNotificationsIQ;
034import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements;
035
036import org.jxmpp.jid.Jid;
037
038/**
039 * Push Notifications manager class.
040 *
041 * @see <a href="http://xmpp.org/extensions/xep-0357.html">XEP-0357: Push
042 *      Notifications</a>
043 * @author Fernando Ramirez
044 *
045 */
046public final class PushNotificationsManager extends Manager {
047
048    static {
049        XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
050            @Override
051            public void connectionCreated(XMPPConnection connection) {
052                getInstanceFor(connection);
053            }
054        });
055    }
056
057    private static final Map<XMPPConnection, PushNotificationsManager> INSTANCES = new WeakHashMap<>();
058
059    /**
060     * Get the singleton instance of PushNotificationsManager.
061     *
062     * @param connection TODO javadoc me please
063     * @return the instance of PushNotificationsManager
064     */
065    public static synchronized PushNotificationsManager getInstanceFor(XMPPConnection connection) {
066        PushNotificationsManager pushNotificationsManager = INSTANCES.get(connection);
067
068        if (pushNotificationsManager == null) {
069            pushNotificationsManager = new PushNotificationsManager(connection);
070            INSTANCES.put(connection, pushNotificationsManager);
071        }
072
073        return pushNotificationsManager;
074    }
075
076    private PushNotificationsManager(XMPPConnection connection) {
077        super(connection);
078    }
079
080    /**
081     * Returns true if Push Notifications are supported by this account.
082     *
083     * @return true if Push Notifications are supported by this account.
084     * @throws NoResponseException if there was no response from the remote entity.
085     * @throws XMPPErrorException if there was an XMPP error returned.
086     * @throws NotConnectedException if the XMPP connection is not connected.
087     * @throws InterruptedException if the calling thread was interrupted.
088     * @since 4.2.2
089     */
090    public boolean isSupported()
091                    throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
092        return ServiceDiscoveryManager.getInstanceFor(connection()).accountSupportsFeatures(
093                        PushNotificationsElements.NAMESPACE);
094    }
095
096    /**
097     * Enable push notifications.
098     *
099     * @param pushJid TODO javadoc me please
100     * @param node TODO javadoc me please
101     * @return true if it was successfully enabled, false if not
102     * @throws NoResponseException if there was no response from the remote entity.
103     * @throws XMPPErrorException if there was an XMPP error returned.
104     * @throws NotConnectedException if the XMPP connection is not connected.
105     * @throws InterruptedException if the calling thread was interrupted.
106     */
107    public boolean enable(Jid pushJid, String node)
108            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
109        return enable(pushJid, node, null);
110    }
111
112    /**
113     * Enable push notifications.
114     *
115     * @param pushJid TODO javadoc me please
116     * @param node TODO javadoc me please
117     * @param publishOptions TODO javadoc me please
118     * @return true if it was successfully enabled, false if not
119     * @throws NoResponseException if there was no response from the remote entity.
120     * @throws XMPPErrorException if there was an XMPP error returned.
121     * @throws NotConnectedException if the XMPP connection is not connected.
122     * @throws InterruptedException if the calling thread was interrupted.
123     */
124    public boolean enable(Jid pushJid, String node, Map<String, String> publishOptions)
125            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
126        EnablePushNotificationsIQ enablePushNotificationsIQ = new EnablePushNotificationsIQ(pushJid, node,
127                publishOptions);
128        return changePushNotificationsStatus(enablePushNotificationsIQ);
129    }
130
131    /**
132     * Disable all push notifications.
133     *
134     * @param pushJid TODO javadoc me please
135     * @return true if it was successfully disabled, false if not
136     * @throws NoResponseException if there was no response from the remote entity.
137     * @throws XMPPErrorException if there was an XMPP error returned.
138     * @throws NotConnectedException if the XMPP connection is not connected.
139     * @throws InterruptedException if the calling thread was interrupted.
140     */
141    public boolean disableAll(Jid pushJid)
142            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
143        return disable(pushJid, null);
144    }
145
146    /**
147     * Disable push notifications of an specific node.
148     *
149     * @param pushJid TODO javadoc me please
150     * @param node TODO javadoc me please
151     * @return true if it was successfully disabled, false if not
152     * @throws NoResponseException if there was no response from the remote entity.
153     * @throws XMPPErrorException if there was an XMPP error returned.
154     * @throws NotConnectedException if the XMPP connection is not connected.
155     * @throws InterruptedException if the calling thread was interrupted.
156     */
157    public boolean disable(Jid pushJid, String node)
158            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
159        DisablePushNotificationsIQ disablePushNotificationsIQ = new DisablePushNotificationsIQ(pushJid, node);
160        return changePushNotificationsStatus(disablePushNotificationsIQ);
161    }
162
163    private boolean changePushNotificationsStatus(IQ iq)
164            throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
165        final XMPPConnection connection = connection();
166        IQ responseIQ = connection.sendIqRequestAndWaitForResponse(iq);
167        return responseIQ.getType() != IQ.Type.error;
168    }
169
170}