1 /* 2 ***************************************************************************** 3 * Copyright (C) 2000-2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ***************************************************************************** 6 */ 7 package com.ibm.rbm; 8 9 10 import java.io.IOException; 11 import java.io.PrintStream; 12 import java.io.Writer; 13 import java.util.*; 14 15 import com.ibm.rbm.gui.RBManagerGUI; 16 17 /** 18 * A class representing the entire Bundle of Resources for a particular language, country, variant. 19 * 20 * @author Jared Jackson 21 * @see com.ibm.rbm.RBManager 22 */ 23 public class Bundle { 24 25 /** 26 * The following public class variables reflect the various properties that can be included as 27 * meta-data in a resource bundle formatted by RBManager 28 */ 29 public String name; 30 /** 31 * The encoding of the bundle (e.g. 'en', 'en_US', 'de', etc.) 32 */ 33 public String encoding; 34 /** 35 * A descriptor of the language in the encoding (e.g. English, German, etc.) 36 */ 37 public String language; 38 /** 39 * A descriptor of the country in the encoding (e.g. US, Canada, Great Britain) 40 */ 41 public String country; 42 /** 43 * The descriptor of the variant in the encoding (e.g. Euro, Irish, etc.) 44 */ 45 public String variant; 46 /** 47 * A comment concerning the bundle 48 */ 49 public String comment; 50 /** 51 * The name of the person responsible for the managerment of this bundle 52 */ 53 public String manager; 54 55 private TreeSet groups; // A vector of groups of NLS items, the key is the group name 56 57 /** 58 * A hashtable of all of the items in the bundle, hashed according to their 59 * NLS key. 60 */ 61 62 public Hashtable allItems; // A hashtable of all items in the file, the key is the NLS key 63 64 private TreeSet untranslatedItems; // A vector of all items which are untranslated 65 66 /** 67 * A vector containing all of the items which are duplicates (based on the NLS keys) 68 * of items previously declared in the bundle. 69 */ 70 71 public Vector duplicates; // A vector of items which are duplicates (NLS Keys) of previous items 72 73 /** 74 * Constructor for creating an empty bundle with a given encoding 75 */ 76 Bundle(String encoding)77 public Bundle(String encoding) { 78 this.encoding = encoding; 79 language = null; 80 country = null; 81 variant = null; 82 comment = null; 83 manager = null; 84 groups = new TreeSet(new Comparator() { 85 public boolean equals(Object o) { return false; } 86 87 public int compare(Object o1, Object o2) { 88 if (!(o1 instanceof BundleGroup) || !(o2 instanceof BundleGroup)) 89 return 0; 90 BundleGroup g1 = (BundleGroup)o1; 91 BundleGroup g2 = (BundleGroup)o2; 92 return g1.getName().compareTo(g2.getName()); 93 } 94 }); 95 96 untranslatedItems = new TreeSet(new Comparator() { 97 public boolean equals(Object o) { return false; } 98 99 public int compare(Object o1, Object o2) { 100 if (!(o1 instanceof BundleItem) || !(o2 instanceof BundleItem)) return 0; 101 BundleItem i1 = (BundleItem)o1; 102 BundleItem i2 = (BundleItem)o2; 103 return i1.getKey().compareTo(i2.getKey()); 104 } 105 }); 106 107 duplicates = new Vector(); 108 allItems = new Hashtable(); 109 } 110 111 /** 112 * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern"). 113 * This method returns the language encoding string, or null if it is not specified 114 */ 115 getLanguageEncoding()116 public String getLanguageEncoding() { 117 if (encoding == null) 118 return null; 119 if (encoding.indexOf("_") >= 0) 120 return encoding.substring(0,encoding.indexOf("_")); 121 return encoding.trim(); 122 } 123 124 /** 125 * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern"). 126 * This method returns the country encoding string, or null if it is not specified 127 */ 128 getCountryEncoding()129 public String getCountryEncoding() { 130 if (encoding == null || encoding.indexOf("_") < 0) 131 return null; 132 // Strip off the language 133 String workStr = encoding.substring(encoding.indexOf("_")+1,encoding.length()); 134 if (workStr.indexOf("_") >= 0) 135 return workStr.substring(0,encoding.indexOf("_")); 136 return workStr.trim(); 137 } 138 139 /** 140 * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern"). 141 * This method returns the variant encoding string, or null if it is not specified 142 */ 143 getVariantEncoding()144 public String getVariantEncoding() { 145 if (encoding == null || encoding.indexOf("_") < 0) 146 return null; 147 // Strip off the language 148 String workStr = encoding.substring(encoding.indexOf("_")+1,encoding.length()); 149 if (workStr == null || workStr.length() < 1 || workStr.indexOf("_") < 0) 150 return null; 151 // Strip off the country 152 workStr = workStr.substring(encoding.indexOf("_")+1, workStr.length()); 153 return workStr.trim(); 154 } 155 156 /** 157 * Returns the UntranslatedItems as a vector. I should find where this happens and stop it. 158 */ 159 getUntranslatedItemsAsVector()160 public Vector getUntranslatedItemsAsVector() { 161 Iterator iter = untranslatedItems.iterator(); 162 Vector v = new Vector(); 163 while (iter.hasNext()) 164 v.addElement(iter.next()); 165 return v; 166 } 167 168 /** 169 * Checks all items in the untranslated items set. If they belong to a group whose name 170 * matches the passed in name, then they are removed. 171 */ 172 removeUntranslatedItemsByGroup(String groupName)173 public void removeUntranslatedItemsByGroup(String groupName) { 174 Iterator iter = untranslatedItems.iterator(); 175 try { 176 while(iter.hasNext()) { 177 BundleItem item = null; 178 item = (BundleItem)iter.next(); 179 if (item != null && item.getParentGroup().getName().equals(groupName)) { 180 removeUntranslatedItem(item.getKey()); 181 } 182 } 183 } catch (Exception e) { 184 RBManagerGUI.debugMsg(e.getMessage()); 185 } 186 } 187 188 /** 189 * Checks to see if an item of the given key name exists in the set of untranslated items. If 190 * it does exist, then it is removed. 191 */ 192 removeUntranslatedItem(String name)193 public void removeUntranslatedItem(String name) { 194 Iterator iter = untranslatedItems.iterator(); 195 while (iter.hasNext()) { 196 BundleItem item = (BundleItem)iter.next(); 197 if (item.getKey().equals(name)) { 198 untranslatedItems.remove(item); 199 break; 200 } 201 } 202 } 203 204 /** 205 * Returns the boolean of wether a group of a given name exists in the bundle 206 */ 207 hasGroup(String groupName)208 public boolean hasGroup(String groupName) { 209 Iterator iter = groups.iterator(); 210 while (iter.hasNext()) { 211 BundleGroup group = (BundleGroup)iter.next(); 212 if (group.getName().equals(groupName)) 213 return true; 214 } 215 return false; 216 } 217 218 /** 219 * Creates a group of the given name and optionally associates a comment with 220 * that group. 221 */ 222 addBundleGroup(String groupName, String groupComment)223 public void addBundleGroup(String groupName, String groupComment) { 224 BundleGroup bg = new BundleGroup(this, groupName); 225 bg.setComment(groupComment); 226 addBundleGroup(bg); 227 } 228 229 /** 230 * Removes the group of the given name if it exists in the bundle 231 */ 232 removeGroup(String groupName)233 public void removeGroup(String groupName) { 234 Iterator iter = groups.iterator(); 235 while (iter.hasNext()) { 236 BundleGroup tempGroup = (BundleGroup)iter.next(); 237 if (tempGroup.getName().equals(groupName)) { 238 groups.remove(tempGroup); 239 break; 240 } 241 } 242 // Remove the items from the untanslated items 243 removeUntranslatedItemsByGroup(groupName); 244 245 // Loop through all Items 246 Enumeration elems = allItems.elements(); 247 while(elems.hasMoreElements()) { 248 BundleItem item = (BundleItem)elems.nextElement(); 249 if (item.getParentGroup().getName().equals(groupName)) { 250 allItems.remove(item); 251 } 252 } 253 } 254 255 /** 256 * Removes a single resource item from the bundle 257 */ 258 removeItem(String key)259 public void removeItem(String key) { 260 Object o = allItems.get(key); 261 if (o != null) { 262 BundleItem item = (BundleItem)o; 263 // Remove from allItems Hashtable 264 allItems.remove(key); 265 // Remove from item's group 266 if (item.getParentGroup() != null) { 267 BundleGroup group = item.getParentGroup(); 268 group.removeBundleItem(key); 269 } 270 // Remove from untranslatedItems Hashtable 271 removeUntranslatedItem(key); 272 } 273 } 274 275 /** 276 * Attempts to add a BundleItem to the untranslatedItems. The addition will fail in two cases: One, if 277 * the item does not all ready belong to this Bundle, and Two, if the item is all ready in the set of 278 * untranslated items. 279 */ 280 addUntranslatedItem(BundleItem item)281 public void addUntranslatedItem(BundleItem item) { 282 if (item.getParentGroup().getParentBundle() != this) 283 return; 284 // Remove it if it exists. 285 if (untranslatedItems.contains(item)) { 286 untranslatedItems.remove(item); 287 } 288 untranslatedItems.add(item); 289 } 290 291 /** 292 * Returns the number of items currently marked as untranslated 293 */ 294 getUntranslatedItemsSize()295 public int getUntranslatedItemsSize() { 296 return untranslatedItems.size(); 297 } 298 299 /** 300 * Returns the indexth untranslated item 301 */ 302 getUntranslatedItem(int index)303 public BundleItem getUntranslatedItem(int index) { 304 if (index >= untranslatedItems.size()) 305 return null; 306 Iterator iter = untranslatedItems.iterator(); 307 for (int i=0; i < index; i++) 308 iter.next(); 309 return (BundleItem)iter.next(); 310 } 311 312 /** 313 * Return the various resource bundle groups stored in a Vector collection. 314 */ 315 getGroupsAsVector()316 public Vector getGroupsAsVector() { 317 Vector v = new Vector(); 318 Iterator iter = groups.iterator(); 319 while (iter.hasNext()) { 320 BundleGroup group = (BundleGroup)iter.next(); 321 v.addElement(group); 322 } 323 return v; 324 } 325 326 /** 327 * Returns the number of groups in the bundle. 328 */ 329 getGroupCount()330 public int getGroupCount() { 331 return groups.size(); 332 } 333 334 /** 335 * Returns a bundle group given a certain index. 336 */ 337 getBundleGroup(int index)338 public BundleGroup getBundleGroup(int index) { 339 if (index >= getGroupCount()) 340 return null; 341 Iterator iter = groups.iterator(); 342 for (int i=0; i < index; i++) 343 iter.next(); 344 return (BundleGroup)iter.next(); 345 } 346 347 /** 348 * Looks for a bundle group of a given name within a bundle and 349 * returns it if found. 350 */ 351 getBundleGroup(String groupName)352 public BundleGroup getBundleGroup(String groupName) { 353 Iterator iter = groups.iterator(); 354 while(iter.hasNext()) { 355 BundleGroup group = (BundleGroup)iter.next(); 356 if (group.getName().equals(groupName)) 357 return group; 358 } 359 return null; 360 } 361 362 /** 363 * Looks up and returns a bundle item stored in the bundle based on its 364 * NLS lookup key. 365 */ 366 getBundleItem(String key)367 public BundleItem getBundleItem(String key) { 368 return (BundleItem)allItems.get(key); 369 } 370 371 /** 372 * One group is created for all bundles called 'Ungrouped Items'. This is the bundle 373 * group in which bundle items are placed that are not specifically grouped in the 374 * resource bundle file. This method returns that bundle group. 375 */ 376 getUngroupedGroup()377 public BundleGroup getUngroupedGroup() { 378 return getBundleGroup("Ungrouped Items"); 379 } 380 381 /** 382 * Add a bundle group to the bundle 383 */ 384 addBundleGroup(BundleGroup bg)385 public void addBundleGroup(BundleGroup bg) { 386 groups.add(bg); 387 } 388 389 /** 390 * Add a bundle item to the bundle. This bundle item should all ready have its 391 * bundle group assigned. 392 */ 393 addBundleItem(BundleItem item)394 public void addBundleItem(BundleItem item) { 395 if (allItems.containsKey(item.getKey())) { 396 duplicates.addElement(item); 397 } else { 398 if (!(groups.contains(item.getParentGroup()))) 399 addBundleGroup(item.getParentGroup()); 400 item.getParentGroup().addBundleItem(item); 401 allItems.put(item.getKey(), item); 402 removeUntranslatedItem(item.getKey()); 403 if (!item.isTranslated()) 404 addUntranslatedItem(item); 405 } 406 } 407 408 /** 409 * A method useful in debugging. The string returned displays the encoding 410 * information about the bundle and wether or not it is the base class of 411 * a resource bundle. 412 */ 413 toString()414 public String toString() { 415 String retStr = new String(); 416 if (language != null && !language.equals("")) retStr = language; 417 if (country != null && !country.equals("")) retStr += ", " + country; 418 if (variant != null && !variant.equals("")) retStr += ", " + variant; 419 420 retStr += " (" + (encoding == null || encoding.equals("") ? "Base Class" : encoding) + ")"; 421 return retStr; 422 } 423 424 /** 425 * This method produces a String which is suitable for inclusion in a .properties 426 * style resource bundle. It attaches (in comments) the meta data that RBManager 427 * reads to manage the resource bundle file. This portion of the output should 428 * be included at the beginning of the resource bundle file. 429 */ 430 toOutputString()431 public String toOutputString() { 432 String retStr = "# @file " + name + "\n"; 433 if (encoding != null) retStr += "# @fileEncoding " + encoding + "\n"; 434 if (language != null) retStr += "# @fileLanguage " + language + "\n"; 435 if (country != null) retStr += "# @fileCountry " + country + "\n"; 436 if (variant != null) retStr += "# @fileVariant " + variant + "\n"; 437 if (manager != null) retStr += "# @fileManager " + manager + "\n"; 438 if (comment != null) retStr += "# @fileComment " + comment + "\n"; 439 return retStr; 440 } 441 442 /** 443 * A helping method for outputting the formatted contents of the bundle to a 444 * print stream. The method first outputs the header information and then outputs 445 * each bundle group's formatted data which includes each bundle item. 446 */ 447 writeContents(PrintStream ps)448 public void writeContents(PrintStream ps) { 449 ps.println(this.toOutputString()); 450 Iterator iter = groups.iterator(); 451 while (iter.hasNext()) { 452 ((BundleGroup)iter.next()).writeContents(ps); 453 } 454 } 455 456 /** 457 * A helping method for outputting the formatted contents of the bundle to a 458 * ouput Writer (such as a FileWriter). The method first outputs the header 459 * information and then outputs each bundle group's formatted data which includes 460 * each bundle item. 461 */ 462 writeContents(Writer w)463 public void writeContents(Writer w) throws IOException { 464 w.write(this.toOutputString() + "\n"); 465 Iterator iter = groups.iterator(); 466 while (iter.hasNext()) { 467 ((BundleGroup)iter.next()).writeContents(w); 468 } 469 } 470 }