KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > smack > packet > Packet


1 /**
2  * $RCSfile$
3  * $Revision: 2408 $
4  * $Date: 2004-11-02 20:53:30 -0300 (Tue, 02 Nov 2004) $
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.smack.packet;
22
23 import org.jivesoftware.smack.util.StringUtils;
24
25 import java.util.*;
26 import java.io.*;
27
28 /**
29  * Base class for XMPP packets. Every packet has a unique ID (which is automatically
30  * generated, but can be overriden). Optionally, the "to" and "from" fields can be set,
31  * as well as an arbitrary number of properties.
32  *
33  * Properties provide an easy mechanism for clients to share data. Each property has a
34  * String name, and a value that is a Java primitive (int, long, float, double, boolean)
35  * or any Serializable object (a Java object is Serializable when it implements the
36  * Serializable interface).
37  *
38  * @author Matt Tucker
39  */

40 public abstract class Packet {
41
42     /**
43      * Constant used as packetID to indicate that a packet has no id. To indicate that a packet
44      * has no id set this constant as the packet's id. When the packet is asked for its id the
45      * answer will be <tt>null</tt>.
46      */

47     public static final String JavaDoc ID_NOT_AVAILABLE = "ID_NOT_AVAILABLE";
48
49     /**
50      * A prefix helps to make sure that ID's are unique across mutliple instances.
51      */

52     private static String JavaDoc prefix = StringUtils.randomString(5) + "-";
53
54     /**
55      * Keeps track of the current increment, which is appended to the prefix to
56      * forum a unique ID.
57      */

58     private static long id = 0;
59
60     /**
61      * Returns the next unique id. Each id made up of a short alphanumeric
62      * prefix along with a unique numeric value.
63      *
64      * @return the next id.
65      */

66     private static synchronized String JavaDoc nextID() {
67         return prefix + Long.toString(id++);
68     }
69
70     private String JavaDoc packetID = null;
71     private String JavaDoc to = null;
72     private String JavaDoc from = null;
73     private List packetExtensions = null;
74     private Map properties = null;
75     private XMPPError error = null;
76
77     /**
78      * Returns the unique ID of the packet. The returned value could be <tt>null</tt> when
79      * ID_NOT_AVAILABLE was set as the packet's id.
80      *
81      * @return the packet's unique ID or <tt>null</tt> if the packet's id is not available.
82      */

83     public String JavaDoc getPacketID() {
84         if (ID_NOT_AVAILABLE.equals(packetID)) {
85             return null;
86         }
87         
88         if (packetID == null) {
89             packetID = nextID();
90         }
91         return packetID;
92     }
93
94     /**
95      * Sets the unique ID of the packet. To indicate that a packet has no id
96      * pass the constant ID_NOT_AVAILABLE as the packet's id value.
97      *
98      * @param packetID the unique ID for the packet.
99      */

100     public void setPacketID(String JavaDoc packetID) {
101         this.packetID = packetID;
102     }
103
104     /**
105      * Returns who the packet is being sent "to", or <tt>null</tt> if
106      * the value is not set. The XMPP protocol often makes the "to"
107      * attribute optional, so it does not always need to be set.
108      *
109      * @return who the packet is being sent to, or <tt>null</tt> if the
110      * value has not been set.
111      */

112     public String JavaDoc getTo() {
113         return to;
114     }
115
116     /**
117      * Sets who the packet is being sent "to". The XMPP protocol often makes
118      * the "to" attribute optional, so it does not always need to be set.
119      *
120      * @param to who the packet is being sent to.
121      */

122     public void setTo(String JavaDoc to) {
123         this.to = to;
124     }
125
126     /**
127      * Returns who the packet is being sent "from" or <tt>null</tt> if
128      * the value is not set. The XMPP protocol often makes the "from"
129      * attribute optional, so it does not always need to be set.
130      *
131      * @return who the packet is being sent from, or <tt>null</tt> if the
132      * valud has not been set.
133      */

134     public String JavaDoc getFrom() {
135         return from;
136     }
137
138     /**
139      * Sets who the packet is being sent "from". The XMPP protocol often
140      * makes the "from" attribute optional, so it does not always need to
141      * be set.
142      *
143      * @param from who the packet is being sent to.
144      */

145     public void setFrom(String JavaDoc from) {
146         this.from = from;
147     }
148
149     /**
150      * Returns the error associated with this packet, or <tt>null</tt> if there are
151      * no errors.
152      *
153      * @return the error sub-packet or <tt>null</tt> if there isn't an error.
154      */

155     public XMPPError getError() {
156         return error;
157     }
158
159     /**
160      * Sets the error for this packet.
161      *
162      * @param error the error to associate with this packet.
163      */

164     public void setError(XMPPError error) {
165         this.error = error;
166     }
167
168     /**
169      * Returns an Iterator for the packet extensions attached to the packet.
170      *
171      * @return an Iterator for the packet extensions.
172      */

173     public synchronized Iterator getExtensions() {
174         if (packetExtensions == null) {
175             return Collections.EMPTY_LIST.iterator();
176         }
177         return Collections.unmodifiableList(new ArrayList(packetExtensions)).iterator();
178     }
179
180     /**
181      * Returns the first packet extension that matches the specified element name and
182      * namespace, or <tt>null</tt> if it doesn't exist. Packet extensions are
183      * are arbitrary XML sub-documents in standard XMPP packets. By default, a
184      * DefaultPacketExtension instance will be returned for each extension. However,
185      * PacketExtensionProvider instances can be registered with the
186      * {@link org.jivesoftware.smack.provider.ProviderManager ProviderManager}
187      * class to handle custom parsing. In that case, the type of the Object
188      * will be determined by the provider.
189      *
190      * @param elementName the XML element name of the packet extension.
191      * @param namespace the XML element namespace of the packet extension.
192      * @return the extension, or <tt>null</tt> if it doesn't exist.
193      */

194     public synchronized PacketExtension getExtension(String JavaDoc elementName, String JavaDoc namespace) {
195         if (packetExtensions == null || elementName == null || namespace == null) {
196             return null;
197         }
198         for (Iterator i=packetExtensions.iterator(); i.hasNext(); ) {
199             PacketExtension ext = (PacketExtension)i.next();
200             if (elementName.equals(ext.getElementName()) && namespace.equals(ext.getNamespace())) {
201                 return ext;
202             }
203         }
204         return null;
205     }
206
207     /**
208      * Adds a packet extension to the packet.
209      *
210      * @param extension a packet extension.
211      */

212     public synchronized void addExtension(PacketExtension extension) {
213         if (packetExtensions == null) {
214             packetExtensions = new ArrayList();
215         }
216         packetExtensions.add(extension);
217     }
218
219     /**
220      * Removes a packet extension from the packet.
221      *
222      * @param extension the packet extension to remove.
223      */

224     public synchronized void removeExtension(PacketExtension extension) {
225         if (packetExtensions != null) {
226             packetExtensions.remove(extension);
227         }
228     }
229
230     /**
231      * Returns the packet property with the specified name or <tt>null</tt> if the
232      * property doesn't exist. Property values that were orginally primitives will
233      * be returned as their object equivalent. For example, an int property will be
234      * returned as an Integer, a double as a Double, etc.
235      *
236      * @param name the name of the property.
237      * @return the property, or <tt>null</tt> if the property doesn't exist.
238      */

239     public synchronized Object JavaDoc getProperty(String JavaDoc name) {
240         if (properties == null) {
241             return null;
242         }
243         return properties.get(name);
244     }
245
246     /**
247      * Sets a packet property with an int value.
248      *
249      * @param name the name of the property.
250      * @param value the value of the property.
251      */

252     public void setProperty(String JavaDoc name, int value) {
253         setProperty(name, new Integer JavaDoc(value));
254     }
255
256     /**
257      * Sets a packet property with a long value.
258      *
259      * @param name the name of the property.
260      * @param value the value of the property.
261      */

262     public void setProperty(String JavaDoc name, long value) {
263         setProperty(name, new Long JavaDoc(value));
264     }
265
266     /**
267      * Sets a packet property with a float value.
268      *
269      * @param name the name of the property.
270      * @param value the value of the property.
271      */

272     public void setProperty(String JavaDoc name, float value) {
273         setProperty(name, new Float JavaDoc(value));
274     }
275
276     /**
277      * Sets a packet property with a double value.
278      *
279      * @param name the name of the property.
280      * @param value the value of the property.
281      */

282     public void setProperty(String JavaDoc name, double value) {
283         setProperty(name, new Double JavaDoc(value));
284     }
285
286     /**
287      * Sets a packet property with a bboolean value.
288      *
289      * @param name the name of the property.
290      * @param value the value of the property.
291      */

292     public void setProperty(String JavaDoc name, boolean value) {
293         setProperty(name, new Boolean JavaDoc(value));
294     }
295
296     /**
297      * Sets a property with an Object as the value. The value must be Serializable
298      * or an IllegalArgumentException will be thrown.
299      *
300      * @param name the name of the property.
301      * @param value the value of the property.
302      */

303     public synchronized void setProperty(String JavaDoc name, Object JavaDoc value) {
304         if (!(value instanceof Serializable)) {
305             throw new IllegalArgumentException JavaDoc("Value must be serialiazble");
306         }
307         if (properties == null) {
308             properties = new HashMap();
309         }
310         properties.put(name, value);
311     }
312
313     /**
314      * Deletes a property.
315      *
316      * @param name the name of the property to delete.
317      */

318     public synchronized void deleteProperty(String JavaDoc name) {
319         if (properties == null) {
320             return;
321         }
322         properties.remove(name);
323     }
324
325     /**
326      * Returns an Iterator for all the property names that are set.
327      *
328      * @return an Iterator for all property names.
329      */

330     public synchronized Iterator getPropertyNames() {
331         if (properties == null) {
332             return Collections.EMPTY_LIST.iterator();
333         }
334         return properties.keySet().iterator();
335     }
336
337     /**
338      * Returns the packet as XML. Every concrete extension of Packet must implement
339      * this method. In addition to writing out packet-specific data, every sub-class
340      * should also write out the error and the extensions data if they are defined.
341      *
342      * @return the XML format of the packet as a String.
343      */

344     public abstract String JavaDoc toXML();
345
346     /**
347      * Returns the extension sub-packets (including properties data) as an XML
348      * String, or the Empty String if there are no packet extensions.
349      *
350      * @return the extension sub-packets as XML or the Empty String if there
351      * are no packet extensions.
352      */

353     protected synchronized String JavaDoc getExtensionsXML() {
354         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
355         // Add in all standard extension sub-packets.
356
Iterator extensions = getExtensions();
357         while (extensions.hasNext()) {
358             PacketExtension extension = (PacketExtension)extensions.next();
359             buf.append(extension.toXML());
360         }
361         // Add in packet properties.
362
if (properties != null && !properties.isEmpty()) {
363             buf.append("<properties xmlns=\"http://www.jivesoftware.com/xmlns/xmpp/properties\">");
364             // Loop through all properties and write them out.
365
for (Iterator i=getPropertyNames(); i.hasNext(); ) {
366                 String JavaDoc name = (String JavaDoc)i.next();
367                 Object JavaDoc value = getProperty(name);
368                 buf.append("<property>");
369                 buf.append("<name>").append(StringUtils.escapeForXML(name)).append("</name>");
370                 buf.append("<value type=\"");
371                 if (value instanceof Integer JavaDoc) {
372                     buf.append("integer\">").append(value).append("</value>");
373                 }
374                 else if (value instanceof Long JavaDoc) {
375                     buf.append("long\">").append(value).append("</value>");
376                 }
377                 else if (value instanceof Float JavaDoc) {
378                     buf.append("float\">").append(value).append("</value>");
379                 }
380                 else if (value instanceof Double JavaDoc) {
381                     buf.append("double\">").append(value).append("</value>");
382                 }
383                 else if (value instanceof Boolean JavaDoc) {
384                     buf.append("boolean\">").append(value).append("</value>");
385                 }
386                 else if (value instanceof String JavaDoc) {
387                     buf.append("string\">");
388                     buf.append(StringUtils.escapeForXML((String JavaDoc)value));
389                     buf.append("</value>");
390                 }
391                 // Otherwise, it's a generic Serializable object. Serialized objects are in
392
// a binary format, which won't work well inside of XML. Therefore, we base-64
393
// encode the binary data before adding it.
394
else {
395                     ByteArrayOutputStream byteStream = null;
396                     ObjectOutputStream out = null;
397                     try {
398                         byteStream = new ByteArrayOutputStream();
399                         out = new ObjectOutputStream(byteStream);
400                         out.writeObject(value);
401                         buf.append("java-object\">");
402                         String JavaDoc encodedVal = StringUtils.encodeBase64(byteStream.toByteArray());
403                         buf.append(encodedVal).append("</value>");
404                     }
405                     catch (Exception JavaDoc e) {
406                         e.printStackTrace();
407                     }
408                     finally {
409                         if (out != null) {
410                             try { out.close(); } catch (Exception JavaDoc e) { }
411                         }
412                         if (byteStream != null) {
413                             try { byteStream.close(); } catch (Exception JavaDoc e) { }
414                         }
415                     }
416                 }
417                 buf.append("</property>");
418             }
419             buf.append("</properties>");
420         }
421         return buf.toString();
422     }
423 }
Popular Tags