Initial check-in.

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@1924 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Matt Tucker 2003-05-08 15:53:40 +00:00 committed by mtucker
parent f5e167e067
commit cdd78ecbe6
5 changed files with 606 additions and 0 deletions

View File

@ -0,0 +1,156 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
* ====================================================================
* The Jive Software License (based on Apache Software License, Version 1.1)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* Jive Software (http://www.jivesoftware.com)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Smack" and "Jive Software" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact webmaster@jivesoftware.com.
*
* 5. Products derived from this software may not be called "Smack",
* nor may "Smack" appear in their name, without prior written
* permission of Jive Software.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
package org.jivesoftware.smack.packet;
import java.util.*;
/**
* Default implementation of the PacketExtension interface. Unless a PacketExtensionProvider
* is registered with {@link org.jivesoftware.smack.provider.ProviderManager ProviderManager},
* instances of this class will be returned when getting packet extensions.<p>
*
* This class provides a very simple representation of an XML sub-document. Each element
* is a key in a Map with its CDATA being the value. For example, given the following
* XML sub-document:
*
* <pre>
* &lt;foo xmlns="http://bar.com"&gt;
* &lt;color&gt;blue&lt;/color&gt;
* &lt;food&gt;pizza&lt;/food&gt;
* &lt;/foo&gt;</pre>
*
* In this case, getValue("color") would return "blue", and getValue("food") would
* return "pizza". This parsing mechanism mechanism is very simplistic and will not work
* as desired in all cases (for example, if some of the elements have attributes. In those
* cases, a custom PacketExtensionProvider should be used.
*
* @author Matt Tucker
*/
public class DefaultPacketExtension implements PacketExtension {
private String elementName;
private String namespace;
private Map map;
/**
* Creates a new generic packet extension.
*
* @param elementName the name of the element of the XML sub-document.
* @param namespace the namespace of the element.
*/
public DefaultPacketExtension(String elementName, String namespace) {
this.elementName = elementName;
this.namespace = namespace;
}
/**
* Returns the XML element name of the extension sub-packet root element.
*
* @return the XML element name of the packet extension.
*/
public String getElementName() {
return elementName;
}
/**
* Returns the XML namespace of the extension sub-packet root element.
*
* @return the XML namespace of the packet extension.
*/
public String getNamespace() {
return namespace;
}
public String toXML() {
return null;
}
/**
* Returns an Iterator for the names that can be used to get
* values of the packet extension.
*
* @return an Iterator for the names.
*/
public synchronized Iterator getNames() {
if (map == null) {
Collections.EMPTY_LIST.iterator();
}
return Collections.unmodifiableMap(new HashMap(map)).keySet().iterator();
}
/**
* Returns a packet extension value given a name.
*
* @param name the name.
* @return the value.
*/
public synchronized String getValue(String name) {
if (map == null) {
return null;
}
return (String)map.get(name);
}
/**
* Sets a packet extension value using the given name.
*
* @param name the name.
* @param value the value.
*/
public synchronized void setValue(String name, String value) {
if (map == null) {
map = new HashMap();
}
map.put(name, value);
}
}

View File

@ -0,0 +1,14 @@
package org.jivesoftware.smack.packet;
/**
*
* @author Matt Tucker
*/
public interface PacketExtension {
public String getElementName();
public String getNamespace();
public String toXML();
}

View File

@ -0,0 +1,79 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
* ====================================================================
* The Jive Software License (based on Apache Software License, Version 1.1)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* Jive Software (http://www.jivesoftware.com)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Smack" and "Jive Software" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact webmaster@jivesoftware.com.
*
* 5. Products derived from this software may not be called "Smack",
* nor may "Smack" appear in their name, without prior written
* permission of Jive Software.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.IQ;
import org.xmlpull.v1.XmlPullParser;
/**
* An interface for parsing custom IQ packets. Each IQProvider must be registered with
* the ProviderManager class for it to be used. Every implementation of this
* interface <b>must</b> have a public, no-argument constructor.
*
* @author Matt Tucker
*/
public interface IQProvider {
/**
* Parse the IQ sub-document and create an IQ instance. Each IQ must have a single
* sub-element At
* the beginning of the method call, the xml parser will be positioned directly
* after the opening &lt;query&gt; tag of the IQ packet. At the end of the method call,
* the parser <b>must</b> be positioned directly after the closing &lt;query/&gt; tag.
*
* @param parser an XML parser.
* @return a new IQ instance.
* @throws Exception if an error occurs parsing the XML.
*/
public IQ parseIQ(XmlPullParser parser) throws Exception;
}

View File

@ -0,0 +1,78 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
* ====================================================================
* The Jive Software License (based on Apache Software License, Version 1.1)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* Jive Software (http://www.jivesoftware.com)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Smack" and "Jive Software" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact webmaster@jivesoftware.com.
*
* 5. Products derived from this software may not be called "Smack",
* nor may "Smack" appear in their name, without prior written
* permission of Jive Software.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.xmlpull.v1.XmlPullParser;
/**
* An interface for parsing custom packets extensions. Each PacketExtensionProvider must
* be registered with the ProviderManager class for it to be used. Every implementation
* of this interface <b>must</b> have a public, no-argument constructor.
*
* @author Matt Tucker
*/
public interface PacketExtensionProvider {
/**
* Parse an extension sub-packet and create a PacketExtension instance. At
* the beginning of the method call, the xml parser will be positioned on the
* opening element of the packet extension. At the end of the method call, the
* parser <b>must</b> be positioned on the closing element of the packet extension.
*
* @param parser an XML parser.
* @return a new IQ instance.
* @throws java.lang.Exception if an error occurs parsing the XML.
*/
public PacketExtension parseExtensions(XmlPullParser parser) throws Exception;
}

View File

@ -0,0 +1,279 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
* ====================================================================
* The Jive Software License (based on Apache Software License, Version 1.1)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* Jive Software (http://www.jivesoftware.com)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Smack" and "Jive Software" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact webmaster@jivesoftware.com.
*
* 5. Products derived from this software may not be called "Smack",
* nor may "Smack" appear in their name, without prior written
* permission of Jive Software.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.PacketExtension;
import org.xmlpull.v1.*;
import java.util.*;
import java.net.URL;
/**
* Manages providers for parsing custom XML sub-documents of XMPP packets. Two types of
* providers exist:<ul>
* <li>IQProvider -- parses IQ requests into Java objects.
* <li>PacketExtension -- parses XML sub-documents attached to packets into
* PacketExtension instances.</ul>
*
* <b>IQProvider</b><p>
*
* By default, Smack only knows how to process IQ packets with query sub-packets that
* are in a few namespaces:<ul>
* <li>jabber:iq:auth
* <li>jabber:iq:roster
* <li>jabber:iq:register</ul>
*
* Because many more IQ types are part of XMPP and its extensions, a pluggable IQ parsing
* mechanism is provided. IQ providers are registered by creating a smack.providers file
* in the WEB-INF directory of your JAR file. The file is an XML document that contains
* one or more iqProvider entries, as in the following example:
*
* <pre>
* &lt;?xml version="1.0"?&gt;
* &lt;smackProviders&gt;
* &lt;iqProvider&gt;
* &lt;elementName&gt;query&lt;/elementName&gt;
* &lt;namespace&gt;jabber:iq:time&lt;/namespace&gt;
* &lt;className&gt;org.jivesoftware.smack.packet.Time&lt/className&gt;
* &lt;/iqProvider&gt;
* &lt;/smackProviders&gt;</pre>
*
* Each IQ provider is associated with an element name and a namespace. If multiple provider entries attempt to
* register to handle the same namespace, the first entry loaded from the classpath will
* take precedence. The IQ provider class can either implement the IQProvider interface,
* or extend the IQ class. In the former case, each IQProvider is responsible for parsing
* the raw XML stream to create an IQ instance. In the latter case, bean introspection is
* used to try to automatically set properties of the IQ instance using the values found
* in the IQ packet XML. For example, an XMPP time packet resembles the following:
* <pre>
* &lt;iq type='get' to='joe@example.com' from='mary@example.com' id='time_1'&gt;
* &lt;query xmlns='jabber:iq:time'&gt;
* &lt;utc&gt;20020910T17:58:35&lt;/utc&gt;
* &lt;tz&gt;MDT&lt;/tz&gt;
* &lt;display&gt;Tue Sep 10 12:58:35 2002&lt;/display&gt;
* &lt;/query&gt;
* &lt;/iq&gt;</pre>
*
* In order for this packet to be automatically mapped to the Time object listed in the
* providers file above, it must have the methods setUtc(String), setTz(String), and
* setDisplay(tz). The introspection service will automatically try to convert the String
* value from the XML into a boolean, int, long, float, double, or Class depending on the
* type the IQ instance expects.<p>
*
* A pluggable system for the &lt;x&gt; portion of packets also exists. Each x provider
* is registered with a name space in the smack.providers file as in the following example:
*
* <pre>
* &lt;?xml version="1.0"?&gt;
* &lt;smackProviders&gt;
* &lt;xProvider namespace="jabber:iq:event"
* className="org.jivesoftware.smack.packet.MessageEvent"/&gt;
* &lt;/smackProviders&gt;</pre>
*
* If multiple provider entries attempt to register to handle the same namespace, the
* first entry loaded from the classpath will take precedence. Whenever an &lt;x&gt; element
* is found in a packet, parsing will be passed to the correct provider. Each provider
* can either implement the XProvider or be a standard Java Bean. In the former case,
* each XProvider is responsible for parsing the raw XML stream to contruct an object.
* In the latter case, bean introspection is used to try to automatically set the
* properties of the class using the values in the x sub-element. When a XProvider is
* not registered for a namespace, Smack will store all top-level elements of the sub-packet
* in a Map and attach it to the packet.
*
* @author Matt Tucker
*/
public class ProviderManager {
private static Map extensionProviders = new Hashtable();
private static Map iqProviders = new Hashtable();
static {
// Load IQ processing providers.
try {
Enumeration enum = ProviderManager.class.getClassLoader().getResources(
"WEB-INF/smack.providers");
while (enum.hasMoreElements()) {
URL url = (URL)enum.nextElement();
java.io.InputStream providerStream = null;
try {
providerStream = url.openStream();
XmlPullParser parser = getParserInstance();
parser.setInput(providerStream, "UTF-8");
int eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("iqProvider")) {
parser.next();
String elementName = parser.nextText();
parser.next();
String namespace = parser.nextText();
parser.next();
String className = parser.nextText();
parser.next();
// Only add the provider for the namespace if one isn't
// already registered.
String key = getProviderKey(elementName, namespace);
if (!iqProviders.containsKey(key)) {
// Attempt to load the provider class and then create
// a new instance if it's an IQProvider. Otherwise, if it's
// an IQ class, add the class object itself, then we'll use
// reflection later to create instances of the class.
try {
// Add the provider to the map.
Class provider = Class.forName(className);
if (IQProvider.class.isAssignableFrom(provider)) {
iqProviders.put(key, provider.newInstance());
}
else if (IQ.class.isAssignableFrom(provider)) {
iqProviders.put(key, provider);
}
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
}
else if (parser.getName().equals("extensionProvider")) {
parser.next();
String elementName = parser.nextText();
parser.next();
String namespace = parser.nextText();
parser.next();
String className = parser.nextText();
parser.next();
// Only add the provider for the namespace if one isn't
// already registered.
String key = getProviderKey(elementName, namespace);
if (!extensionProviders.containsKey(key)) {
// Attempt to load the provider class and then create
// a new instance if it's a Provider. Otherwise, if it's
// a PacketExtension, add the class object itself and
// then we'll use reflection later to create instances
// of the class.
try {
// Add the provider to the map.
Class provider = Class.forName(className);
if (PacketExtensionProvider.class.isAssignableFrom(provider)) {
extensionProviders.put(key, provider.newInstance());
}
else if (PacketExtension.class.isAssignableFrom(provider)) {
extensionProviders.put(key, provider);
}
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
}
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
}
finally {
try { providerStream.close(); }
catch (Exception e) { }
}
}
}
catch (Exception e) { }
}
public synchronized static Object getIQProvider(String elementName, String namespace) {
String key = getProviderKey(elementName, namespace);
return iqProviders.get(key);
}
public synchronized static Object getExtensionProvider(String elementName, String namespace) {
String key = getProviderKey(elementName, namespace);
return extensionProviders.get(key);
}
private static String getProviderKey(String elementName, String nameSpace) {
StringBuffer buf = new StringBuffer();
buf.append("<").append(elementName).append("/><").append(nameSpace).append("/>");
return buf.toString();
}
/**
* Returns an XML parser instance.
*
* @return an XML parser instance.
*/
private static XmlPullParser getParserInstance() {
XmlPullParser parser = null;
try {
final String defaultProviderName = "org.xmlpull.mxp1.MXParserFactory";
XmlPullParserFactory factory = null;
try {
// Attempt to load a factory implementation using a system property
// and a classloader context.
factory = XmlPullParserFactory.newInstance(
System.getProperty(XmlPullParserFactory.PROPERTY_NAME),
Thread.currentThread().getContextClassLoader().getClass());
}
catch (Exception e) {
if (factory == null) {
// Loading failed. Therefore, use the hardcoded default.
factory = XmlPullParserFactory.newInstance(defaultProviderName, null);
}
}
factory.setNamespaceAware(true);
parser = factory.newPullParser();
}
catch (XmlPullParserException xppe) {
xppe.printStackTrace();
}
return parser;
}
}