All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jivesoftware.smackx.PrivateDataManager Maven / Gradle / Ivy

Go to download

Smack is an Open Source XMPP (Jabber) client library for instant messaging and presence. This library provides the client side functionality as specified in the core XMPP specifications as related to the client side of said specifications.

The newest version!
/**
 * $RCSfile$
 * $Revision: 11613 $
 * $Date: 2010-02-09 05:55:56 -0600 (Tue, 09 Feb 2010) $
 *
 * Copyright 2003-2007 Jive Software.
 *
 * All rights reserved. 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;

import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smackx.packet.DefaultPrivateData;
import org.jivesoftware.smackx.packet.PrivateData;
import org.jivesoftware.smackx.provider.PrivateDataProvider;
import org.xmlpull.v1.XmlPullParser;

import java.util.Hashtable;
import java.util.Map;

/**
 * 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 * JEP-49. Because this is a * non-standard protocol, it is subject to change. * * @author Matt Tucker */ public class PrivateDataManager { /** * Map of provider instances. */ private static Map privateDataProviders = new Hashtable(); /** * Returns the private data provider registered to the specified XML element name and namespace. * For example, if a provider was registered to the element name "prefs" and the * namespace "http://www.xmppclient.com/prefs", then the following packet would trigger * the provider: * *

     * <iq type='result' to='[email protected]' from='[email protected]' id='time_1'>
     *     <query xmlns='jabber:iq:private'>
     *         <prefs xmlns='http://www.xmppclient.com/prefs'>
     *             <value1>ABC</value1>
     *             <value2>XYZ</value2>
     *         </prefs>
     *     </query>
     * </iq>
* *

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 = getProviderKey(elementName, namespace); return (PrivateDataProvider)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 = getProviderKey(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 = getProviderKey(elementName, namespace); privateDataProviders.remove(key); } private Connection connection; /** * The user to get and set private data for. In most cases, this value should * be null, as the typical use of private data is to get and set * your own private data and not others. */ private String user; /** * Creates a new private data manager. The connection must have * undergone a successful login before being used to construct an instance of * this class. * * @param connection an XMPP connection which must have already undergone a * successful login. */ public PrivateDataManager(Connection connection) { if (!connection.isAuthenticated()) { throw new IllegalStateException("Must be logged in to XMPP server."); } this.connection = connection; } /** * Creates a new private data manager for a specific user (special case). Most * servers only support getting and setting private data for the user that * authenticated via the connection. However, some servers support the ability * to get and set private data for other users (for example, if you are the * administrator). The connection must have undergone a successful login before * being used to construct an instance of this class. * * @param connection an XMPP connection which must have already undergone a * successful login. * @param user the XMPP address of the user to get and set private data for. */ public PrivateDataManager(Connection connection, String user) { if (!connection.isAuthenticated()) { throw new IllegalStateException("Must be logged in to XMPP server."); } this.connection = connection; this.user = user; } /** * 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 XMPPException if an error occurs getting the private data. */ public PrivateData getPrivateData(final String elementName, final String namespace) throws XMPPException { // Create an IQ packet to get the private data. IQ privateDataGet = new IQ() { public String getChildElementXML() { StringBuilder buf = new StringBuilder(); buf.append(""); buf.append("<").append(elementName).append(" xmlns=\"").append(namespace).append("\"/>"); buf.append(""); return buf.toString(); } }; privateDataGet.setType(IQ.Type.GET); // Address the packet to the other account if user has been set. if (user != null) { privateDataGet.setTo(user); } // Setup a listener for the reply to the set operation. String packetID = privateDataGet.getPacketID(); PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(packetID)); // Send the private data. connection.sendPacket(privateDataGet); // Wait up to five seconds for a response from the server. IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); // Stop queuing results collector.cancel(); if (response == null) { throw new XMPPException("No response from the server."); } // If the server replied with an error, throw an exception. else if (response.getType() == IQ.Type.ERROR) { throw new XMPPException(response.getError()); } return ((PrivateDataResult)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 XMPPException if setting the private data fails. */ public void setPrivateData(final PrivateData privateData) throws XMPPException { // Create an IQ packet to set the private data. IQ privateDataSet = new IQ() { public String getChildElementXML() { StringBuilder buf = new StringBuilder(); buf.append(""); buf.append(privateData.toXML()); buf.append(""); return buf.toString(); } }; privateDataSet.setType(IQ.Type.SET); // Address the packet to the other account if user has been set. if (user != null) { privateDataSet.setTo(user); } // Setup a listener for the reply to the set operation. String packetID = privateDataSet.getPacketID(); PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(packetID)); // Send the private data. connection.sendPacket(privateDataSet); // Wait up to five seconds for a response from the server. IQ response = (IQ)collector.nextResult(5000); // Stop queuing results collector.cancel(); if (response == null) { throw new XMPPException("No response from the server."); } // If the server replied with an error, throw an exception. else if (response.getType() == IQ.Type.ERROR) { throw new XMPPException(response.getError()); } } /** * Returns a String key for a given element name and namespace. * * @param elementName the element name. * @param namespace the namespace. * @return a unique key for the element name and namespace pair. */ private static String getProviderKey(String elementName, String namespace) { StringBuilder buf = new StringBuilder(); buf.append("<").append(elementName).append("/><").append(namespace).append("/>"); return buf.toString(); } /** * An IQ provider to parse IQ results containing private data. */ public static class PrivateDataIQProvider implements IQProvider { public IQ parseIQ(XmlPullParser parser) throws Exception { PrivateData privateData = null; boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); String namespace = parser.getNamespace(); // See if any objects are registered to handle this private data type. PrivateDataProvider provider = getPrivateDataProvider(elementName, namespace); // If there is a registered provider, use it. if (provider != null) { privateData = provider.parsePrivateData(parser); } // Otherwise, use a DefaultPrivateData instance to store the private data. else { DefaultPrivateData data = new DefaultPrivateData(elementName, namespace); boolean finished = false; while (!finished) { int event = parser.next(); if (event == XmlPullParser.START_TAG) { String name = parser.getName(); // If an empty element, set the value with the empty string. if (parser.isEmptyElementTag()) { data.setValue(name,""); } // Otherwise, get the the element text. else { event = parser.next(); if (event == XmlPullParser.TEXT) { String value = parser.getText(); data.setValue(name, value); } } } else if (event == XmlPullParser.END_TAG) { if (parser.getName().equals(elementName)) { finished = true; } } } privateData = data; } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("query")) { done = true; } } } return new PrivateDataResult(privateData); } } /** * An IQ packet to hold PrivateData GET results. */ private static class PrivateDataResult extends IQ { private PrivateData privateData; PrivateDataResult(PrivateData privateData) { this.privateData = privateData; } public PrivateData getPrivateData() { return privateData; } public String getChildElementXML() { StringBuilder buf = new StringBuilder(); buf.append(""); if (privateData != null) { privateData.toXML(); } buf.append(""); return buf.toString(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy