/** * * Copyright 2003-2007 Jive Software. * * 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.packet; import java.util.List; import java.util.Locale; import javax.xml.namespace.QName; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.util.EqualsUtil; import org.jivesoftware.smack.util.HashCode; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; /** * Represents XMPP message packets. A message can be one of several types: * *
Message type | |||||
Field | Normal | Chat | Group Chat | Headline | XMPPError |
subject | SHOULD | SHOULD NOT | SHOULD NOT | SHOULD NOT | SHOULD NOT |
thread | OPTIONAL | SHOULD | OPTIONAL | OPTIONAL | SHOULD NOT |
body | SHOULD | SHOULD | SHOULD | SHOULD | SHOULD NOT |
error | MUST NOT | MUST NOT | MUST NOT | MUST NOT | MUST |
* This does not perform a deep clone, as extension elements are shared between the new and old * instance. *
* * @param other TODO javadoc me please */ public Message(Message other) { super(other); this.type = other.type; } @Override public Type getType() { if (type == null) { return Type.normal; } return type; } /** * Sets the type of the message. * * @param type the type of the message. * @deprecated use {@link StanzaBuilder} instead. */ @Deprecated // TODO: Remove in Smack 4.5. public void setType(Type type) { this.type = type; } /** * Sets the subject of the message. The subject is a short description of * message contents. * * @param subject the subject of the message. * @deprecated use {@link StanzaBuilder} instead. */ @Deprecated // TODO: Remove when stanza builder is ready. public void setSubject(String subject) { if (subject == null) { removeSubject(""); // use empty string because #removeSubject(null) is ambiguous return; } addSubject(null, subject); } /** * Adds a subject with a corresponding language. * * @param language the language of the subject being added. * @param subject the subject being added to the message. * @return the new {@link org.jivesoftware.smack.packet.Message.Subject} * @throws NullPointerException if the subject is null, a null pointer exception is thrown */ @Deprecated // TODO: Remove when stanza builder is ready. public Subject addSubject(String language, String subject) { language = Stanza.determineLanguage(this, language); List* This does not perform a deep clone, as extension elements are shared between the new and old * instance. *
* @return a clone of this message. * @deprecated use {@link #asBuilder()} instead. */ // TODO: Remove in Smack 4.5. @Deprecated @Override public Message clone() { return new Message(this); } /** * Represents a message subject, its language and the content of the subject. */ public static final class Subject implements ExtensionElement { public static final String ELEMENT = "subject"; public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE; public static final QName QNAME = new QName(NAMESPACE, ELEMENT); private final String subject; private final String language; public Subject(String language, String subject) { if (subject == null) { throw new NullPointerException("Subject cannot be null."); } this.language = language; this.subject = subject; } @Override public String getLanguage() { return language; } /** * Returns the subject content. * * @return the content of the subject. */ public String getSubject() { return subject; } private final HashCode.Cache hashCodeCache = new HashCode.Cache(); @Override public int hashCode() { return hashCodeCache.getHashCode(c -> c.append(language) .append(subject) ); } @Override public boolean equals(Object obj) { return EqualsUtil.equals(this, obj, (e, o) -> e.append(language, o.language) .append(subject, o.subject) ); } @Override public String getElementName() { return ELEMENT; } @Override public String getNamespace() { return NAMESPACE; } @Override public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace); xml.rightAngleBracket(); xml.escape(subject); xml.closeElement(getElementName()); return xml; } } /** * Represents a message body, its language and the content of the message. */ public static final class Body implements ExtensionElement { public static final String ELEMENT = "body"; public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE; public static final QName QNAME = new QName(NAMESPACE, ELEMENT); enum BodyElementNamespace { client(StreamOpen.CLIENT_NAMESPACE), server(StreamOpen.SERVER_NAMESPACE), ; private final String xmlNamespace; BodyElementNamespace(String xmlNamespace) { this.xmlNamespace = xmlNamespace; } public String getNamespace() { return xmlNamespace; } } private final String message; private final String language; private final BodyElementNamespace namespace; public Body(String language, String message) { this(language, message, BodyElementNamespace.client); } public Body(String language, String message, BodyElementNamespace namespace) { if (message == null) { throw new NullPointerException("Message cannot be null."); } this.language = language; this.message = message; this.namespace = Objects.requireNonNull(namespace); } @Override public String getLanguage() { return language; } /** * Returns the message content. * * @return the content of the message. */ public String getMessage() { return message; } private final HashCode.Cache hashCodeCache = new HashCode.Cache(); @Override public int hashCode() { return hashCodeCache.getHashCode(c -> c.append(language) .append(message) ); } @Override public boolean equals(Object obj) { return EqualsUtil.equals(this, obj, (e, o) -> e.append(language, o.language) .append(message, o.message) ); } @Override public String getElementName() { return ELEMENT; } @Override public String getNamespace() { return namespace.xmlNamespace; } @Override public XmlStringBuilder toXML(XmlEnvironment enclosingXmlEnvironment) { XmlStringBuilder xml = new XmlStringBuilder(this, enclosingXmlEnvironment); xml.rightAngleBracket(); xml.escape(message); xml.closeElement(getElementName()); return xml; } } @SuppressWarnings("JavaLangClash") public static class Thread implements ExtensionElement { public static final String ELEMENT = "thread"; public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE; public static final QName QNAME = new QName(NAMESPACE, ELEMENT); public static final String PARENT_ATTRIBUTE_NAME = "parent"; private final String thread; private final String parent; public Thread(String thread) { this(thread, null); } public Thread(String thread, String parent) { this.thread = StringUtils.requireNotNullNorEmpty(thread, "thread must not be null nor empty"); this.parent = StringUtils.requireNullOrNotEmpty(parent, "parent must be null or not empty"); } public String getThread() { return thread; } public String getParent() { return parent; } @Override public String getElementName() { return ELEMENT; } @Override public String getNamespace() { return NAMESPACE; } @Override public QName getQName() { return QNAME; } @Override public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment); xml.optAttribute(PARENT_ATTRIBUTE_NAME, parent); xml.rightAngleBracket(); xml.escape(thread); xml.closeElement(this); return xml; } } /** * Represents the type of a message. */ public enum Type { /** * (Default) a normal text message used in email like interface. */ normal, /** * Typically short text message used in line-by-line chat interfaces. */ chat, /** * Chat message sent to a groupchat server for group chats. */ groupchat, /** * Text message to be displayed in scrolling marquee displays. */ headline, /** * indicates a messaging error. */ error; /** * Converts a String into the corresponding types. Valid String values that can be converted * to types are: "normal", "chat", "groupchat", "headline" and "error". * * @param string the String value to covert. * @return the corresponding Type. * @throws IllegalArgumentException when not able to parse the string parameter * @throws NullPointerException if the string is null */ public static Type fromString(String string) { return Type.valueOf(string.toLowerCase(Locale.US)); } } }