/** * * Copyright 2003-2007 Jive Software. * * 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.iqprivate; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.XMPPError.Condition; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smackx.iqprivate.packet.DefaultPrivateData; import org.jivesoftware.smackx.iqprivate.packet.PrivateData; import org.jivesoftware.smackx.iqprivate.packet.PrivateDataIQ; import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider; import org.jxmpp.util.XmppStringUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Hashtable; import java.util.Map; import java.util.WeakHashMap; /** * Manages private data, which is a mechanism to allow users to store arbitrary XML * data on an XMPP server. Each private data chunk is defined by a element name and * XML namespace. Example private data: * *
* <color xmlns="http://example.com/xmpp/color"> * <favorite>blue</blue> * <leastFavorite>puce</leastFavorite> * </color> ** * {@link PrivateDataProvider} instances are responsible for translating the XML into objects. * If no PrivateDataProvider is registered for a given element name and namespace, then * a {@link DefaultPrivateData} instance will be returned.
*
* Warning: this is an non-standard protocol documented by
* XEP-49. Because this is a
* non-standard protocol, it is subject to change.
*
* @author Matt Tucker
*/
public final class PrivateDataManager extends Manager {
private static final Map Note: this method is generally only called by the internal Smack classes.
*
* @param elementName the XML element name.
* @param namespace the XML namespace.
* @return the PrivateData provider.
*/
public static PrivateDataProvider getPrivateDataProvider(String elementName, String namespace) {
String key = XmppStringUtils.generateKey(elementName, namespace);
return privateDataProviders.get(key);
}
/**
* Adds a private data provider with the specified element name and name space. The provider
* will override any providers loaded through the classpath.
*
* @param elementName the XML element name.
* @param namespace the XML namespace.
* @param provider the private data provider.
*/
public static void addPrivateDataProvider(String elementName, String namespace,
PrivateDataProvider provider)
{
String key = XmppStringUtils.generateKey(elementName, namespace);
privateDataProviders.put(key, provider);
}
/**
* Removes a private data provider with the specified element name and namespace.
*
* @param elementName The XML element name.
* @param namespace The XML namespace.
*/
public static void removePrivateDataProvider(String elementName, String namespace) {
String key = XmppStringUtils.generateKey(elementName, namespace);
privateDataProviders.remove(key);
}
/**
* Creates a new private data manager.
*
* @param connection an XMPP connection which must have already undergone a
* successful login.
*/
private PrivateDataManager(XMPPConnection connection) {
super(connection);
instances.put(connection, this);
}
/**
* Returns the private data specified by the given element name and namespace. Each chunk
* of private data is uniquely identified by an element name and namespace pair.
*
* If a PrivateDataProvider is registered for the specified element name/namespace pair then
* that provider will determine the specific object type that is returned. If no provider
* is registered, a {@link DefaultPrivateData} instance will be returned.
*
* @param elementName the element name.
* @param namespace the namespace.
* @return the private data.
* @throws XMPPErrorException
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
*/
public PrivateData getPrivateData(final String elementName, final String namespace) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{
// Create an IQ packet to get the private data.
IQ privateDataGet = new PrivateDataIQ(elementName, namespace);
PrivateDataIQ response = connection().createPacketCollectorAndSend(
privateDataGet).nextResultOrThrow();
return response.getPrivateData();
}
/**
* Sets a private data value. Each chunk of private data is uniquely identified by an
* element name and namespace pair. If private data has already been set with the
* element name and namespace, then the new private data will overwrite the old value.
*
* @param privateData the private data.
* @throws XMPPErrorException
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
*/
public void setPrivateData(final PrivateData privateData) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
// Create an IQ packet to set the private data.
IQ privateDataSet = new PrivateDataIQ(privateData);
connection().createPacketCollectorAndSend(privateDataSet).nextResultOrThrow();
}
private static final PrivateData DUMMY_PRIVATE_DATA = new PrivateData() {
@Override
public String getElementName() {
return "smackDummyPrivateData";
}
@Override
public String getNamespace() {
return "https://igniterealtime.org/projects/smack/";
}
@Override
public CharSequence toXML() {
return '<' + getElementName() + " xmlns='" + getNamespace() + "'/>";
}
};
/**
* Check if the service supports private data.
*
* @return true if the service supports private data, false otherwise.
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
* @throws XMPPErrorException
* @since 4.2
*/
public boolean isSupported() throws NoResponseException, NotConnectedException,
InterruptedException, XMPPErrorException {
// This is just a primitive hack, since XEP-49 does not specify a way to determine if the
// service supports it
try {
setPrivateData(DUMMY_PRIVATE_DATA);
return true;
}
catch (XMPPErrorException e) {
if (e.getXMPPError().getCondition() == Condition.service_unavailable) {
return false;
}
else {
throw e;
}
}
}
/**
* An IQ provider to parse IQ results containing private data.
*/
public static class PrivateDataIQProvider extends IQProvider
* <iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'>
* <query xmlns='jabber:iq:private'>
* <prefs xmlns='http://www.xmppclient.com/prefs'>
* <value1>ABC</value1>
* <value2>XYZ</value2>
* </prefs>
* </query>
* </iq>
*
*