1 55 package org.lateralnz.common.util; 56 57 import java.io.File ; 58 import java.io.IOException ; 59 import java.io.FilenameFilter ; 60 import java.util.Arrays ; 61 import java.util.Comparator ; 62 import java.util.HashMap ; 63 import java.util.Iterator ; 64 import java.util.Locale ; 65 import java.util.Map ; 66 import java.util.MissingResourceException ; 67 import java.util.regex.*; 68 69 import org.apache.log4j.Logger; 70 import org.w3c.dom.Document ; 71 import org.w3c.dom.Node ; 72 import org.w3c.dom.NodeList ; 73 74 import org.lateralnz.common.util.StringUtils; 75 import org.lateralnz.common.util.XMLUtils; 76 77 89 public class MVResourceBundle implements Constants { 90 private static final Logger log = Logger.getLogger(MVResourceBundle.class.getName()); 91 private static final String BRANCH = "branch"; 92 private static final String CLASSNAME = MVResourceBundle.class.getName(); 93 private static final String DOT_XML = ".xml"; 94 private static final String NAME = "name"; 95 private static final String PATTERN_SUFFIX = "_?.*\\.xml"; 96 private static final String PROPERTY = "property"; 97 private static final String PROPERTIES_NODE = "properties"; 98 99 private static final Pattern PROPS_PATTERN = Pattern.compile("(\\$\\{[^}]*\\})"); 100 101 private static HashMap resourceBundles = new HashMap (); 102 static { 103 ObjRefUtils.getInstance().add(resourceBundles); 104 } 105 106 private static final Comparator rbcomp = new Comparator () { 107 public int compare(Object o1, Object o2) { 108 String s1 = (String )o1; 109 String s2 = (String )o2; 110 111 int tok1 = StringUtils.countOccurrences(s1, '_'); 112 int tok2 = StringUtils.countOccurrences(s2, '_'); 113 114 if (tok1 == tok2) { 115 return 0; 116 } 117 else if (tok1 < tok2) { 118 return -1; 119 } 120 else { 121 return 1; 122 } 123 } 124 125 public boolean equals(Object o1, Object o2) { 126 String s1 = (String )o1; 127 String s2 = (String )o2; 128 return s1.equals(s2); 129 } 130 }; 131 132 protected HashMap props = null; 133 protected Locale thislocale = null; 134 private String dir; 135 private String name; 136 private String thisname; 137 private HashMap bundles; 138 139 private MVResourceBundle(HashMap bundles, String dir, String name, String thisname) throws MissingResourceException { 140 this.dir = dir; 141 this.name = name; 142 this.thisname = thisname; 143 int pos = name.length()+1; 147 if (pos >= thisname.length()) { 148 this.thislocale = Locale.getDefault(); 149 } 150 else { 151 this.thislocale = LocaleUtils.getLocale(thisname.substring(pos)); 152 } 153 this.bundles = bundles; 154 155 init(); 156 } 157 158 private void init() throws MissingResourceException { 159 try { 160 if (log.isInfoEnabled()) { 161 log.info("initing " + StringUtils.toDirectory(dir) + thisname + DOT_XML); 162 } 163 HashMap newprops = getParentProps(bundles, thisname); 164 165 String xml = StringUtils.readFromFile(StringUtils.toDirectory(dir) + thisname + DOT_XML); 166 Document doc = XMLUtils.parse(XMLUtils.preprocess(xml)); 167 168 Node n = doc.getFirstChild(); 169 NodeList nl = doc.getChildNodes(); 170 NodeList nl2 = null; 171 for (int i = 0; i < nl.getLength(); i++) { 172 Node n2 = nl.item(i); 173 if (n2.getNodeName().equals(PROPERTIES_NODE)) { 174 nl2 = n2.getChildNodes(); 175 break; 176 } 177 } 178 if (nl2 == null) { 179 throw new Exception ("invalid property file"); 180 } 181 182 parse(EMPTY, newprops, nl2); 183 184 this.props = newprops; 185 } 186 catch (Exception e) { 187 e.printStackTrace(); 188 throw new MissingResourceException (e.getMessage(), CLASSNAME, ""); 189 } 190 191 } 192 193 198 private void parse(String branch, HashMap hm, NodeList nl) throws Exception { 199 for (int i = 0; i < nl.getLength(); i++) { 200 Node n = nl.item(i); 201 String name = XMLUtils.getAttributeValue(n, NAME, EMPTY); 202 if (StringUtils.isEmpty(name)) { 203 continue; 204 } 205 else if (n.getNodeName().equals(PROPERTY)) { 206 String val; 207 if (n.getFirstChild() != null) { 208 val = n.getFirstChild().getNodeValue(); 209 } 210 else { 211 val = n.getNodeValue(); 212 } 213 214 if (!StringUtils.isEmpty(val) && val.indexOf("${") >= 0) { 215 Matcher mat = PROPS_PATTERN.matcher(val); 216 217 StringBuffer sb = new StringBuffer (); 218 while (mat.find()) { 219 String match = mat.group(1).substring(2, mat.group(1).length()-1); 220 String prop = System.getProperty(match, EMPTY); 221 if (StringUtils.isEmpty(prop)) { 222 throw new Exception ("missing system property " + match); 223 } 224 mat.appendReplacement(sb, prop); 225 } 226 mat.appendTail(sb); 227 val = sb.toString(); 228 } 229 hm.put(branch + name, val); 230 } 231 else if (n.getNodeName().equals(BRANCH)) { 232 parse(branch + name + FORWARD_SLASH, hm, n.getChildNodes()); 233 } 234 } 235 } 236 237 240 public static final MVResourceBundle getBundle(String dir, String name) throws MissingResourceException { 241 return getBundle(dir, name, null); 242 } 243 244 public static final MVResourceBundle getBundle(String dir, String name, Locale locale) throws MissingResourceException { 245 return getBundle(dir, name, EMPTY, locale); 246 } 247 248 252 public static final MVResourceBundle getBundle(String dir, String name, String prevariant, Locale locale) throws MissingResourceException { 253 if (log.isDebugEnabled()) { 254 log.debug("getBundle " + dir + ", " + name + ", " + prevariant + ", " + locale); 255 } 256 257 File f = new File (dir); 258 try { 259 dir = f.getCanonicalPath(); 260 } 261 catch (IOException ioe) { 262 log.error(ioe); 263 } 264 265 String mainkey = dir + FORWARD_SLASH + name; 266 if (!resourceBundles.containsKey(mainkey)) { 267 reload(dir, name); 268 } 269 270 HashMap hm = (HashMap )resourceBundles.get(mainkey); 271 if (hm != null) { 272 String key = name; 273 if (!StringUtils.isEmpty(prevariant)) { 274 key = key + UNDERSCORE + prevariant; 275 276 if (locale != null) { 277 key = key + UNDERSCORE + locale.getLanguage() + UNDERSCORE + locale.getCountry() + UNDERSCORE + locale.getVariant(); 278 } 279 } 280 281 if (hm.containsKey(key)) { 282 return (MVResourceBundle)hm.get(key); 283 } 284 else { 285 String [] split = key.split(UNDERSCORE); 286 for (int i = 0, j = split.length-1; i < split.length; i++, j--) { 287 key = StringUtils.fromArray(split, UNDERSCORE, 0, j); 288 if (hm.containsKey(key)) { 289 if (log.isDebugEnabled()) { 290 log.debug("found resources for " + key); 291 } 292 return (MVResourceBundle)hm.get(key); 293 } 294 } 295 if (hm.containsKey(name)) { 296 if (log.isDebugEnabled()) { 297 log.debug("no localised bundle, returning default for " + name); 298 } 299 return (MVResourceBundle)hm.get(name); 300 } 301 } 302 } 303 throw new MissingResourceException ("no such bundle " + dir + FORWARD_SLASH + name, CLASSNAME, EMPTY); 304 } 305 306 309 private static final void reload(String dir, String name) throws MissingResourceException { 310 final String pat = name + PATTERN_SUFFIX; 311 FilenameFilter filter = new FilenameFilter () { 312 public boolean accept(File f, String fname) { 313 if (StringUtils.matches(fname, pat)) { 314 return true; 315 } 316 else { 317 return false; 318 } 319 } 320 }; 321 322 File d = new File (dir); 323 if (d.exists() && d.isDirectory()) { 324 String [] list = d.list(filter); 325 326 Arrays.sort(list, rbcomp); 329 330 if (list != null && list.length > 0) { 331 String key = dir + FORWARD_SLASH + name; 332 HashMap bundles; 333 if (!resourceBundles.containsKey(key)) { 334 synchronized (resourceBundles) { 335 if (!resourceBundles.containsKey(key)) { 336 bundles = new HashMap (); 337 resourceBundles.put(key, bundles); 338 } 339 } 340 } 341 bundles = (HashMap )resourceBundles.get(key); 342 343 synchronized (bundles) { 344 for (int i = 0; i < list.length; i++) { 345 String bkey = list[i].substring(0, list[i].length()-4); 346 if (!bundles.containsKey(bkey)) { 347 MVResourceBundle mvrb = new MVResourceBundle(bundles, dir, name, bkey); 348 bundles.put(bkey, mvrb); 349 } 350 else { 351 MVResourceBundle mvrb = (MVResourceBundle)bundles.get(bkey); 352 mvrb.init(); 353 } 354 } 355 } 356 } 357 } 358 else { 359 throw new MissingResourceException ("invalid resource bundle " + dir + FORWARD_SLASH + name, CLASSNAME, EMPTY); 360 } 361 } 362 363 private static final HashMap getParentProps(HashMap bundles, String thisname) { 364 if (StringUtils.countOccurrences(thisname, '_') < 1) { 365 return new HashMap (); 366 } 367 else { 368 String [] split = thisname.split(UNDERSCORE); 371 for (int i = 0, j = split.length-1; i < split.length; i++, j--) { 372 String key = StringUtils.fromArray(split, UNDERSCORE, 0, j); 373 if (bundles.containsKey(key)) { 374 MVResourceBundle mvrb = (MVResourceBundle)bundles.get(key); 375 return (HashMap )mvrb.props.clone(); 376 } 377 } 378 return new HashMap (); 379 } 380 } 381 382 385 public final void reload() throws Exception { 386 reload(dir, name); 387 } 388 389 public final boolean contains(String name) { 390 return props.containsKey(name); 391 } 392 393 public final String formatString(String name, Object [] args) { 394 String s = getString(name); 395 if (!StringUtils.isEmpty(s)) { 396 return StringUtils.format(s, args); 397 } 398 else { 399 return s; 400 } 401 } 402 403 public final Locale getLocale() { 404 return thislocale; 405 } 406 407 public final String getString(String name) { 408 return getString(name, true); 409 } 410 411 public final String getString(String name, boolean throwerror) { 412 if (props.containsKey(name)) { 413 return (String )props.get(name); 414 } 415 else if (throwerror) { 416 throw new MissingResourceException ("no such resource '" + name + "'", CLASSNAME, name); 417 } 418 else { 419 return EMPTY; 420 } 421 } 422 423 426 public final Map getBranchAsMap(String branch) { 427 if (!branch.endsWith(FORWARD_SLASH)) { 428 branch = branch + FORWARD_SLASH; 429 } 430 int len = branch.length(); 431 HashMap copy = (HashMap )props.clone(); 432 Iterator iter = copy.keySet().iterator(); 433 HashMap rtn = new HashMap (); 434 while (iter.hasNext()) { 435 String key = (String )iter.next(); 436 if (key.startsWith(branch)) { 437 rtn.put(key.substring(len), copy.get(key)); 438 } 439 } 440 return rtn; 441 } 442 443 } 444 | Popular Tags |