KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > smackx > PrivateDataManager


1 /**
2  * $RCSfile$
3  * $Revision: 2655 $
4  * $Date: 2005-08-15 12:21:02 -0300 (Mon, 15 Aug 2005) $
5  *
6  * Copyright 2003-2004 Jive Software.
7  *
8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */

20
21 package org.jivesoftware.smackx;
22
23 import org.jivesoftware.smack.*;
24 import org.jivesoftware.smack.provider.IQProvider;
25 import org.jivesoftware.smack.filter.PacketIDFilter;
26 import org.jivesoftware.smack.packet.IQ;
27 import org.jivesoftware.smackx.packet.*;
28 import org.jivesoftware.smackx.provider.*;
29 import org.xmlpull.v1.XmlPullParser;
30
31 import java.util.Map JavaDoc;
32 import java.util.Hashtable JavaDoc;
33
34 /**
35  * Manages private data, which is a mechanism to allow users to store arbitrary XML
36  * data on an XMPP server. Each private data chunk is defined by a element name and
37  * XML namespace. Example private data:
38  *
39  * <pre>
40  * &lt;color xmlns="http://example.com/xmpp/color"&gt;
41  * &lt;favorite&gt;blue&lt;/blue&gt;
42  * &lt;leastFavorite&gt;puce&lt;/leastFavorite&gt;
43  * &lt;/color&gt;
44  * </pre>
45  *
46  * {@link PrivateDataProvider} instances are responsible for translating the XML into objects.
47  * If no PrivateDataProvider is registered for a given element name and namespace, then
48  * a {@link DefaultPrivateData} instance will be returned.<p>
49  *
50  * Warning: this is an non-standard protocol documented by
51  * <a HREF="http://www.jabber.org/jeps/jep-0049.html">JEP-49</a>. Because this is a
52  * non-standard protocol, it is subject to change.
53  *
54  * @author Matt Tucker
55  */

