001/**
002 *
003 * Copyright 2014 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.vcardtemp;
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;
030import org.jivesoftware.smack.packet.id.StanzaIdUtil;
031import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
032import org.jivesoftware.smackx.vcardtemp.packet.VCard;
033
034public class VCardManager extends Manager {
035    public static final String NAMESPACE = VCard.NAMESPACE;
036    public static final String ELEMENT = VCard.ELEMENT;
037
038    private static final Map<XMPPConnection, VCardManager> INSTANCES = new WeakHashMap<>();
039
040    static {
041        XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
042            @Override
043            public void connectionCreated(XMPPConnection connection) {
044                getInstanceFor(connection);
045            }
046        });
047    }
048
049    /**
050     * Retrieves a {@link VCardManager} for the specified {@link XMPPConnection}, creating one if it doesn't already
051     * exist.
052     * 
053     * @param connection the connection the manager is attached to.
054     * @return The new or existing manager.
055     */
056    public static synchronized VCardManager getInstanceFor(XMPPConnection connection) {
057        VCardManager vcardManager = INSTANCES.get(connection);
058        if (vcardManager == null) {
059            vcardManager = new VCardManager(connection);
060            INSTANCES.put(connection, vcardManager);
061        }
062        return vcardManager;
063    }
064
065    /**
066     * Returns true if the given entity understands the vCard-XML format and allows the exchange of such.
067     * 
068     * @param jid
069     * @param connection
070     * @return true if the given entity understands the vCard-XML format and exchange.
071     * @throws XMPPErrorException 
072     * @throws NoResponseException 
073     * @throws NotConnectedException
074     * @deprecated use {@link #isSupported(String)} instead.
075     */
076    @Deprecated
077    public static boolean isSupported(String jid, XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException  {
078        return VCardManager.getInstanceFor(connection).isSupported(jid);
079    }
080
081    private VCardManager(XMPPConnection connection) {
082        super(connection);
083        ServiceDiscoveryManager.getInstanceFor(connection).addFeature(NAMESPACE);
084    }
085
086    /**
087     * Save this vCard for the user connected by 'connection'. XMPPConnection should be authenticated
088     * and not anonymous.
089     *
090     * @throws XMPPErrorException thrown if there was an issue setting the VCard in the server.
091     * @throws NoResponseException if there was no response from the server.
092     * @throws NotConnectedException 
093     */
094    public void saveVCard(VCard vcard) throws NoResponseException, XMPPErrorException, NotConnectedException {
095        // XEP-54 § 3.2 "A user may publish or update his or her vCard by sending an IQ of type "set" with no 'to' address…"
096        vcard.setTo(null);
097        vcard.setType(IQ.Type.set);
098        // Also make sure to generate a new stanza id (the given vcard could be a vcard result), in which case we don't
099        // want to use the same stanza id again (although it wouldn't break if we did)
100        vcard.setStanzaId(StanzaIdUtil.newStanzaId());
101        connection().createPacketCollectorAndSend(vcard).nextResultOrThrow();
102    }
103
104    /**
105     * Load the VCard of the current user.
106     *
107     * @throws XMPPErrorException 
108     * @throws NoResponseException 
109     * @throws NotConnectedException 
110     */
111    public VCard loadVCard() throws NoResponseException, XMPPErrorException, NotConnectedException {
112        return loadVCard(null);
113    }
114
115    /**
116     * Load VCard information for a given user.
117     *
118     * @throws XMPPErrorException 
119     * @throws NoResponseException if there was no response from the server.
120     * @throws NotConnectedException 
121     */
122    public VCard loadVCard(String bareJid) throws NoResponseException, XMPPErrorException, NotConnectedException {
123        VCard vcardRequest = new VCard();
124        vcardRequest.setTo(bareJid);
125        VCard result = connection().createPacketCollectorAndSend(vcardRequest).nextResultOrThrow();
126        return result;
127    }
128
129    /**
130     * Returns true if the given entity understands the vCard-XML format and allows the exchange of such.
131     * 
132     * @param jid
133     * @return true if the given entity understands the vCard-XML format and exchange.
134     * @throws XMPPErrorException 
135     * @throws NoResponseException 
136     * @throws NotConnectedException 
137     */
138    public boolean isSupported(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException {
139        return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, NAMESPACE);
140    }
141}