Skip to content

Package: Flags$Flag

Flags$Flag

nameinstructionbranchcomplexitylinemethod
Flags.Flag(int)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 36
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail;
18:
19: import java.io.Serializable;
20: import java.util.Enumeration;
21: import java.util.Hashtable;
22: import java.util.Locale;
23: import java.util.Vector;
24:
25: /**
26: * The Flags class represents the set of flags on a Message. Flags
27: * are composed of predefined system flags, and user defined flags. <p>
28: *
29: * A System flag is represented by the <code>Flags.Flag</code>
30: * inner class. A User defined flag is represented as a String.
31: * User flags are case-independent. <p>
32: *
33: * A set of standard system flags are predefined. Most folder
34: * implementations are expected to support these flags. Some
35: * implementations may also support arbitrary user-defined flags. The
36: * <code>getPermanentFlags</code> method on a Folder returns a Flags
37: * object that holds all the flags that are supported by that folder
38: * implementation. <p>
39: *
40: * A Flags object is serializable so that (for example) the
41: * use of Flags objects in search terms can be serialized
42: * along with the search terms. <p>
43: *
44: * <strong>Warning:</strong>
45: * Serialized objects of this class may not be compatible with future
46: * Jakarta Mail API releases. The current serialization support is
47: * appropriate for short term storage. <p>
48: *
49: * The below code sample illustrates how to set, examine, and get the
50: * flags for a message.
51: * <pre>
52: *
53: * Message m = folder.getMessage(1);
54: * m.setFlag(Flags.Flag.DELETED, true); // set the DELETED flag
55: *
56: * // Check if DELETED flag is set on this message
57: * if (m.isSet(Flags.Flag.DELETED))
58: *         System.out.println("DELETED message");
59: *
60: * // Examine ALL system flags for this message
61: * Flags flags = m.getFlags();
62: * Flags.Flag[] sf = flags.getSystemFlags();
63: * for (int i = 0; i < sf.length; i++) {
64: *         if (sf[i] == Flags.Flag.DELETED)
65: * System.out.println("DELETED message");
66: *         else if (sf[i] == Flags.Flag.SEEN)
67: * System.out.println("SEEN message");
68: * ......
69: * ......
70: * }
71: * </pre>
72: *
73: * @author John Mani
74: * @author Bill Shannon
75: * @see Folder#getPermanentFlags
76: */
77:
78: public class Flags implements Cloneable, Serializable {
79:
80: private int system_flags = 0;
81: // used as a case-independent Set that preserves the original case,
82: // the key is the lowercase flag name and the value is the original
83: private Hashtable<String, String> user_flags = null;
84:
85: private final static int ANSWERED_BIT = 0x01;
86: private final static int DELETED_BIT = 0x02;
87: private final static int DRAFT_BIT = 0x04;
88: private final static int FLAGGED_BIT = 0x08;
89: private final static int RECENT_BIT = 0x10;
90: private final static int SEEN_BIT = 0x20;
91: private final static int USER_BIT = 0x80000000;
92:
93: private static final long serialVersionUID = 6243590407214169028L;
94:
95: /**
96: * This inner class represents an individual system flag. A set
97: * of standard system flag objects are predefined here.
98: */
99: public static final class Flag {
100: /**
101: * This message has been answered. This flag is set by clients
102: * to indicate that this message has been answered to.
103: */
104: public static final Flag ANSWERED = new Flag(ANSWERED_BIT);
105:
106: /**
107: * This message is marked deleted. Clients set this flag to
108: * mark a message as deleted. The expunge operation on a folder
109: * removes all messages in that folder that are marked for deletion.
110: */
111: public static final Flag DELETED = new Flag(DELETED_BIT);
112:
113: /**
114: * This message is a draft. This flag is set by clients
115: * to indicate that the message is a draft message.
116: */
117: public static final Flag DRAFT = new Flag(DRAFT_BIT);
118:
119: /**
120: * This message is flagged. No semantic is defined for this flag.
121: * Clients alter this flag.
122: */
123: public static final Flag FLAGGED = new Flag(FLAGGED_BIT);
124:
125: /**
126: * This message is recent. Folder implementations set this flag
127: * to indicate that this message is new to this folder, that is,
128: * it has arrived since the last time this folder was opened. <p>
129: *
130: * Clients cannot alter this flag.
131: */
132: public static final Flag RECENT = new Flag(RECENT_BIT);
133:
134: /**
135: * This message is seen. This flag is implicitly set by the
136: * implementation when this Message's content is returned
137: * to the client in some form. The <code>getInputStream</code>
138: * and <code>getContent</code> methods on Message cause this
139: * flag to be set. <p>
140: *
141: * Clients can alter this flag.
142: */
143: public static final Flag SEEN = new Flag(SEEN_BIT);
144:
145: /**
146: * A special flag that indicates that this folder supports
147: * user defined flags. <p>
148: *
149: * The implementation sets this flag. Clients cannot alter
150: * this flag but can use it to determine if a folder supports
151: * user defined flags by using
152: * <code>folder.getPermanentFlags().contains(Flags.Flag.USER)</code>.
153: */
154: public static final Flag USER = new Flag(USER_BIT);
155:
156: // flags are stored as bits for efficiency
157: private int bit;
158:
159: private Flag(int bit) {
160: this.bit = bit;
161: }
162: }
163:
164:
165: /**
166: * Construct an empty Flags object.
167: */
168: public Flags() {
169: }
170:
171: /**
172: * Construct a Flags object initialized with the given flags.
173: *
174: * @param flags the flags for initialization
175: */
176: @SuppressWarnings("unchecked")
177: public Flags(Flags flags) {
178: this.system_flags = flags.system_flags;
179: if (flags.user_flags != null)
180: this.user_flags = (Hashtable) flags.user_flags.clone();
181: }
182:
183: /**
184: * Construct a Flags object initialized with the given system flag.
185: *
186: * @param flag the flag for initialization
187: */
188: public Flags(Flag flag) {
189: this.system_flags |= flag.bit;
190: }
191:
192: /**
193: * Construct a Flags object initialized with the given user flag.
194: *
195: * @param flag the flag for initialization
196: */
197: public Flags(String flag) {
198: user_flags = new Hashtable<>(1);
199: user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
200: }
201:
202: /**
203: * Add the specified system flag to this Flags object.
204: *
205: * @param flag the flag to add
206: */
207: public void add(Flag flag) {
208: system_flags |= flag.bit;
209: }
210:
211: /**
212: * Add the specified user flag to this Flags object.
213: *
214: * @param flag the flag to add
215: */
216: public void add(String flag) {
217: if (user_flags == null)
218: user_flags = new Hashtable<>(1);
219: user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
220: }
221:
222: /**
223: * Add all the flags in the given Flags object to this
224: * Flags object.
225: *
226: * @param f Flags object
227: */
228: public void add(Flags f) {
229: system_flags |= f.system_flags; // add system flags
230:
231: if (f.user_flags != null) { // add user-defined flags
232: if (user_flags == null)
233: user_flags = new Hashtable<>(1);
234:
235: Enumeration<String> e = f.user_flags.keys();
236:
237: while (e.hasMoreElements()) {
238: String s = e.nextElement();
239: user_flags.put(s, f.user_flags.get(s));
240: }
241: }
242: }
243:
244: /**
245: * Remove the specified system flag from this Flags object.
246: *
247: * @param flag the flag to be removed
248: */
249: public void remove(Flag flag) {
250: system_flags &= ~flag.bit;
251: }
252:
253: /**
254: * Remove the specified user flag from this Flags object.
255: *
256: * @param flag the flag to be removed
257: */
258: public void remove(String flag) {
259: if (user_flags != null)
260: user_flags.remove(flag.toLowerCase(Locale.ENGLISH));
261: }
262:
263: /**
264: * Remove all flags in the given Flags object from this
265: * Flags object.
266: *
267: * @param f the flag to be removed
268: */
269: public void remove(Flags f) {
270: system_flags &= ~f.system_flags; // remove system flags
271:
272: if (f.user_flags != null) {
273: if (user_flags == null)
274: return;
275:
276: Enumeration<String> e = f.user_flags.keys();
277: while (e.hasMoreElements())
278: user_flags.remove(e.nextElement());
279: }
280: }
281:
282: /**
283: * Remove any flags <strong>not</strong> in the given Flags object.
284: * Useful for clearing flags not supported by a server. If the
285: * given Flags object includes the Flags.Flag.USER flag, all user
286: * flags in this Flags object are retained.
287: *
288: * @param f the flags to keep
289: * @return true if this Flags object changed
290: * @since JavaMail 1.6
291: */
292: public boolean retainAll(Flags f) {
293: boolean changed = false;
294: int sf = system_flags & f.system_flags;
295: if (system_flags != sf) {
296: system_flags = sf;
297: changed = true;
298: }
299:
300: // if we have user flags, and the USER flag is not set in "f",
301: // determine which user flags to clear
302: if (user_flags != null && (f.system_flags & USER_BIT) == 0) {
303: if (f.user_flags != null) {
304: Enumeration<String> e = user_flags.keys();
305: while (e.hasMoreElements()) {
306: String key = e.nextElement();
307: if (!f.user_flags.containsKey(key)) {
308: user_flags.remove(key);
309: changed = true;
310: }
311: }
312: } else {
313: // if anything in user_flags, throw them away
314: changed = user_flags.size() > 0;
315: user_flags = null;
316: }
317: }
318: return changed;
319: }
320:
321: /**
322: * Check whether the specified system flag is present in this Flags object.
323: *
324: * @param flag the flag to test
325: * @return true of the given flag is present, otherwise false.
326: */
327: public boolean contains(Flag flag) {
328: return (system_flags & flag.bit) != 0;
329: }
330:
331: /**
332: * Check whether the specified user flag is present in this Flags object.
333: *
334: * @param flag the flag to test
335: * @return true of the given flag is present, otherwise false.
336: */
337: public boolean contains(String flag) {
338: if (user_flags == null)
339: return false;
340: else
341: return user_flags.containsKey(flag.toLowerCase(Locale.ENGLISH));
342: }
343:
344: /**
345: * Check whether all the flags in the specified Flags object are
346: * present in this Flags object.
347: *
348: * @param f the flags to test
349: * @return true if all flags in the given Flags object are present,
350: * otherwise false.
351: */
352: public boolean contains(Flags f) {
353: // Check system flags
354: if ((f.system_flags & system_flags) != f.system_flags)
355: return false;
356:
357: // Check user flags
358: if (f.user_flags != null) {
359: if (user_flags == null)
360: return false;
361: Enumeration<String> e = f.user_flags.keys();
362:
363: while (e.hasMoreElements()) {
364: if (!user_flags.containsKey(e.nextElement()))
365: return false;
366: }
367: }
368:
369: // If we've made it till here, return true
370: return true;
371: }
372:
373: /**
374: * Check whether the two Flags objects are equal.
375: *
376: * @return true if they're equal
377: */
378: @Override
379: public boolean equals(Object obj) {
380: if (!(obj instanceof Flags))
381: return false;
382:
383: Flags f = (Flags) obj;
384:
385: // Check system flags
386: if (f.system_flags != this.system_flags)
387: return false;
388:
389: // Check user flags
390: int size = this.user_flags == null ? 0 : this.user_flags.size();
391: int fsize = f.user_flags == null ? 0 : f.user_flags.size();
392: if (size == 0 && fsize == 0)
393: return true;
394: if (f.user_flags != null && this.user_flags != null && fsize == size)
395: return user_flags.keySet().equals(f.user_flags.keySet());
396:
397: return false;
398: }
399:
400: /**
401: * Compute a hash code for this Flags object.
402: *
403: * @return the hash code
404: */
405: @Override
406: public int hashCode() {
407: int hash = system_flags;
408: if (user_flags != null) {
409: Enumeration<String> e = user_flags.keys();
410: while (e.hasMoreElements())
411: hash += e.nextElement().hashCode();
412: }
413: return hash;
414: }
415:
416: /**
417: * Return all the system flags in this Flags object. Returns
418: * an array of size zero if no flags are set.
419: *
420: * @return array of Flags.Flag objects representing system flags
421: */
422: public Flag[] getSystemFlags() {
423: Vector<Flag> v = new Vector<>();
424: if ((system_flags & ANSWERED_BIT) != 0)
425: v.addElement(Flag.ANSWERED);
426: if ((system_flags & DELETED_BIT) != 0)
427: v.addElement(Flag.DELETED);
428: if ((system_flags & DRAFT_BIT) != 0)
429: v.addElement(Flag.DRAFT);
430: if ((system_flags & FLAGGED_BIT) != 0)
431: v.addElement(Flag.FLAGGED);
432: if ((system_flags & RECENT_BIT) != 0)
433: v.addElement(Flag.RECENT);
434: if ((system_flags & SEEN_BIT) != 0)
435: v.addElement(Flag.SEEN);
436: if ((system_flags & USER_BIT) != 0)
437: v.addElement(Flag.USER);
438:
439: Flag[] f = new Flag[v.size()];
440: v.copyInto(f);
441: return f;
442: }
443:
444: /**
445: * Return all the user flags in this Flags object. Returns
446: * an array of size zero if no flags are set.
447: *
448: * @return array of Strings, each String represents a flag.
449: */
450: public String[] getUserFlags() {
451: Vector<String> v = new Vector<>();
452: if (user_flags != null) {
453: Enumeration<String> e = user_flags.elements();
454:
455: while (e.hasMoreElements())
456: v.addElement(e.nextElement());
457: }
458:
459: String[] f = new String[v.size()];
460: v.copyInto(f);
461: return f;
462: }
463:
464: /**
465: * Clear all of the system flags.
466: *
467: * @since JavaMail 1.6
468: */
469: public void clearSystemFlags() {
470: system_flags = 0;
471: }
472:
473: /**
474: * Clear all of the user flags.
475: *
476: * @since JavaMail 1.6
477: */
478: public void clearUserFlags() {
479: user_flags = null;
480: }
481:
482: /**
483: * Returns a clone of this Flags object.
484: */
485: @SuppressWarnings("unchecked")
486: @Override
487: public Object clone() {
488: Flags f = null;
489: try {
490: f = (Flags) super.clone();
491: } catch (CloneNotSupportedException cex) {
492: // ignore, can't happen
493: }
494: if (this.user_flags != null)
495: f.user_flags = (Hashtable) this.user_flags.clone();
496: return f;
497: }
498:
499: /**
500: * Return a string representation of this Flags object.
501: * Note that the exact format of the string is subject to change.
502: */
503: public String toString() {
504: StringBuilder sb = new StringBuilder();
505:
506: if ((system_flags & ANSWERED_BIT) != 0)
507: sb.append("\\Answered ");
508: if ((system_flags & DELETED_BIT) != 0)
509: sb.append("\\Deleted ");
510: if ((system_flags & DRAFT_BIT) != 0)
511: sb.append("\\Draft ");
512: if ((system_flags & FLAGGED_BIT) != 0)
513: sb.append("\\Flagged ");
514: if ((system_flags & RECENT_BIT) != 0)
515: sb.append("\\Recent ");
516: if ((system_flags & SEEN_BIT) != 0)
517: sb.append("\\Seen ");
518: if ((system_flags & USER_BIT) != 0)
519: sb.append("\\* ");
520:
521: boolean first = true;
522: if (user_flags != null) {
523: Enumeration<String> e = user_flags.elements();
524:
525: while (e.hasMoreElements()) {
526: if (first)
527: first = false;
528: else
529: sb.append(' ');
530: sb.append(e.nextElement());
531: }
532: }
533:
534: if (first && sb.length() > 0)
535: sb.setLength(sb.length() - 1); // smash trailing space
536:
537: return sb.toString();
538: }
539:
540: /*
541: public static void main(String argv[]) throws Exception {
542: // a new flags object
543: Flags f1 = new Flags();
544: f1.add(Flags.Flag.DELETED);
545: f1.add(Flags.Flag.SEEN);
546: f1.add(Flags.Flag.RECENT);
547: f1.add(Flags.Flag.ANSWERED);
548:
549: // check copy constructor with only system flags
550: Flags fc = new Flags(f1);
551: if (f1.equals(fc) && fc.equals(f1))
552: System.out.println("success");
553: else
554: System.out.println("fail");
555:
556: // check clone with only system flags
557: fc = (Flags)f1.clone();
558: if (f1.equals(fc) && fc.equals(f1))
559: System.out.println("success");
560: else
561: System.out.println("fail");
562:
563: // add a user flag and make sure it still works right
564: f1.add("MyFlag");
565:
566: // shouldn't be equal here
567: if (!f1.equals(fc) && !fc.equals(f1))
568: System.out.println("success");
569: else
570: System.out.println("fail");
571:
572: // check clone
573: fc = (Flags)f1.clone();
574: if (f1.equals(fc) && fc.equals(f1))
575: System.out.println("success");
576: else
577: System.out.println("fail");
578:
579: // make sure user flag hash tables are separate
580: fc.add("AnotherFlag");
581: if (!f1.equals(fc) && !fc.equals(f1))
582: System.out.println("success");
583: else
584: System.out.println("fail");
585:
586: // check copy constructor
587: fc = new Flags(f1);
588: if (f1.equals(fc) && fc.equals(f1))
589: System.out.println("success");
590: else
591: System.out.println("fail");
592:
593: // another new flags object
594: Flags f2 = new Flags(Flags.Flag.ANSWERED);
595: f2.add("MyFlag");
596:
597: if (f1.contains(Flags.Flag.DELETED))
598: System.out.println("success");
599: else
600: System.out.println("fail");
601:
602: if (f1.contains(Flags.Flag.SEEN))
603: System.out.println("success");
604: else
605: System.out.println("fail");
606:
607: if (f1.contains(Flags.Flag.RECENT))
608: System.out.println("success");
609: else
610: System.out.println("fail");
611:
612: if (f1.contains("MyFlag"))
613: System.out.println("success");
614: else
615: System.out.println("fail");
616:
617: if (f2.contains(Flags.Flag.ANSWERED))
618: System.out.println("success");
619: else
620: System.out.println("fail");
621:
622:
623: System.out.println("----------------");
624:
625: String[] s = f1.getUserFlags();
626: for (int i = 0; i < s.length; i++)
627: System.out.println(s[i]);
628: System.out.println("----------------");
629: s = f2.getUserFlags();
630: for (int i = 0; i < s.length; i++)
631: System.out.println(s[i]);
632:
633: System.out.println("----------------");
634:
635: if (f1.contains(f2)) // this should be true
636: System.out.println("success");
637: else
638: System.out.println("fail");
639:
640: if (!f2.contains(f1)) // this should be false
641: System.out.println("success");
642: else
643: System.out.println("fail");
644:
645: Flags f3 = new Flags();
646: f3.add(Flags.Flag.DELETED);
647: f3.add(Flags.Flag.SEEN);
648: f3.add(Flags.Flag.RECENT);
649: f3.add(Flags.Flag.ANSWERED);
650: f3.add("ANOTHERFLAG");
651: f3.add("MYFLAG");
652:
653: f1.add("AnotherFlag");
654:
655: if (f1.equals(f3))
656: System.out.println("equals success");
657: else
658: System.out.println("fail");
659: if (f3.equals(f1))
660: System.out.println("equals success");
661: else
662: System.out.println("fail");
663: System.out.println("f1 hash code " + f1.hashCode());
664: System.out.println("f3 hash code " + f3.hashCode());
665: if (f1.hashCode() == f3.hashCode())
666: System.out.println("success");
667: else
668: System.out.println("fail");
669: }
670: ****/
671: }