56 public class PrivateDataManager {
57
58     /**
59      * Map of provider instances.
60      */

61     private static Map JavaDoc privateDataProviders = new Hashtable JavaDoc();
62
63     /**
64      * Returns the private data provider registered to the specified XML element name and namespace.
65      * For example, if a provider was registered to the element name "prefs" and the
66      * namespace "http://www.xmppclient.com/prefs", then the following packet would trigger
67      * the provider:
68      *
69      * <pre>
70      * &lt;iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'&gt;
71      * &lt;query xmlns='jabber:iq:private'&gt;
72      * &lt;prefs xmlns='http://www.xmppclient.com/prefs'&gt;
73      * &lt;value1&gt;ABC&lt;/value1&gt;
74      * &lt;value2&gt;XYZ&lt;/value2&gt;
75      * &lt;/prefs&gt;
76      * &lt;/query&gt;
77      * &lt;/iq&gt;</pre>
78      *
79      * <p>Note: this method is generally only called by the internal Smack classes.
80      *
81      * @param elementName the XML element name.
82      * @param namespace the XML namespace.
83      * @return the PrivateData provider.
84      */

85     public static PrivateDataProvider getPrivateDataProvider(String JavaDoc elementName, String JavaDoc namespace) {
86         String JavaDoc key = getProviderKey(elementName, namespace);
87         return (PrivateDataProvider)privateDataProviders.get(key);
88     }
89
90     /**
91      * Adds a private data provider with the specified element name and name space. The provider
92      * will override any providers loaded through the classpath.
93      *
94      * @param elementName the XML element name.
95      * @param namespace the XML namespace.
96      * @param provider the private data provider.
97      */

98     public static void addPrivateDataProvider(String JavaDoc elementName, String JavaDoc namespace,
99             PrivateDataProvider provider)
100     {
101         String JavaDoc key = getProviderKey(elementName, namespace);
102         privateDataProviders.put(key, provider);
103     }
104
105
106     private XMPPConnection connection;
107
108     /**
109      * The user to get and set private data for. In most cases, this value should
110      * be <tt>null</tt>, as the typical use of private data is to get and set
111      * your own private data and not others.
112      */

113     private String JavaDoc user;
114
115     /**
116      * Creates a new private data manager. The connection must have
117      * undergone a successful login before being used to construct an instance of
118      * this class.
119      *
120      * @param connection an XMPP connection which must have already undergone a
121      * successful login.
122      */

123     public PrivateDataManager(XMPPConnection connection) {
124         if (!connection.isAuthenticated()) {
125             throw new IllegalStateException JavaDoc("Must be logged in to XMPP server.");
126         }
127         this.connection = connection;
128     }
129
130     /**
131      * Creates a new private data manager for a specific user (special case). Most
132      * servers only support getting and setting private data for the user that
133      * authenticated via the connection. However, some servers support the ability
134      * to get and set private data for other users (for example, if you are the
135      * administrator). The connection must have undergone a successful login before
136      * being used to construct an instance of this class.
137      *
138      * @param connection an XMPP connection which must have already undergone a
139      * successful login.
140      * @param user the XMPP address of the user to get and set private data for.
141      */

142     public PrivateDataManager(XMPPConnection connection, String JavaDoc user) {
143         if (!connection.isAuthenticated()) {
144             throw new IllegalStateException JavaDoc("Must be logged in to XMPP server.");
145         }
146         this.connection = connection;
147         this.user = user;
148     }
149
150     /**
151      * Returns the private data specified by the given element name and namespace. Each chunk
152      * of private data is uniquely identified by an element name and namespace pair.<p>
153      *
154      * If a PrivateDataProvider is registered for the specified element name/namespace pair then
155      * that provider will determine the specific object type that is returned. If no provider
156      * is registered, a {@link DefaultPrivateData} instance will be returned.
157      *
158      * @param elementName the element name.
159      * @param namespace the namespace.
160      * @return the private data.
161      * @throws XMPPException if an error occurs getting the private data.
162      */

163     public PrivateData getPrivateData(final String JavaDoc elementName, final String JavaDoc namespace)
164             throws XMPPException
165     {
166         // Create an IQ packet to get the private data.
167
IQ privateDataGet = new IQ() {
168             public String JavaDoc getChildElementXML() {
169                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
170                 buf.append("<query xmlns=\"jabber:iq:private\">");
171                 buf.append("<").append(elementName).append(" xmlns=\"").append(namespace).append("\"/>");
172                 buf.append("</query>");
173                 return buf.toString();
174             }
175         };
176         privateDataGet.setType(IQ.Type.GET);
177         // Address the packet to the other account if user has been set.
178
if (user != null) {
179             privateDataGet.setTo(user);
180         }
181
182         // Setup a listener for the reply to the set operation.
183
String JavaDoc packetID = privateDataGet.getPacketID();
184         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(packetID));
185
186         // Send the private data.
187
connection.sendPacket(privateDataGet);
188
189         // Wait up to five seconds for a response from the server.
190
IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
191         // Stop queuing results
192
collector.cancel();
193         if (response == null) {
194             throw new XMPPException("No response from the server.");
195         }
196         // If the server replied with an error, throw an exception.
197
else if (response.getType() == IQ.Type.ERROR) {
198             throw new XMPPException(response.getError());
199         }
200         return ((PrivateDataResult)response).getPrivateData();
201     }
202
203     /**
204      * Sets a private data value. Each chunk of private data is uniquely identified by an
205      * element name and namespace pair. If private data has already been set with the
206      * element name and namespace, then the new private data will overwrite the old value.
207      *
208      * @param privateData the private data.
209      * @throws XMPPException if setting the private data fails.
210      */

