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.HashMap;
020import java.util.Map;
021import java.util.WeakHashMap;
022
023import org.jivesoftware.smack.ConnectionCreationListener;
024import org.jivesoftware.smack.Manager;
025import org.jivesoftware.smack.SmackException.NoResponseException;
026import org.jivesoftware.smack.SmackException.NotConnectedException;
027import org.jivesoftware.smack.XMPPConnection;
028import org.jivesoftware.smack.XMPPConnectionRegistry;
029import org.jivesoftware.smack.XMPPException.XMPPErrorException;
030import org.jivesoftware.smack.packet.IQ;
031import org.jivesoftware.smack.packet.IQ.Type;
032import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
033import org.jivesoftware.smackx.push_notifications.element.DisablePushNotificationsIQ;
034import org.jivesoftware.smackx.push_notifications.element.EnablePushNotificationsIQ;
035import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements;
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
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 is supported by the server.
082     *
083     * @return true if Push Notifications is supported by the server.
084     * @throws NoResponseException
085     * @throws XMPPErrorException
086     * @throws NotConnectedException
087     * @throws InterruptedException
088     */
089    public boolean isSupportedByServer()
090            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
091        return ServiceDiscoveryManager.getInstanceFor(connection())
092                .serverSupportsFeature(PushNotificationsElements.NAMESPACE);
093    }
094
095    /**
096     * Enable push notifications.
097     * 
098     * @param pushJid
099     * @param node
100     * @return true if it was successfully enabled, false if not
101     * @throws NoResponseException
102     * @throws XMPPErrorException
103     * @throws NotConnectedException
104     * @throws InterruptedException
105     */
106    public boolean enable(Jid pushJid, String node)
107            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
108        return enable(pushJid, node, null);
109    }
110
111    /**
112     * Enable push notifications.
113     * 
114     * @param pushJid
115     * @param node
116     * @param publishOptions
117     * @return true if it was successfully enabled, false if not
118     * @throws NoResponseException
119     * @throws XMPPErrorException
120     * @throws NotConnectedException
121     * @throws InterruptedException
122     */
123    public boolean enable(Jid pushJid, String node, HashMap<String, String> publishOptions)
124            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
125        EnablePushNotificationsIQ enablePushNotificationsIQ = new EnablePushNotificationsIQ(pushJid, node,
126                publishOptions);
127        return changePushNotificationsStatus(enablePushNotificationsIQ);
128    }
129
130    /**
131     * Disable all push notifications.
132     * 
133     * @param pushJid
134     * @return true if it was successfully disabled, false if not
135     * @throws NoResponseException
136     * @throws XMPPErrorException
137     * @throws NotConnectedException
138     * @throws InterruptedException
139     */
140    public boolean disableAll(Jid pushJid)
141            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
142        return disable(pushJid, null);
143    }
144
145    /**
146     * Disable push notifications of an specific node.
147     * 
148     * @param pushJid
149     * @param node
150     * @return true if it was successfully disabled, false if not
151     * @throws NoResponseException
152     * @throws XMPPErrorException
153     * @throws NotConnectedException
154     * @throws InterruptedException
155     */
156    public boolean disable(Jid pushJid, String node)
157            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
158        DisablePushNotificationsIQ disablePushNotificationsIQ = new DisablePushNotificationsIQ(pushJid, node);
159        return changePushNotificationsStatus(disablePushNotificationsIQ);
160    }
161
162    private boolean changePushNotificationsStatus(IQ iq)
163            throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
164        final XMPPConnection connection = connection();
165        IQ responseIQ = connection.createStanzaCollectorAndSend(iq).nextResultOrThrow();
166        return responseIQ.getType() != Type.error;
167    }
168
169}