1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack.packet;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringUtils;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.*;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Represents XMPP message packets. A message can be one of several types:
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <ul>
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *      <li>Message.Type.NORMAL -- (Default) a normal text message used in email like interface.
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *      <li>Message.Type.CHAT -- a typically short text message used in line-by-line chat interfaces.
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *      <li>Message.Type.GROUP_CHAT -- a chat message sent to a groupchat server for group chats.
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *      <li>Message.Type.HEADLINE -- a text message to be displayed in scrolling marquee displays.
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *      <li>Message.Type.ERROR -- indicates a messaging error.
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * </ul>
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * For each message type, different message fields are typically used as follows:
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p>
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <table border="1">
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td>&nbsp;</td><td colspan="5"><b>Message type</b></td></tr>
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td><i>Field</i></td><td><b>Normal</b></td><td><b>Chat</b></td><td><b>Group Chat</b></td><td><b>Headline</b></td><td><b>XMPPError</b></td></tr>
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td><i>subject</i></td> <td>SHOULD</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td></tr>
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td><i>thread</i></td>  <td>OPTIONAL</td><td>SHOULD</td><td>OPTIONAL</td><td>OPTIONAL</td><td>SHOULD NOT</td></tr>
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td><i>body</i></td>    <td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD NOT</td></tr>
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <tr><td><i>error</i></td>   <td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST</td></tr>
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * </table>
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Matt Tucker
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class Message extends Packet {
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Type type = Type.normal;
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String thread = null;
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String language;
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final Set<Subject> subjects = new HashSet<Subject>();
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final Set<Body> bodies = new HashSet<Body>();
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new, "normal" message.
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Message() {
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new "normal" message to the specified recipient.
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param to the recipient of the message.
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Message(String to) {
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setTo(to);
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new message of the specified type to a recipient.
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param to the user to send the message to.
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param type the message type.
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Message(String to, Type type) {
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setTo(to);
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.type = type;
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the type of the message. If no type has been set this method will return {@link
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * org.jivesoftware.smack.packet.Message.Type#normal}.
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the type of the message.
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Type getType() {
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return type;
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the type of the message.
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param type the type of the message.
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws IllegalArgumentException if null is passed in as the type
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setType(Type type) {
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (type == null) {
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalArgumentException("Type cannot be null.");
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.type = type;
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the default subject of the message, or null if the subject has not been set.
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The subject is a short description of message contents.
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p>
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The default subject of a message is the subject that corresponds to the message's language.
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * (see {@link #getLanguage()}) or if no language is set to the applications default
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * language (see {@link Packet#getDefaultLanguage()}).
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the subject of the message.
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getSubject() {
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return getSubject(null);
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the subject corresponding to the language. If the language is null, the method result
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * will be the same as {@link #getSubject()}. Null will be returned if the language does not have
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * a corresponding subject.
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the subject to return.
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the subject related to the passed in language.
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getSubject(String language) {
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Subject subject = getMessageSubject(language);
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return subject == null ? null : subject.subject;
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Subject getMessageSubject(String language) {
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Subject subject : subjects) {
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language.equals(subject.language)) {
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return subject;
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return null;
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns a set of all subjects in this Message, including the default message subject accessible
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * from {@link #getSubject()}.
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return a collection of all subjects in this message.
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Collection<Subject> getSubjects() {
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return Collections.unmodifiableCollection(subjects);
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the subject of the message. The subject is a short description of
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * message contents.
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param subject the subject of the message.
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setSubject(String subject) {
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (subject == null) {
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            removeSubject(""); // use empty string because #removeSubject(null) is ambiguous
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        addSubject(null, subject);
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds a subject with a corresponding language.
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the subject being added.
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param subject the subject being added to the message.
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the new {@link org.jivesoftware.smack.packet.Message.Subject}
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws NullPointerException if the subject is null, a null pointer exception is thrown
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Subject addSubject(String language, String subject) {
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Subject messageSubject = new Subject(language, subject);
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        subjects.add(messageSubject);
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return messageSubject;
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the subject with the given language from the message.
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the subject which is to be removed
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if a subject was removed and false if it was not.
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean removeSubject(String language) {
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Subject subject : subjects) {
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language.equals(subject.language)) {
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return subjects.remove(subject);
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the subject from the message and returns true if the subject was removed.
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param subject the subject being removed from the message.
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if the subject was successfully removed and false if it was not.
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean removeSubject(Subject subject) {
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return subjects.remove(subject);
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns all the languages being used for the subjects, not including the default subject.
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the languages being used for the subjects.
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Collection<String> getSubjectLanguages() {
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Subject defaultSubject = getMessageSubject(null);
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<String> languages = new ArrayList<String>();
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Subject subject : subjects) {
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!subject.equals(defaultSubject)) {
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                languages.add(subject.language);
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return Collections.unmodifiableCollection(languages);
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the default body of the message, or null if the body has not been set. The body
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * is the main message contents.
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p>
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The default body of a message is the body that corresponds to the message's language.
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * (see {@link #getLanguage()}) or if no language is set to the applications default
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * language (see {@link Packet#getDefaultLanguage()}).
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the body of the message.
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getBody() {
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return getBody(null);
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the body corresponding to the language. If the language is null, the method result
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * will be the same as {@link #getBody()}. Null will be returned if the language does not have
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * a corresponding body.
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the body to return.
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the body related to the passed in language.
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getBody(String language) {
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Body body = getMessageBody(language);
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return body == null ? null : body.message;
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Body getMessageBody(String language) {
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Body body : bodies) {
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language.equals(body.language)) {
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return body;
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return null;
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns a set of all bodies in this Message, including the default message body accessible
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * from {@link #getBody()}.
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return a collection of all bodies in this Message.
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Collection<Body> getBodies() {
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return Collections.unmodifiableCollection(bodies);
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the body of the message. The body is the main message contents.
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param body the body of the message.
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setBody(String body) {
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (body == null) {
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            removeBody(""); // use empty string because #removeBody(null) is ambiguous
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        addBody(null, body);
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds a body with a corresponding language.
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the body being added.
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param body the body being added to the message.
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the new {@link org.jivesoftware.smack.packet.Message.Body}
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws NullPointerException if the body is null, a null pointer exception is thrown
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Body addBody(String language, String body) {
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Body messageBody = new Body(language, body);
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        bodies.add(messageBody);
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return messageBody;
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the body with the given language from the message.
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the language of the body which is to be removed
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if a body was removed and false if it was not.
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean removeBody(String language) {
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = determineLanguage(language);
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Body body : bodies) {
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language.equals(body.language)) {
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return bodies.remove(body);
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the body from the message and returns true if the body was removed.
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param body the body being removed from the message.
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if the body was successfully removed and false if it was not.
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean removeBody(Body body) {
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return bodies.remove(body);
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns all the languages being used for the bodies, not including the default body.
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the languages being used for the bodies.
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Collection<String> getBodyLanguages() {
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Body defaultBody = getMessageBody(null);
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<String> languages = new ArrayList<String>();
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Body body : bodies) {
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!body.equals(defaultBody)) {
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                languages.add(body.language);
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return Collections.unmodifiableCollection(languages);
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the thread id of the message, which is a unique identifier for a sequence
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * of "chat" messages. If no thread id is set, <tt>null</tt> will be returned.
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the thread id of the message, or <tt>null</tt> if it doesn't exist.
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getThread() {
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return thread;
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the thread id of the message, which is a unique identifier for a sequence
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * of "chat" messages.
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param thread the thread id of the message.
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setThread(String thread) {
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.thread = thread;
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the xml:lang of this Message.
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the xml:lang of this Message.
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getLanguage() {
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return language;
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the xml:lang of this Message.
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param language the xml:lang of this Message.
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @since 3.0.2
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setLanguage(String language) {
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.language = language;
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String determineLanguage(String language) {
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // empty string is passed by #setSubject() and #setBody() and is the same as null
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        language = "".equals(language) ? null : language;
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // if given language is null check if message language is set
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (language == null && this.language != null) {
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return this.language;
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        else if (language == null) {
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return getDefaultLanguage();
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        else {
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return language;
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String toXML() {
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        StringBuilder buf = new StringBuilder();
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append("<message");
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (getXmlns() != null) {
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" xmlns=\"").append(getXmlns()).append("\"");
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (language != null) {
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" xml:lang=\"").append(getLanguage()).append("\"");
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (getPacketID() != null) {
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" id=\"").append(getPacketID()).append("\"");
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (getTo() != null) {
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" to=\"").append(StringUtils.escapeForXML(getTo())).append("\"");
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (getFrom() != null) {
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" from=\"").append(StringUtils.escapeForXML(getFrom())).append("\"");
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (type != Type.normal) {
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" type=\"").append(type).append("\"");
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append(">");
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add the subject in the default language
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Subject defaultSubject = getMessageSubject(null);
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (defaultSubject != null) {
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<subject>").append(StringUtils.escapeForXML(defaultSubject.subject)).append("</subject>");
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add the subject in other languages
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Subject subject : getSubjects()) {
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Skip the default language
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if(subject.equals(defaultSubject))
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                continue;
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<subject xml:lang=\"").append(subject.language).append("\">");
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(StringUtils.escapeForXML(subject.subject));
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("</subject>");
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add the body in the default language
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Body defaultBody = getMessageBody(null);
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (defaultBody != null) {
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<body>").append(StringUtils.escapeForXML(defaultBody.message)).append("</body>");
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add the bodies in other languages
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Body body : getBodies()) {
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Skip the default language
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if(body.equals(defaultBody))
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                continue;
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<body xml:lang=\"").append(body.getLanguage()).append("\">");
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(StringUtils.escapeForXML(body.getMessage()));
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("</body>");
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (thread != null) {
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<thread>").append(thread).append("</thread>");
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Append the error subpacket if the message type is an error.
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (type == Type.error) {
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            XMPPError error = getError();
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (error != null) {
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buf.append(error.toXML());
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add packet extensions, if any are defined.
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append(getExtensionsXML());
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append("</message>");
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return buf.toString();
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean equals(Object o) {
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (this == o) return true;
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (o == null || getClass() != o.getClass()) return false;
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Message message = (Message) o;
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if(!super.equals(message)) { return false; }
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (bodies.size() != message.bodies.size() || !bodies.containsAll(message.bodies)) {
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (language != null ? !language.equals(message.language) : message.language != null) {
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (subjects.size() != message.subjects.size() || !subjects.containsAll(message.subjects)) {
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (thread != null ? !thread.equals(message.thread) : message.thread != null) {
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return type == message.type;
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public int hashCode() {
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        int result;
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = (type != null ? type.hashCode() : 0);
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 31 * result + subjects.hashCode();
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 31 * result + (thread != null ? thread.hashCode() : 0);
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 31 * result + (language != null ? language.hashCode() : 0);
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 31 * result + bodies.hashCode();
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return result;
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Represents a message subject, its language and the content of the subject.
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static class Subject {
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String subject;
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String language;
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private Subject(String language, String subject) {
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language == null) {
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new NullPointerException("Language cannot be null.");
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (subject == null) {
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new NullPointerException("Subject cannot be null.");
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.language = language;
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.subject = subject;
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the language of this message subject.
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the language of this message subject.
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getLanguage() {
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return language;
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the subject content.
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the content of the subject.
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getSubject() {
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return subject;
542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int hashCode() {
546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            final int prime = 31;
547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int result = 1;
548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + this.language.hashCode();
549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + this.subject.hashCode();
550d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return result;
551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public boolean equals(Object obj) {
554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (this == obj) {
555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == null) {
558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (getClass() != obj.getClass()) {
561d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Subject other = (Subject) obj;
564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // simplified comparison because language and subject are always set
565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return this.language.equals(other.language) && this.subject.equals(other.subject);
566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Represents a message body, its language and the content of the message.
572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static class Body {
574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String message;
576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String language;
577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private Body(String language, String message) {
579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (language == null) {
580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new NullPointerException("Language cannot be null.");
581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (message == null) {
583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new NullPointerException("Message cannot be null.");
584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.language = language;
586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.message = message;
587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
588d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the language of this message body.
591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the language of this message body.
593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getLanguage() {
595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return language;
596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the message content.
600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the content of the message.
602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getMessage() {
604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return message;
605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int hashCode() {
608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            final int prime = 31;
609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int result = 1;
610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + this.language.hashCode();
611d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + this.message.hashCode();
612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return result;
613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public boolean equals(Object obj) {
616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (this == obj) {
617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == null) {
620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (getClass() != obj.getClass()) {
623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Body other = (Body) obj;
626d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // simplified comparison because language and message are always set
627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return this.language.equals(other.language) && this.message.equals(other.message);
628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Represents the type of a message.
634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public enum Type {
636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * (Default) a normal text message used in email like interface.
639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        normal,
641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Typically short text message used in line-by-line chat interfaces.
644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        chat,
646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Chat message sent to a groupchat server for group chats.
649d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        groupchat,
651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Text message to be displayed in scrolling marquee displays.
654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        headline,
656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * indicates a messaging error.
659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
660d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        error;
661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public static Type fromString(String name) {
663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return Type.valueOf(name);
665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Exception e) {
667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return normal;
668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
673