1 // ================================================================================================= 2 // ADOBE SYSTEMS INCORPORATED 3 // Copyright 2006 Adobe Systems Incorporated 4 // All Rights Reserved 5 // 6 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 7 // of the Adobe license agreement accompanying it. 8 // ================================================================================================= 9 10 package com.adobe.xmp.options; 11 12 import java.util.HashMap; 13 import java.util.Map; 14 15 import com.adobe.xmp.XMPError; 16 import com.adobe.xmp.XMPException; 17 18 /** 19 * The base class for a collection of 32 flag bits. Individual flags are defined as enum value bit 20 * masks. Inheriting classes add convenience accessor methods. 21 * 22 * @since 24.01.2006 23 */ 24 public abstract class Options 25 { 26 /** the internal int containing all options */ 27 private int options = 0; 28 /** a map containing the bit names */ 29 private Map optionNames = null; 30 31 32 /** 33 * The default constructor. 34 */ 35 public Options() 36 { 37 // EMTPY 38 } 39 40 41 /** 42 * Constructor with the options bit mask. 43 * 44 * @param options the options bit mask 45 * @throws XMPException If the options are not correct 46 */ 47 public Options(int options) throws XMPException 48 { 49 assertOptionsValid(options); 50 setOptions(options); 51 } 52 53 54 /** 55 * Resets the options. 56 */ 57 public void clear() 58 { 59 options = 0; 60 } 61 62 63 /** 64 * @param optionBits an option bitmask 65 * @return Returns true, if this object is equal to the given options. 66 */ 67 public boolean isExactly(int optionBits) 68 { 69 return getOptions() == optionBits; 70 } 71 72 73 /** 74 * @param optionBits an option bitmask 75 * @return Returns true, if this object contains all given options. 76 */ 77 public boolean containsAllOptions(int optionBits) 78 { 79 return (getOptions() & optionBits) == optionBits; 80 } 81 82 83 /** 84 * @param optionBits an option bitmask 85 * @return Returns true, if this object contain at least one of the given options. 86 */ 87 public boolean containsOneOf(int optionBits) 88 { 89 return ((getOptions()) & optionBits) != 0; 90 } 91 92 93 /** 94 * @param optionBit the binary bit or bits that are requested 95 * @return Returns if <emp>all</emp> of the requested bits are set or not. 96 */ 97 protected boolean getOption(int optionBit) 98 { 99 return (options & optionBit) != 0; 100 } 101 102 103 /** 104 * @param optionBits the binary bit or bits that shall be set to the given value 105 * @param value the boolean value to set 106 */ 107 public void setOption(int optionBits, boolean value) 108 { 109 options = value ? options | optionBits : options & ~optionBits; 110 } 111 112 113 /** 114 * Is friendly to access it during the tests. 115 * @return Returns the options. 116 */ 117 public int getOptions() 118 { 119 return options; 120 } 121 122 123 /** 124 * @param options The options to set. 125 * @throws XMPException 126 */ 127 public void setOptions(int options) throws XMPException 128 { 129 assertOptionsValid(options); 130 this.options = options; 131 } 132 133 134 /** 135 * @see Object#equals(Object) 136 */ 137 public boolean equals(Object obj) 138 { 139 return getOptions() == ((Options) obj).getOptions(); 140 } 141 142 143 /** 144 * @see java.lang.Object#hashCode() 145 */ 146 public int hashCode() 147 { 148 return getOptions(); 149 } 150 151 152 /** 153 * Creates a human readable string from the set options. <em>Note:</em> This method is quite 154 * expensive and should only be used within tests or as 155 * @return Returns a String listing all options that are set to <code>true</code> by their name, 156 * like "option1 | option4". 157 */ 158 public String getOptionsString() 159 { 160 if (options != 0) 161 { 162 StringBuffer sb = new StringBuffer(); 163 int theBits = options; 164 while (theBits != 0) 165 { 166 int oneLessBit = theBits & (theBits - 1); // clear rightmost one bit 167 int singleBit = theBits ^ oneLessBit; 168 String bitName = getOptionName(singleBit); 169 sb.append(bitName); 170 if (oneLessBit != 0) 171 { 172 sb.append(" | "); 173 } 174 theBits = oneLessBit; 175 } 176 return sb.toString(); 177 } 178 else 179 { 180 return "<none>"; 181 } 182 } 183 184 185 /** 186 * @return Returns the options as hex bitmask. 187 */ 188 public String toString() 189 { 190 return "0x" + Integer.toHexString(options); 191 } 192 193 194 /** 195 * To be implemeted by inheritants. 196 * @return Returns a bit mask where all valid option bits are set. 197 */ 198 protected abstract int getValidOptions(); 199 200 201 /** 202 * To be implemeted by inheritants. 203 * @param option a single, valid option bit. 204 * @return Returns a human readable name for an option bit. 205 */ 206 protected abstract String defineOptionName(int option); 207 208 209 /** 210 * The inheriting option class can do additional checks on the options. 211 * <em>Note:</em> For performance reasons this method is only called 212 * when setting bitmasks directly. 213 * When get- and set-methods are used, this method must be called manually, 214 * normally only when the Options-object has been created from a client 215 * (it has to be made public therefore). 216 * 217 * @param options the bitmask to check. 218 * @throws XMPException Thrown if the options are not consistent. 219 */ 220 protected void assertConsistency(int options) throws XMPException 221 { 222 // empty, no checks 223 } 224 225 226 /** 227 * Checks options before they are set. 228 * First it is checked if only defined options are used, 229 * second the additional {@link Options#assertConsistency(int)}-method is called. 230 * 231 * @param options the options to check 232 * @throws XMPException Thrown if the options are invalid. 233 */ 234 private void assertOptionsValid(int options) throws XMPException 235 { 236 int invalidOptions = options & ~getValidOptions(); 237 if (invalidOptions == 0) 238 { 239 assertConsistency(options); 240 } 241 else 242 { 243 throw new XMPException("The option bit(s) 0x" + Integer.toHexString(invalidOptions) 244 + " are invalid!", XMPError.BADOPTIONS); 245 } 246 } 247 248 249 250 /** 251 * Looks up or asks the inherited class for the name of an option bit. 252 * Its save that there is only one valid option handed into the method. 253 * @param option a single option bit 254 * @return Returns the option name or undefined. 255 */ 256 private String getOptionName(int option) 257 { 258 Map optionsNames = procureOptionNames(); 259 260 Integer key = new Integer(option); 261 String result = (String) optionsNames.get(key); 262 if (result == null) 263 { 264 result = defineOptionName(option); 265 if (result != null) 266 { 267 optionsNames.put(key, result); 268 } 269 else 270 { 271 result = "<option name not defined>"; 272 } 273 } 274 275 return result; 276 } 277 278 279 /** 280 * @return Returns the optionNames map and creates it if required. 281 */ 282 private Map procureOptionNames() 283 { 284 if (optionNames == null) 285 { 286 optionNames = new HashMap(); 287 } 288 return optionNames; 289 } 290 } 291