001: /*
002: *****************************************************************************
003: * Copyright (C) 2000-2004, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *****************************************************************************
006: */
007: package com.ibm.rbm;
008:
009: import java.io.IOException;
010: import java.io.PrintStream;
011: import java.io.Writer;
012: import java.util.*;
013:
014: import com.ibm.rbm.gui.RBManagerGUI;
015:
016: /**
017: * A class representing the entire Bundle of Resources for a particular language, country, variant.
018: *
019: * @author Jared Jackson
020: * @see com.ibm.rbm.RBManager
021: */
022: public class Bundle {
023:
024: /**
025: * The following public class variables reflect the various properties that can be included as
026: * meta-data in a resource bundle formatted by RBManager
027: */
028: public String name;
029: /**
030: * The encoding of the bundle (e.g. 'en', 'en_US', 'de', etc.)
031: */
032: public String encoding;
033: /**
034: * A descriptor of the language in the encoding (e.g. English, German, etc.)
035: */
036: public String language;
037: /**
038: * A descriptor of the country in the encoding (e.g. US, Canada, Great Britain)
039: */
040: public String country;
041: /**
042: * The descriptor of the variant in the encoding (e.g. Euro, Irish, etc.)
043: */
044: public String variant;
045: /**
046: * A comment concerning the bundle
047: */
048: public String comment;
049: /**
050: * The name of the person responsible for the managerment of this bundle
051: */
052: public String manager;
053:
054: private TreeSet groups; // A vector of groups of NLS items, the key is the group name
055:
056: /**
057: * A hashtable of all of the items in the bundle, hashed according to their
058: * NLS key.
059: */
060:
061: public Hashtable allItems; // A hashtable of all items in the file, the key is the NLS key
062:
063: private TreeSet untranslatedItems; // A vector of all items which are untranslated
064:
065: /**
066: * A vector containing all of the items which are duplicates (based on the NLS keys)
067: * of items previously declared in the bundle.
068: */
069:
070: public Vector duplicates; // A vector of items which are duplicates (NLS Keys) of previous items
071:
072: /**
073: * Constructor for creating an empty bundle with a given encoding
074: */
075:
076: public Bundle(String encoding) {
077: this .encoding = encoding;
078: language = null;
079: country = null;
080: variant = null;
081: comment = null;
082: manager = null;
083: groups = new TreeSet(new Comparator() {
084: public boolean equals(Object o) {
085: return false;
086: }
087:
088: public int compare(Object o1, Object o2) {
089: if (!(o1 instanceof BundleGroup)
090: || !(o2 instanceof BundleGroup))
091: return 0;
092: BundleGroup g1 = (BundleGroup) o1;
093: BundleGroup g2 = (BundleGroup) o2;
094: return g1.getName().compareTo(g2.getName());
095: }
096: });
097:
098: untranslatedItems = new TreeSet(new Comparator() {
099: public boolean equals(Object o) {
100: return false;
101: }
102:
103: public int compare(Object o1, Object o2) {
104: if (!(o1 instanceof BundleItem)
105: || !(o2 instanceof BundleItem))
106: return 0;
107: BundleItem i1 = (BundleItem) o1;
108: BundleItem i2 = (BundleItem) o2;
109: return i1.getKey().compareTo(i2.getKey());
110: }
111: });
112:
113: duplicates = new Vector();
114: allItems = new Hashtable();
115: }
116:
117: /**
118: * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern").
119: * This method returns the language encoding string, or null if it is not specified
120: */
121:
122: public String getLanguageEncoding() {
123: if (encoding == null)
124: return null;
125: if (encoding.indexOf("_") >= 0)
126: return encoding.substring(0, encoding.indexOf("_"));
127: return encoding.trim();
128: }
129:
130: /**
131: * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern").
132: * This method returns the country encoding string, or null if it is not specified
133: */
134:
135: public String getCountryEncoding() {
136: if (encoding == null || encoding.indexOf("_") < 0)
137: return null;
138: // Strip off the language
139: String workStr = encoding.substring(encoding.indexOf("_") + 1,
140: encoding.length());
141: if (workStr.indexOf("_") >= 0)
142: return workStr.substring(0, encoding.indexOf("_"));
143: return workStr.trim();
144: }
145:
146: /**
147: * Encodings are of the form -> language_country_variant <- (for example: "en_us_southern").
148: * This method returns the variant encoding string, or null if it is not specified
149: */
150:
151: public String getVariantEncoding() {
152: if (encoding == null || encoding.indexOf("_") < 0)
153: return null;
154: // Strip off the language
155: String workStr = encoding.substring(encoding.indexOf("_") + 1,
156: encoding.length());
157: if (workStr == null || workStr.length() < 1
158: || workStr.indexOf("_") < 0)
159: return null;
160: // Strip off the country
161: workStr = workStr.substring(encoding.indexOf("_") + 1, workStr
162: .length());
163: return workStr.trim();
164: }
165:
166: /**
167: * Returns the UntranslatedItems as a vector. I should find where this happens and stop it.
168: */
169:
170: public Vector getUntranslatedItemsAsVector() {
171: Iterator iter = untranslatedItems.iterator();
172: Vector v = new Vector();
173: while (iter.hasNext())
174: v.addElement(iter.next());
175: return v;
176: }
177:
178: /**
179: * Checks all items in the untranslated items set. If they belong to a group whose name
180: * matches the passed in name, then they are removed.
181: */
182:
183: public void removeUntranslatedItemsByGroup(String groupName) {
184: Iterator iter = untranslatedItems.iterator();
185: try {
186: while (iter.hasNext()) {
187: BundleItem item = null;
188: item = (BundleItem) iter.next();
189: if (item != null
190: && item.getParentGroup().getName().equals(
191: groupName)) {
192: removeUntranslatedItem(item.getKey());
193: }
194: }
195: } catch (Exception e) {
196: RBManagerGUI.debugMsg(e.getMessage());
197: }
198: }
199:
200: /**
201: * Checks to see if an item of the given key name exists in the set of untranslated items. If
202: * it does exist, then it is removed.
203: */
204:
205: public void removeUntranslatedItem(String name) {
206: Iterator iter = untranslatedItems.iterator();
207: while (iter.hasNext()) {
208: BundleItem item = (BundleItem) iter.next();
209: if (item.getKey().equals(name)) {
210: untranslatedItems.remove(item);
211: break;
212: }
213: }
214: }
215:
216: /**
217: * Returns the boolean of wether a group of a given name exists in the bundle
218: */
219:
220: public boolean hasGroup(String groupName) {
221: Iterator iter = groups.iterator();
222: while (iter.hasNext()) {
223: BundleGroup group = (BundleGroup) iter.next();
224: if (group.getName().equals(groupName))
225: return true;
226: }
227: return false;
228: }
229:
230: /**
231: * Creates a group of the given name and optionally associates a comment with
232: * that group.
233: */
234:
235: public void addBundleGroup(String groupName, String groupComment) {
236: BundleGroup bg = new BundleGroup(this , groupName);
237: bg.setComment(groupComment);
238: addBundleGroup(bg);
239: }
240:
241: /**
242: * Removes the group of the given name if it exists in the bundle
243: */
244:
245: public void removeGroup(String groupName) {
246: Iterator iter = groups.iterator();
247: while (iter.hasNext()) {
248: BundleGroup tempGroup = (BundleGroup)iter.next();
249: if (tempGroup.getName().equals(groupName)) {
250: groups.remove(tempGroup);
251: break;
252: }
253: }
254: // Remove the items from the untanslated items
255: removeUntranslatedItemsByGroup(groupName);
256:
257: // Loop through all Items
258: Enumeration enum = allItems.elements();
259: while(enum.hasMoreElements()) {
260: BundleItem item = (BundleItem)enum.nextElement();
261: if (item.getParentGroup().getName().equals(groupName)) {
262: allItems.remove(item);
263: }
264: }
265: }
266:
267: /**
268: * Removes a single resource item from the bundle
269: */
270:
271: public void removeItem(String key) {
272: Object o = allItems.get(key);
273: if (o != null) {
274: BundleItem item = (BundleItem) o;
275: // Remove from allItems Hashtable
276: allItems.remove(key);
277: // Remove from item's group
278: if (item.getParentGroup() != null) {
279: BundleGroup group = item.getParentGroup();
280: group.removeBundleItem(key);
281: }
282: // Remove from untranslatedItems Hashtable
283: removeUntranslatedItem(key);
284: }
285: }
286:
287: /**
288: * Attempts to add a BundleItem to the untranslatedItems. The addition will fail in two cases: One, if
289: * the item does not all ready belong to this Bundle, and Two, if the item is all ready in the set of
290: * untranslated items.
291: */
292:
293: public void addUntranslatedItem(BundleItem item) {
294: if (item.getParentGroup().getParentBundle() != this )
295: return;
296: // Remove it if it exists.
297: if (untranslatedItems.contains(item)) {
298: untranslatedItems.remove(item);
299: }
300: untranslatedItems.add(item);
301: }
302:
303: /**
304: * Returns the number of items currently marked as untranslated
305: */
306:
307: public int getUntranslatedItemsSize() {
308: return untranslatedItems.size();
309: }
310:
311: /**
312: * Returns the indexth untranslated item
313: */
314:
315: public BundleItem getUntranslatedItem(int index) {
316: if (index >= untranslatedItems.size())
317: return null;
318: Iterator iter = untranslatedItems.iterator();
319: for (int i = 0; i < index; i++)
320: iter.next();
321: return (BundleItem) iter.next();
322: }
323:
324: /**
325: * Return the various resource bundle groups stored in a Vector collection.
326: */
327:
328: public Vector getGroupsAsVector() {
329: Vector v = new Vector();
330: Iterator iter = groups.iterator();
331: while (iter.hasNext()) {
332: BundleGroup group = (BundleGroup) iter.next();
333: v.addElement(group);
334: }
335: return v;
336: }
337:
338: /**
339: * Returns the number of groups in the bundle.
340: */
341:
342: public int getGroupCount() {
343: return groups.size();
344: }
345:
346: /**
347: * Returns a bundle group given a certain index.
348: */
349:
350: public BundleGroup getBundleGroup(int index) {
351: if (index >= getGroupCount())
352: return null;
353: Iterator iter = groups.iterator();
354: for (int i = 0; i < index; i++)
355: iter.next();
356: return (BundleGroup) iter.next();
357: }
358:
359: /**
360: * Looks for a bundle group of a given name within a bundle and
361: * returns it if found.
362: */
363:
364: public BundleGroup getBundleGroup(String groupName) {
365: Iterator iter = groups.iterator();
366: while (iter.hasNext()) {
367: BundleGroup group = (BundleGroup) iter.next();
368: if (group.getName().equals(groupName))
369: return group;
370: }
371: return null;
372: }
373:
374: /**
375: * Looks up and returns a bundle item stored in the bundle based on its
376: * NLS lookup key.
377: */
378:
379: public BundleItem getBundleItem(String key) {
380: return (BundleItem) allItems.get(key);
381: }
382:
383: /**
384: * One group is created for all bundles called 'Ungrouped Items'. This is the bundle
385: * group in which bundle items are placed that are not specifically grouped in the
386: * resource bundle file. This method returns that bundle group.
387: */
388:
389: public BundleGroup getUngroupedGroup() {
390: return getBundleGroup("Ungrouped Items");
391: }
392:
393: /**
394: * Add a bundle group to the bundle
395: */
396:
397: public void addBundleGroup(BundleGroup bg) {
398: groups.add(bg);
399: }
400:
401: /**
402: * Add a bundle item to the bundle. This bundle item should all ready have its
403: * bundle group assigned.
404: */
405:
406: public void addBundleItem(BundleItem item) {
407: if (allItems.containsKey(item.getKey())) {
408: duplicates.addElement(item);
409: } else {
410: if (!(groups.contains(item.getParentGroup())))
411: addBundleGroup(item.getParentGroup());
412: item.getParentGroup().addBundleItem(item);
413: allItems.put(item.getKey(), item);
414: removeUntranslatedItem(item.getKey());
415: if (!item.isTranslated())
416: addUntranslatedItem(item);
417: }
418: }
419:
420: /**
421: * A method useful in debugging. The string returned displays the encoding
422: * information about the bundle and wether or not it is the base class of
423: * a resource bundle.
424: */
425:
426: public String toString() {
427: String retStr = new String();
428: if (language != null && !language.equals(""))
429: retStr = language;
430: if (country != null && !country.equals(""))
431: retStr += ", " + country;
432: if (variant != null && !variant.equals(""))
433: retStr += ", " + variant;
434:
435: retStr += " ("
436: + (encoding == null || encoding.equals("") ? "Base Class"
437: : encoding) + ")";
438: return retStr;
439: }
440:
441: /**
442: * This method produces a String which is suitable for inclusion in a .properties
443: * style resource bundle. It attaches (in comments) the meta data that RBManager
444: * reads to manage the resource bundle file. This portion of the output should
445: * be included at the beginning of the resource bundle file.
446: */
447:
448: public String toOutputString() {
449: String retStr = "# @file " + name + "\n";
450: if (encoding != null)
451: retStr += "# @fileEncoding " + encoding + "\n";
452: if (language != null)
453: retStr += "# @fileLanguage " + language + "\n";
454: if (country != null)
455: retStr += "# @fileCountry " + country + "\n";
456: if (variant != null)
457: retStr += "# @fileVariant " + variant + "\n";
458: if (manager != null)
459: retStr += "# @fileManager " + manager + "\n";
460: if (comment != null)
461: retStr += "# @fileComment " + comment + "\n";
462: return retStr;
463: }
464:
465: /**
466: * A helping method for outputting the formatted contents of the bundle to a
467: * print stream. The method first outputs the header information and then outputs
468: * each bundle group's formatted data which includes each bundle item.
469: */
470:
471: public void writeContents(PrintStream ps) {
472: ps.println(this .toOutputString());
473: Iterator iter = groups.iterator();
474: while (iter.hasNext()) {
475: ((BundleGroup) iter.next()).writeContents(ps);
476: }
477: }
478:
479: /**
480: * A helping method for outputting the formatted contents of the bundle to a
481: * ouput Writer (such as a FileWriter). The method first outputs the header
482: * information and then outputs each bundle group's formatted data which includes
483: * each bundle item.
484: */
485:
486: public void writeContents(Writer w) throws IOException {
487: w.write(this .toOutputString() + "\n");
488: Iterator iter = groups.iterator();
489: while (iter.hasNext()) {
490: ((BundleGroup) iter.next()).writeContents(w);
491: }
492: }
493: }
|