mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-12-10 15:11:08 +01:00
smack_1_5_1
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@2639 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
aa32e12164
commit
7ae75258be
276 changed files with 40430 additions and 0 deletions
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An ObservableReader is a wrapper on a Reader that notifies to its listeners when
|
||||
* reading character streams.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class ObservableReader extends Reader {
|
||||
|
||||
Reader wrappedReader = null;
|
||||
List listeners = new ArrayList();
|
||||
|
||||
public ObservableReader(Reader wrappedReader) {
|
||||
this.wrappedReader = wrappedReader;
|
||||
}
|
||||
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
int count = wrappedReader.read(cbuf, off, len);
|
||||
if (count > 0) {
|
||||
String str = new String(cbuf, off, count);
|
||||
// Notify that a new string has been read
|
||||
ReaderListener[] readerListeners = null;
|
||||
synchronized (listeners) {
|
||||
readerListeners = new ReaderListener[listeners.size()];
|
||||
listeners.toArray(readerListeners);
|
||||
}
|
||||
for (int i = 0; i < readerListeners.length; i++) {
|
||||
readerListeners[i].read(str);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
wrappedReader.close();
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
return wrappedReader.read();
|
||||
}
|
||||
|
||||
public int read(char cbuf[]) throws IOException {
|
||||
return wrappedReader.read(cbuf);
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
return wrappedReader.skip(n);
|
||||
}
|
||||
|
||||
public boolean ready() throws IOException {
|
||||
return wrappedReader.ready();
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return wrappedReader.markSupported();
|
||||
}
|
||||
|
||||
public void mark(int readAheadLimit) throws IOException {
|
||||
wrappedReader.mark(readAheadLimit);
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
wrappedReader.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reader listener to this reader that will be notified when
|
||||
* new strings are read.
|
||||
*
|
||||
* @param readerListener a reader listener.
|
||||
*/
|
||||
public void addReaderListener(ReaderListener readerListener) {
|
||||
if (readerListener == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (listeners) {
|
||||
if (!listeners.contains(readerListener)) {
|
||||
listeners.add(readerListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a reader listener from this reader.
|
||||
*
|
||||
* @param readerListener a reader listener.
|
||||
*/
|
||||
public void removeReaderListener(ReaderListener readerListener) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(readerListener);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An ObservableWriter is a wrapper on a Writer that notifies to its listeners when
|
||||
* writing to character streams.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class ObservableWriter extends Writer {
|
||||
|
||||
Writer wrappedWriter = null;
|
||||
List listeners = new ArrayList();
|
||||
|
||||
public ObservableWriter(Writer wrappedWriter) {
|
||||
this.wrappedWriter = wrappedWriter;
|
||||
}
|
||||
|
||||
public void write(char cbuf[], int off, int len) throws IOException {
|
||||
wrappedWriter.write(cbuf, off, len);
|
||||
String str = new String(cbuf, off, len);
|
||||
notifyListeners(str);
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
wrappedWriter.flush();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
wrappedWriter.close();
|
||||
}
|
||||
|
||||
public void write(int c) throws IOException {
|
||||
wrappedWriter.write(c);
|
||||
}
|
||||
|
||||
public void write(char cbuf[]) throws IOException {
|
||||
wrappedWriter.write(cbuf);
|
||||
String str = new String(cbuf);
|
||||
notifyListeners(str);
|
||||
}
|
||||
|
||||
public void write(String str) throws IOException {
|
||||
wrappedWriter.write(str);
|
||||
notifyListeners(str);
|
||||
}
|
||||
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
wrappedWriter.write(str, off, len);
|
||||
str = str.substring(off, off + len);
|
||||
notifyListeners(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a new string has been written.
|
||||
*
|
||||
* @param str the written String to notify
|
||||
*/
|
||||
private void notifyListeners(String str) {
|
||||
WriterListener[] writerListeners = null;
|
||||
synchronized (listeners) {
|
||||
writerListeners = new WriterListener[listeners.size()];
|
||||
listeners.toArray(writerListeners);
|
||||
}
|
||||
for (int i = 0; i < writerListeners.length; i++) {
|
||||
writerListeners[i].write(str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a writer listener to this writer that will be notified when
|
||||
* new strings are sent.
|
||||
*
|
||||
* @param writerListener a writer listener.
|
||||
*/
|
||||
public void addWriterListener(WriterListener writerListener) {
|
||||
if (writerListener == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (listeners) {
|
||||
if (!listeners.contains(writerListener)) {
|
||||
listeners.add(writerListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a writer listener from this writer.
|
||||
*
|
||||
* @param writerListener a writer listener.
|
||||
*/
|
||||
public void removeWriterListener(WriterListener writerListener) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(writerListener);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,417 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.jivesoftware.smack.packet.*;
|
||||
import org.jivesoftware.smack.provider.PacketExtensionProvider;
|
||||
import org.jivesoftware.smack.provider.ProviderManager;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* Utility class that helps to parse packets. Any parsing packets method that must be shared
|
||||
* between many clients must be placed in this utility class.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class PacketParserUtils {
|
||||
|
||||
/**
|
||||
* Namespace used to store packet properties.
|
||||
*/
|
||||
private static final String PROPERTIES_NAMESPACE =
|
||||
"http://www.jivesoftware.com/xmlns/xmpp/properties";
|
||||
|
||||
/**
|
||||
* Parses a message packet.
|
||||
*
|
||||
* @param parser the XML parser, positioned at the start of a message packet.
|
||||
* @return a Message packet.
|
||||
* @throws Exception if an exception occurs while parsing the packet.
|
||||
*/
|
||||
public static Packet parseMessage(XmlPullParser parser) throws Exception {
|
||||
Message message = new Message();
|
||||
String id = parser.getAttributeValue("", "id");
|
||||
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id);
|
||||
message.setTo(parser.getAttributeValue("", "to"));
|
||||
message.setFrom(parser.getAttributeValue("", "from"));
|
||||
message.setType(Message.Type.fromString(parser.getAttributeValue("", "type")));
|
||||
|
||||
// Parse sub-elements. We include extra logic to make sure the values
|
||||
// are only read once. This is because it's possible for the names to appear
|
||||
// in arbitrary sub-elements.
|
||||
boolean done = false;
|
||||
String subject = null;
|
||||
String body = null;
|
||||
String thread = null;
|
||||
Map properties = null;
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String elementName = parser.getName();
|
||||
String namespace = parser.getNamespace();
|
||||
if (elementName.equals("subject")) {
|
||||
if (subject == null) {
|
||||
subject = parser.nextText();
|
||||
}
|
||||
}
|
||||
else if (elementName.equals("body")) {
|
||||
if (body == null) {
|
||||
body = parser.nextText();
|
||||
}
|
||||
}
|
||||
else if (elementName.equals("thread")) {
|
||||
if (thread == null) {
|
||||
thread = parser.nextText();
|
||||
}
|
||||
}
|
||||
else if (elementName.equals("error")) {
|
||||
message.setError(parseError(parser));
|
||||
}
|
||||
else if (elementName.equals("properties") &&
|
||||
namespace.equals(PROPERTIES_NAMESPACE))
|
||||
{
|
||||
properties = parseProperties(parser);
|
||||
}
|
||||
// Otherwise, it must be a packet extension.
|
||||
else {
|
||||
message.addExtension(
|
||||
PacketParserUtils.parsePacketExtension(elementName, namespace, parser));
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals("message")) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
message.setSubject(subject);
|
||||
message.setBody(body);
|
||||
message.setThread(thread);
|
||||
// Set packet properties.
|
||||
if (properties != null) {
|
||||
for (Iterator i=properties.keySet().iterator(); i.hasNext(); ) {
|
||||
String name = (String)i.next();
|
||||
message.setProperty(name, properties.get(name));
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a presence packet.
|
||||
*
|
||||
* @param parser the XML parser, positioned at the start of a presence packet.
|
||||
* @return a Presence packet.
|
||||
* @throws Exception if an exception occurs while parsing the packet.
|
||||
*/
|
||||
public static Presence parsePresence(XmlPullParser parser) throws Exception {
|
||||
Presence.Type type = Presence.Type.fromString(parser.getAttributeValue("", "type"));
|
||||
|
||||
Presence presence = new Presence(type);
|
||||
presence.setTo(parser.getAttributeValue("", "to"));
|
||||
presence.setFrom(parser.getAttributeValue("", "from"));
|
||||
String id = parser.getAttributeValue("", "id");
|
||||
presence.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id);
|
||||
|
||||
// Parse sub-elements
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String elementName = parser.getName();
|
||||
String namespace = parser.getNamespace();
|
||||
if (elementName.equals("status")) {
|
||||
presence.setStatus(parser.nextText());
|
||||
}
|
||||
else if (elementName.equals("priority")) {
|
||||
try {
|
||||
int priority = Integer.parseInt(parser.nextText());
|
||||
presence.setPriority(priority);
|
||||
}
|
||||
catch (NumberFormatException nfe) { }
|
||||
catch (IllegalArgumentException iae) {
|
||||
// Presence priority is out of range so assume priority to be zero
|
||||
presence.setPriority(0);
|
||||
}
|
||||
}
|
||||
else if (elementName.equals("show")) {
|
||||
presence.setMode(Presence.Mode.fromString(parser.nextText()));
|
||||
}
|
||||
else if (elementName.equals("error")) {
|
||||
presence.setError(parseError(parser));
|
||||
}
|
||||
else if (elementName.equals("properties") &&
|
||||
namespace.equals(PROPERTIES_NAMESPACE))
|
||||
{
|
||||
Map properties = parseProperties(parser);
|
||||
// Set packet properties.
|
||||
for (Iterator i=properties.keySet().iterator(); i.hasNext(); ) {
|
||||
String name = (String)i.next();
|
||||
presence.setProperty(name, properties.get(name));
|
||||
}
|
||||
}
|
||||
// Otherwise, it must be a packet extension.
|
||||
else {
|
||||
presence.addExtension(
|
||||
PacketParserUtils.parsePacketExtension(elementName, namespace, parser));
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals("presence")) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return presence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a properties sub-packet. If any errors occur while de-serializing Java object
|
||||
* properties, an exception will be printed and not thrown since a thrown
|
||||
* exception will shut down the entire connection. ClassCastExceptions will occur
|
||||
* when both the sender and receiver of the packet don't have identical versions
|
||||
* of the same class.
|
||||
*
|
||||
* @param parser the XML parser, positioned at the start of a properties sub-packet.
|
||||
* @return a map of the properties.
|
||||
* @throws Exception if an error occurs while parsing the properties.
|
||||
*/
|
||||
public static Map parseProperties(XmlPullParser parser) throws Exception {
|
||||
Map properties = new HashMap();
|
||||
while (true) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("property")) {
|
||||
// Parse a property
|
||||
boolean done = false;
|
||||
String name = null;
|
||||
String type = null;
|
||||
String valueText = null;
|
||||
Object value = null;
|
||||
while (!done) {
|
||||
eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String elementName = parser.getName();
|
||||
if (elementName.equals("name")) {
|
||||
name = parser.nextText();
|
||||
}
|
||||
else if (elementName.equals("value")) {
|
||||
type = parser.getAttributeValue("", "type");
|
||||
valueText = parser.nextText();
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals("property")) {
|
||||
if ("integer".equals(type)) {
|
||||
value = new Integer(valueText);
|
||||
}
|
||||
else if ("long".equals(type)) {
|
||||
value = new Long(valueText);
|
||||
}
|
||||
else if ("float".equals(type)) {
|
||||
value = new Float(valueText);
|
||||
}
|
||||
else if ("double".equals(type)) {
|
||||
value = new Double(valueText);
|
||||
}
|
||||
else if ("boolean".equals(type)) {
|
||||
value = new Boolean(valueText);
|
||||
}
|
||||
else if ("string".equals(type)) {
|
||||
value = valueText;
|
||||
}
|
||||
else if ("java-object".equals(type)) {
|
||||
try {
|
||||
byte [] bytes = StringUtils.decodeBase64(valueText);
|
||||
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
value = in.readObject();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (name != null && value != null) {
|
||||
properties.put(name, value);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals("properties")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses error sub-packets.
|
||||
*
|
||||
* @param parser the XML parser.
|
||||
* @return an error sub-packet.
|
||||
* @throws Exception if an exception occurs while parsing the packet.
|
||||
*/
|
||||
public static XMPPError parseError(XmlPullParser parser) throws Exception {
|
||||
String errorCode = "-1";
|
||||
String message = null;
|
||||
for (int i=0; i<parser.getAttributeCount(); i++) {
|
||||
if (parser.getAttributeName(i).equals("code")) {
|
||||
errorCode = parser.getAttributeValue("", "code");
|
||||
}
|
||||
}
|
||||
// Get the error text in a safe way since we are not sure about the error message format
|
||||
try {
|
||||
message = parser.nextText();
|
||||
}
|
||||
catch (XmlPullParserException ex) {}
|
||||
while (true) {
|
||||
if (parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals("error")) {
|
||||
break;
|
||||
}
|
||||
parser.next();
|
||||
}
|
||||
return new XMPPError(Integer.parseInt(errorCode), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a packet extension sub-packet.
|
||||
*
|
||||
* @param elementName the XML element name of the packet extension.
|
||||
* @param namespace the XML namespace of the packet extension.
|
||||
* @param parser the XML parser, positioned at the starting element of the extension.
|
||||
* @return a PacketExtension.
|
||||
* @throws Exception if a parsing error occurs.
|
||||
*/
|
||||
public static PacketExtension parsePacketExtension(String elementName, String namespace, XmlPullParser parser)
|
||||
throws Exception
|
||||
{
|
||||
// See if a provider is registered to handle the extension.
|
||||
Object provider = ProviderManager.getExtensionProvider(elementName, namespace);
|
||||
if (provider != null) {
|
||||
if (provider instanceof PacketExtensionProvider) {
|
||||
return ((PacketExtensionProvider)provider).parseExtension(parser);
|
||||
}
|
||||
else if (provider instanceof Class) {
|
||||
return (PacketExtension)parseWithIntrospection(
|
||||
elementName, (Class)provider, parser);
|
||||
}
|
||||
}
|
||||
// No providers registered, so use a default extension.
|
||||
DefaultPacketExtension extension = new DefaultPacketExtension(elementName, namespace);
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String name = parser.getName();
|
||||
// If an empty element, set the value with the empty string.
|
||||
if (parser.isEmptyElementTag()) {
|
||||
extension.setValue(name,"");
|
||||
}
|
||||
// Otherwise, get the the element text.
|
||||
else {
|
||||
eventType = parser.next();
|
||||
if (eventType == XmlPullParser.TEXT) {
|
||||
String value = parser.getText();
|
||||
extension.setValue(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals(elementName)) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
public static Object parseWithIntrospection(String elementName,
|
||||
Class objectClass, XmlPullParser parser) throws Exception
|
||||
{
|
||||
boolean done = false;
|
||||
Object object = objectClass.newInstance();
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String name = parser.getName();
|
||||
String stringValue = parser.nextText();
|
||||
PropertyDescriptor descriptor = new PropertyDescriptor(name, objectClass);
|
||||
// Load the class type of the property.
|
||||
Class propertyType = descriptor.getPropertyType();
|
||||
// Get the value of the property by converting it from a
|
||||
// String to the correct object type.
|
||||
Object value = decode(propertyType, stringValue);
|
||||
// Set the value of the bean.
|
||||
descriptor.getWriteMethod().invoke(object, new Object[] { value });
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals(elementName)) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a String into an object of the specified type. If the object
|
||||
* type is not supported, null will be returned.
|
||||
*
|
||||
* @param type the type of the property.
|
||||
* @param value the encode String value to decode.
|
||||
* @return the String value decoded into the specified type.
|
||||
*/
|
||||
private static Object decode(Class type, String value) throws Exception {
|
||||
if (type.getName().equals("java.lang.String")) {
|
||||
return value;
|
||||
}
|
||||
if (type.getName().equals("boolean")) {
|
||||
return Boolean.valueOf(value);
|
||||
}
|
||||
if (type.getName().equals("int")) {
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
if (type.getName().equals("long")) {
|
||||
return Long.valueOf(value);
|
||||
}
|
||||
if (type.getName().equals("float")) {
|
||||
return Float.valueOf(value);
|
||||
}
|
||||
if (type.getName().equals("double")) {
|
||||
return Double.valueOf(value);
|
||||
}
|
||||
if (type.getName().equals("java.lang.Class")) {
|
||||
return Class.forName(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
/**
|
||||
* Interface that allows for implementing classes to listen for string reading
|
||||
* events. Listeners are registered with ObservableReader objects.
|
||||
*
|
||||
* @see ObservableReader#addReaderListener
|
||||
* @see ObservableReader#removeReaderListener
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public interface ReaderListener {
|
||||
|
||||
/**
|
||||
* Notification that the Reader has read a new string.
|
||||
*
|
||||
* @param str the read String
|
||||
*/
|
||||
public abstract void read(String str);
|
||||
|
||||
}
|
||||
437
CopyOftrunk/source/org/jivesoftware/smack/util/StringUtils.java
Normal file
437
CopyOftrunk/source/org/jivesoftware/smack/util/StringUtils.java
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A collection of utility methods for String objects.
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
private static final char[] QUOTE_ENCODE = """.toCharArray();
|
||||
private static final char[] AMP_ENCODE = "&".toCharArray();
|
||||
private static final char[] LT_ENCODE = "<".toCharArray();
|
||||
private static final char[] GT_ENCODE = ">".toCharArray();
|
||||
|
||||
/**
|
||||
* Returns the name portion of a XMPP address. For example, for the
|
||||
* address "matt@jivesoftware.com/Smack", "matt" would be returned. If no
|
||||
* username is present in the address, the empty string will be returned.
|
||||
*
|
||||
* @param XMPPAddress the XMPP address.
|
||||
* @return the name portion of the XMPP address.
|
||||
*/
|
||||
public static String parseName(String XMPPAddress) {
|
||||
if (XMPPAddress == null) {
|
||||
return null;
|
||||
}
|
||||
int atIndex = XMPPAddress.indexOf("@");
|
||||
if (atIndex <= 0) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return XMPPAddress.substring(0, atIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server portion of a XMPP address. For example, for the
|
||||
* address "matt@jivesoftware.com/Smack", "jivesoftware.com" would be returned.
|
||||
* If no server is present in the address, the empty string will be returned.
|
||||
*
|
||||
* @param XMPPAddress the XMPP address.
|
||||
* @return the server portion of the XMPP address.
|
||||
*/
|
||||
public static String parseServer(String XMPPAddress) {
|
||||
if (XMPPAddress == null) {
|
||||
return null;
|
||||
}
|
||||
int atIndex = XMPPAddress.indexOf("@");
|
||||
// If the String ends with '@', return the empty string.
|
||||
if (atIndex + 1 > XMPPAddress.length()) {
|
||||
return "";
|
||||
}
|
||||
int slashIndex = XMPPAddress.indexOf("/");
|
||||
if (slashIndex > 0) {
|
||||
return XMPPAddress.substring(atIndex + 1, slashIndex);
|
||||
}
|
||||
else {
|
||||
return XMPPAddress.substring(atIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource portion of a XMPP address. For example, for the
|
||||
* address "matt@jivesoftware.com/Smack", "Smack" would be returned. If no
|
||||
* resource is present in the address, the empty string will be returned.
|
||||
*
|
||||
* @param XMPPAddress the XMPP address.
|
||||
* @return the resource portion of the XMPP address.
|
||||
*/
|
||||
public static String parseResource(String XMPPAddress) {
|
||||
if (XMPPAddress == null) {
|
||||
return null;
|
||||
}
|
||||
int slashIndex = XMPPAddress.indexOf("/");
|
||||
if (slashIndex + 1 > XMPPAddress.length() || slashIndex < 0) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return XMPPAddress.substring(slashIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XMPP address with any resource information removed. For example,
|
||||
* for the address "matt@jivesoftware.com/Smack", "matt@jivesoftware.com" would
|
||||
* be returned.
|
||||
*
|
||||
* @param XMPPAddress the XMPP address.
|
||||
* @return the bare XMPP address without resource information.
|
||||
*/
|
||||
public static String parseBareAddress(String XMPPAddress) {
|
||||
if (XMPPAddress == null) {
|
||||
return null;
|
||||
}
|
||||
int slashIndex = XMPPAddress.indexOf("/");
|
||||
if (slashIndex < 0) {
|
||||
return XMPPAddress;
|
||||
}
|
||||
else if (slashIndex == 0) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return XMPPAddress.substring(0, slashIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes all necessary characters in the String so that it can be used
|
||||
* in an XML doc.
|
||||
*
|
||||
* @param string the string to escape.
|
||||
* @return the string with appropriate characters escaped.
|
||||
*/
|
||||
public static final String escapeForXML(String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
char ch;
|
||||
int i=0;
|
||||
int last=0;
|
||||
char[] input = string.toCharArray();
|
||||
int len = input.length;
|
||||
StringBuffer out = new StringBuffer((int)(len*1.3));
|
||||
for (; i < len; i++) {
|
||||
ch = input[i];
|
||||
if (ch > '>') {
|
||||
continue;
|
||||
}
|
||||
else if (ch == '<') {
|
||||
if (i > last) {
|
||||
out.append(input, last, i - last);
|
||||
}
|
||||
last = i + 1;
|
||||
out.append(LT_ENCODE);
|
||||
}
|
||||
else if (ch == '>') {
|
||||
if (i > last) {
|
||||
out.append(input, last, i - last);
|
||||
}
|
||||
last = i + 1;
|
||||
out.append(GT_ENCODE);
|
||||
}
|
||||
|
||||
else if (ch == '&') {
|
||||
if (i > last) {
|
||||
out.append(input, last, i - last);
|
||||
}
|
||||
// Do nothing if the string is of the form ë (unicode value)
|
||||
if (!(len > i + 5
|
||||
&& input[i + 1] == '#'
|
||||
&& Character.isDigit(input[i + 2])
|
||||
&& Character.isDigit(input[i + 3])
|
||||
&& Character.isDigit(input[i + 4])
|
||||
&& input[i + 5] == ';')) {
|
||||
last = i + 1;
|
||||
out.append(AMP_ENCODE);
|
||||
}
|
||||
}
|
||||
else if (ch == '"') {
|
||||
if (i > last) {
|
||||
out.append(input, last, i - last);
|
||||
}
|
||||
last = i + 1;
|
||||
out.append(QUOTE_ENCODE);
|
||||
}
|
||||
}
|
||||
if (last == 0) {
|
||||
return string;
|
||||
}
|
||||
if (i > last) {
|
||||
out.append(input, last, i - last);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the hash method.
|
||||
*/
|
||||
private static MessageDigest digest = null;
|
||||
|
||||
/**
|
||||
* Hashes a String using the SHA-1 algorithm and returns the result as a
|
||||
* String of hexadecimal numbers. This method is synchronized to avoid
|
||||
* excessive MessageDigest object creation. If calling this method becomes
|
||||
* a bottleneck in your code, you may wish to maintain a pool of
|
||||
* MessageDigest objects instead of using this method.
|
||||
* <p>
|
||||
* A hash is a one-way function -- that is, given an
|
||||
* input, an output is easily computed. However, given the output, the
|
||||
* input is almost impossible to compute. This is useful for passwords
|
||||
* since we can store the hash and a hacker will then have a very hard time
|
||||
* determining the original password.
|
||||
*
|
||||
* @param data the String to compute the hash of.
|
||||
* @return a hashed version of the passed-in String
|
||||
*/
|
||||
public synchronized static final String hash(String data) {
|
||||
if (digest == null) {
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-1");
|
||||
}
|
||||
catch (NoSuchAlgorithmException nsae) {
|
||||
System.err.println("Failed to load the SHA-1 MessageDigest. " +
|
||||
"Jive will be unable to function normally.");
|
||||
}
|
||||
}
|
||||
// Now, compute hash.
|
||||
try {
|
||||
digest.update(data.getBytes("UTF-8"));
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
return encodeHex(digest.digest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns an array of bytes into a String representing each byte as an
|
||||
* unsigned hex number.
|
||||
* <p>
|
||||
* Method by Santeri Paavolainen, Helsinki Finland 1996<br>
|
||||
* (c) Santeri Paavolainen, Helsinki Finland 1996<br>
|
||||
* Distributed under LGPL.
|
||||
*
|
||||
* @param bytes an array of bytes to convert to a hex-string
|
||||
* @return generated hex string
|
||||
*/
|
||||
public static final String encodeHex(byte[] bytes) {
|
||||
StringBuffer buf = new StringBuffer(bytes.length * 2);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bytes.length; i++) {
|
||||
if (((int) bytes[i] & 0xff) < 0x10) {
|
||||
buf.append("0");
|
||||
}
|
||||
buf.append(Long.toString((int) bytes[i] & 0xff, 16));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//* Base64 - a simple base64 encoder and decoder.
|
||||
//*
|
||||
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
|
||||
//*
|
||||
//* This code may be freely used for any purpose, either personal
|
||||
//* or commercial, provided the authors copyright notice remains
|
||||
//* intact.
|
||||
//*********************************************************************
|
||||
|
||||
private static final int fillchar = '=';
|
||||
private static final String cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
+ "0123456789+/";
|
||||
|
||||
/**
|
||||
* Encodes a String as a base64 String.
|
||||
*
|
||||
* @param data a String to encode.
|
||||
* @return a base64 encoded String.
|
||||
*/
|
||||
public static String encodeBase64(String data) {
|
||||
byte [] bytes = null;
|
||||
try {
|
||||
bytes = data.getBytes("ISO-8859-1");
|
||||
}
|
||||
catch (UnsupportedEncodingException uee) {
|
||||
uee.printStackTrace();
|
||||
}
|
||||
return encodeBase64(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte array into a base64 String.
|
||||
*
|
||||
* @param data a byte array to encode.
|
||||
* @return a base64 encode String.
|
||||
*/
|
||||
public static String encodeBase64(byte[] data) {
|
||||
int c;
|
||||
int len = data.length;
|
||||
StringBuffer ret = new StringBuffer(((len / 3) + 1) * 4);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
c = (data[i] >> 2) & 0x3f;
|
||||
ret.append(cvt.charAt(c));
|
||||
c = (data[i] << 4) & 0x3f;
|
||||
if (++i < len)
|
||||
c |= (data[i] >> 4) & 0x0f;
|
||||
|
||||
ret.append(cvt.charAt(c));
|
||||
if (i < len) {
|
||||
c = (data[i] << 2) & 0x3f;
|
||||
if (++i < len)
|
||||
c |= (data[i] >> 6) & 0x03;
|
||||
|
||||
ret.append(cvt.charAt(c));
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
ret.append((char) fillchar);
|
||||
}
|
||||
|
||||
if (i < len) {
|
||||
c = data[i] & 0x3f;
|
||||
ret.append(cvt.charAt(c));
|
||||
}
|
||||
else {
|
||||
ret.append((char) fillchar);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base64 String.
|
||||
*
|
||||
* @param data a base64 encoded String to decode.
|
||||
* @return the decoded String.
|
||||
*/
|
||||
public static byte[] decodeBase64(String data) {
|
||||
byte [] bytes = null;
|
||||
try {
|
||||
bytes = data.getBytes("ISO-8859-1");
|
||||
return decodeBase64(bytes).getBytes("ISO-8859-1");
|
||||
}
|
||||
catch (UnsupportedEncodingException uee) {
|
||||
uee.printStackTrace();
|
||||
}
|
||||
return new byte[] { };
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base64 aray of bytes.
|
||||
*
|
||||
* @param data a base64 encode byte array to decode.
|
||||
* @return the decoded String.
|
||||
*/
|
||||
private static String decodeBase64(byte[] data) {
|
||||
int c, c1;
|
||||
int len = data.length;
|
||||
StringBuffer ret = new StringBuffer((len * 3) / 4);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
c = cvt.indexOf(data[i]);
|
||||
++i;
|
||||
c1 = cvt.indexOf(data[i]);
|
||||
c = ((c << 2) | ((c1 >> 4) & 0x3));
|
||||
ret.append((char) c);
|
||||
if (++i < len) {
|
||||
c = data[i];
|
||||
if (fillchar == c)
|
||||
break;
|
||||
|
||||
c = cvt.indexOf(c);
|
||||
c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
|
||||
ret.append((char) c1);
|
||||
}
|
||||
|
||||
if (++i < len) {
|
||||
c1 = data[i];
|
||||
if (fillchar == c1)
|
||||
break;
|
||||
|
||||
c1 = cvt.indexOf(c1);
|
||||
c = ((c << 6) & 0xc0) | c1;
|
||||
ret.append((char) c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pseudo-random number generator object for use with randomString().
|
||||
* The Random class is not considered to be cryptographically secure, so
|
||||
* only use these random Strings for low to medium security applications.
|
||||
*/
|
||||
private static Random randGen = new Random();
|
||||
|
||||
/**
|
||||
* Array of numbers and letters of mixed case. Numbers appear in the list
|
||||
* twice so that there is a more equal chance that a number will be picked.
|
||||
* We can use the array to get a random number or letter by picking a random
|
||||
* array index.
|
||||
*/
|
||||
private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
|
||||
|
||||
/**
|
||||
* Returns a random String of numbers and letters (lower and upper case)
|
||||
* of the specified length. The method uses the Random class that is
|
||||
* built-in to Java which is suitable for low to medium grade security uses.
|
||||
* This means that the output is only pseudo random, i.e., each number is
|
||||
* mathematically generated so is not truly random.<p>
|
||||
*
|
||||
* The specified length must be at least one. If not, the method will return
|
||||
* null.
|
||||
*
|
||||
* @param length the desired length of the random String to return.
|
||||
* @return a random String of numbers and letters of the specified length.
|
||||
*/
|
||||
public static final String randomString(int length) {
|
||||
if (length < 1) {
|
||||
return null;
|
||||
}
|
||||
// Create a char buffer to put random letters and numbers in.
|
||||
char [] randBuffer = new char[length];
|
||||
for (int i=0; i<randBuffer.length; i++) {
|
||||
randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
|
||||
}
|
||||
return new String(randBuffer);
|
||||
}
|
||||
|
||||
private StringUtils() {
|
||||
// Not instantiable.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2004 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.smack.util;
|
||||
|
||||
/**
|
||||
* Interface that allows for implementing classes to listen for string writing
|
||||
* events. Listeners are registered with ObservableWriter objects.
|
||||
*
|
||||
* @see ObservableWriter#addWriterListener
|
||||
* @see ObservableWriter#removeWriterListener
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public interface WriterListener {
|
||||
|
||||
/**
|
||||
* Notification that the Writer has written a new string.
|
||||
*
|
||||
* @param str the written string
|
||||
*/
|
||||
public abstract void write(String str);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<body>Utility classes.</body>
|
||||
Loading…
Add table
Add a link
Reference in a new issue