View Javadoc

1   /**
2    *
3    * Copyright 2003-2006 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package javax.mail;
19  
20  import java.io.Serializable;
21  import java.util.Hashtable;
22  import java.util.Iterator;
23  import java.util.LinkedList;
24  import java.util.List;
25  
26  /**
27   * Representation of flags that may be associated with a message.
28   * Flags can either be system flags, defined by the {@link Flags.Flag Flag} inner class,
29   * or user-defined flags defined by a String. The system flags represent those expected
30   * to be provided by most folder systems; user-defined flags allow for additional flags
31   * on a per-provider basis.
32   * <p/>
33   * This class is Serializable but compatibility is not guaranteed across releases.
34   *
35   * @version $Rev: 421852 $ $Date: 2006-07-14 03:02:19 -0700 (Fri, 14 Jul 2006) $
36   */
37  public class Flags implements Cloneable, Serializable {
38      public static final class Flag {
39          /**
40           * Flag that indicates that the message has been replied to; has a bit value of 1.
41           */
42          public static final Flag ANSWERED = new Flag(1);
43          /**
44           * Flag that indicates that the message has been marked for deletion and
45           * should be removed on a subsequent expunge operation; has a bit value of 2.
46           */
47          public static final Flag DELETED = new Flag(2);
48          /**
49           * Flag that indicates that the message is a draft; has a bit value of 4.
50           */
51          public static final Flag DRAFT = new Flag(4);
52          /**
53           * Flag that indicates that the message has been flagged; has a bit value of 8.
54           */
55          public static final Flag FLAGGED = new Flag(8);
56          /**
57           * Flag that indicates that the message has been delivered since the last time
58           * this folder was opened; has a bit value of 16.
59           */
60          public static final Flag RECENT = new Flag(16);
61          /**
62           * Flag that indicates that the message has been viewed; has a bit value of 32.
63           * This flag is set by the {@link Message#getInputStream()} and {@link Message#getContent()}
64           * methods.
65           */
66          public static final Flag SEEN = new Flag(32);
67          /**
68           * Flags that indicates if this folder supports user-defined flags; has a bit value of 0x80000000.
69           */
70          public static final Flag USER = new Flag(0x80000000);
71  
72          private final int mask;
73  
74          private Flag(int mask) {
75              this.mask = mask;
76          }
77      }
78  
79      // the Serialized form of this class required the following two fields to be persisted
80      // this leads to a specific type of implementation
81      private int system_flags;
82      private final Hashtable user_flags;
83  
84      /**
85       * Construct a Flags instance with no flags set.
86       */
87      public Flags() {
88          user_flags = new Hashtable();
89      }
90  
91      /**
92       * Construct a Flags instance with a supplied system flag set.
93       * @param flag the system flag to set
94       */
95      public Flags(Flag flag) {
96          system_flags = flag.mask;
97          user_flags = new Hashtable();
98      }
99  
100     /**
101      * Construct a Flags instance with a same flags set.
102      * @param flags the instance to copy
103      */
104     public Flags(Flags flags) {
105         system_flags = flags.system_flags;
106         user_flags = new Hashtable(flags.user_flags);
107     }
108 
109     /**
110      * Construct a Flags instance with the supplied user flags set.
111      * Question: should this automatically set the USER system flag?
112      * @param name the user flag to set
113      */
114     public Flags(String name) {
115         user_flags = new Hashtable();
116         user_flags.put(name.toLowerCase(), name);
117     }
118 
119     /**
120      * Set a system flag.
121      * @param flag the system flag to set
122      */
123     public void add(Flag flag) {
124         system_flags |= flag.mask;
125     }
126 
127     /**
128      * Set all system and user flags from the supplied Flags.
129      * Question: do we need to check compatibility of USER flags?
130      * @param flags the Flags to add
131      */
132     public void add(Flags flags) {
133         system_flags |= flags.system_flags;
134         user_flags.putAll(flags.user_flags);
135     }
136 
137     /**
138      * Set a user flag.
139      * Question: should this fail if the USER system flag is not set?
140      * @param name the user flag to set
141      */
142     public void add(String name) {
143         user_flags.put(name.toLowerCase(), name);
144     }
145 
146     /**
147      * Return a copy of this instance.
148      * @return a copy of this instance
149      */
150     public Object clone() {
151         return new Flags(this);
152     }
153 
154     /**
155      * See if the supplied system flags are set
156      * @param flag the system flags to check for
157      * @return true if the flags are set
158      */
159     public boolean contains(Flag flag) {
160         return (system_flags & flag.mask) != 0;
161     }
162 
163     /**
164      * See if all of the supplied Flags are set
165      * @param flags the flags to check for
166      * @return true if all the supplied system and user flags are set
167      */
168     public boolean contains(Flags flags) {
169         return ((system_flags & flags.system_flags) == flags.system_flags)
170                 && user_flags.keySet().containsAll(flags.user_flags.keySet());
171     }
172 
173     /**
174      * See if the supplied user flag is set
175      * @param name the user flag to check for
176      * @return true if the flag is set
177      */
178     public boolean contains(String name) {
179         return user_flags.containsKey(name.toLowerCase());
180     }
181 
182     /**
183      * Equality is defined as true if the other object is a instanceof Flags with the
184      * same system and user flags set (using a case-insensitive name comparison for user flags).
185      * @param other the instance to compare against
186      * @return true if the two instance are the same
187      */
188     public boolean equals(Object other) {
189         if (other == this) return true;
190         if (other instanceof Flags == false) return false;
191         final Flags flags = (Flags) other;
192         return system_flags == flags.system_flags && user_flags.keySet().equals(flags.user_flags.keySet());
193     }
194 
195     /**
196      * Calculate a hashCode for this instance
197      * @return a hashCode for this instance
198      */
199     public int hashCode() {
200         return system_flags ^ user_flags.keySet().hashCode();
201     }
202 
203     /**
204      * Return a list of {@link Flags.Flag Flags} containing the system flags that have been set
205      * @return the system flags that have been set
206      */
207     public Flag[] getSystemFlags() {
208         // assumption: it is quicker to calculate the size than it is to reallocate the array
209         int size = 0;
210         if ((system_flags & Flag.ANSWERED.mask) != 0) size += 1;
211         if ((system_flags & Flag.DELETED.mask) != 0) size += 1;
212         if ((system_flags & Flag.DRAFT.mask) != 0) size += 1;
213         if ((system_flags & Flag.FLAGGED.mask) != 0) size += 1;
214         if ((system_flags & Flag.RECENT.mask) != 0) size += 1;
215         if ((system_flags & Flag.SEEN.mask) != 0) size += 1;
216         if ((system_flags & Flag.USER.mask) != 0) size += 1;
217         Flag[] result = new Flag[size];
218         if ((system_flags & Flag.USER.mask) != 0) result[--size] = Flag.USER;
219         if ((system_flags & Flag.SEEN.mask) != 0) result[--size] = Flag.SEEN;
220         if ((system_flags & Flag.RECENT.mask) != 0) result[--size] = Flag.RECENT;
221         if ((system_flags & Flag.FLAGGED.mask) != 0) result[--size] = Flag.FLAGGED;
222         if ((system_flags & Flag.DRAFT.mask) != 0) result[--size] = Flag.DRAFT;
223         if ((system_flags & Flag.DELETED.mask) != 0) result[--size] = Flag.DELETED;
224         if ((system_flags & Flag.ANSWERED.mask) != 0) result[--size] = Flag.ANSWERED;
225         return result;
226     }
227 
228     /**
229      * Return a list of user flags that have been set
230      * @return a list of user flags
231      */
232     public String[] getUserFlags() {
233         return (String[]) user_flags.values().toArray(new String[user_flags.values().size()]);
234     }
235 
236     /**
237      * Unset the supplied system flag.
238      * Question: what happens if we unset the USER flags and user flags are set?
239      * @param flag the flag to clear
240      */
241     public void remove(Flag flag) {
242         system_flags &= ~flag.mask;
243     }
244 
245     /**
246      * Unset all flags from the supplied instance.
247      * @param flags the flags to clear
248      */
249     public void remove(Flags flags) {
250         system_flags &= ~flags.system_flags;
251         user_flags.keySet().removeAll(flags.user_flags.keySet());
252     }
253 
254     /**
255      * Unset the supplied user flag.
256      * @param name the flag to clear
257      */
258     public void remove(String name) {
259         user_flags.remove(name.toLowerCase());
260     }
261 }