211     public void setPrivateData(final PrivateData privateData) throws XMPPException {
212         // Create an IQ packet to set the private data.
213
IQ privateDataSet = new IQ() {
214             public String JavaDoc getChildElementXML() {
215                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
216                 buf.append("<query xmlns=\"jabber:iq:private\">");
217                 buf.append(privateData.toXML());
218                 buf.append("</query>");
219                 return buf.toString();
220             }
221         };
222         privateDataSet.setType(IQ.Type.SET);
223         // Address the packet to the other account if user has been set.
224
if (user != null) {
225             privateDataSet.setTo(user);
226         }
227
228         // Setup a listener for the reply to the set operation.
229
String JavaDoc packetID = privateDataSet.getPacketID();
230         PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(packetID));
231
232         // Send the private data.
233
connection.sendPacket(privateDataSet);
234
235         // Wait up to five seconds for a response from the server.
236
IQ response = (IQ)collector.nextResult(5000);
237         // Stop queuing results
238
collector.cancel();
239         if (response == null) {
240             throw new XMPPException("No response from the server.");
241         }
242         // If the server replied with an error, throw an exception.
243
else if (response.getType() == IQ.Type.ERROR) {
244             throw new XMPPException(response.getError());
245         }
246     }
247
248     /**
249      * Returns a String key for a given element name and namespace.
250      *
251      * @param elementName the element name.
252      * @param namespace the namespace.
253      * @return a unique key for the element name and namespace pair.
254      */

255     private static String JavaDoc getProviderKey(String JavaDoc elementName, String JavaDoc namespace) {
256         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
257         buf.append("<").append(elementName).append("/><").append(namespace).append("/>");
258         return buf.toString();
259     }
260
261     /**
262      * An IQ provider to parse IQ results containing private data.
263      */

264     public static class PrivateDataIQProvider implements IQProvider {
265         public IQ parseIQ(XmlPullParser parser) throws Exception JavaDoc {
266             PrivateData privateData = null;
267             boolean done = false;
268             while (!done) {
269                 int eventType = parser.next();
270                 if (eventType == XmlPullParser.START_TAG) {
271                     String JavaDoc elementName = parser.getName();
272                     String JavaDoc namespace = parser.getNamespace();
273                     // See if any objects are registered to handle this private data type.
274
PrivateDataProvider provider = getPrivateDataProvider(elementName, namespace);
275                     // If there is a registered provider, use it.
276
if (provider != null) {
277                         privateData = provider.parsePrivateData(parser);
278                     }
279                     // Otherwise, use a DefaultPrivateData instance to store the private data.
280
else {
281                         DefaultPrivateData data = new DefaultPrivateData(elementName, namespace);
282                         boolean finished = false;
283                         while (!finished) {
284                             int event = parser.next();
285                             if (event == XmlPullParser.START_TAG) {
286                                 String JavaDoc name = parser.getName();
287                                 // If an empty element, set the value with the empty string.
288
if (parser.isEmptyElementTag()) {
289                                     data.setValue(name,"");
290                                 }
291                                 // Otherwise, get the the element text.
292
else {
293                                     event = parser.next();
294                                     if (event == XmlPullParser.TEXT) {
295                                         String JavaDoc value = parser.getText();
296                                         data.setValue(name, value);
297                                     }
298                                 }
299                             }
300                             else if (event == XmlPullParser.END_TAG) {
301                                 if (parser.getName().equals(elementName)) {
302                                     finished = true;
303                                 }
304                             }
305                         }
306                         privateData = data;
307                     }
308                 }
309                 else if (eventType == XmlPullParser.END_TAG) {
310                     if (parser.getName().equals("query")) {
311                         done = true;
312                     }
313                 }
314             }
315             IQ result = new PrivateDataResult(privateData);
316             return result;
317         }
318     }
319
320     /**
321      * An IQ packet to hold PrivateData GET results.
322      */

323     private static class PrivateDataResult extends IQ {
324
325         private PrivateData privateData;
326
327         PrivateDataResult(PrivateData privateData) {
328             this.privateData = privateData;
329         }
330
331         public PrivateData getPrivateData() {
332             return privateData;
333         }
334
335         public String JavaDoc getChildElementXML() {
336             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
337             buf.append("<query xmlns=\"jabber:iq:private\">");
338             if (privateData != null) {
339                 privateData.toXML();
340             }
341             buf.append("</query>");
342             return buf.toString();
343         }
344     }
345 }
Popular Tags