1 10 package org.mmbase.util; 11 12 import java.util.*; 13 import java.io.*; 14 import org.w3c.dom.*; 15 import org.mmbase.bridge.*; 16 import org.mmbase.bridge.util.Queries; 17 import org.mmbase.bridge.util.xml.query.*; 18 import org.mmbase.util.xml.DocumentSerializable; 19 import org.mmbase.util.xml.DocumentReader; 20 import org.mmbase.util.logging.*; 21 22 43 public class LocalizedEntryListFactory implements Serializable, Cloneable { 44 45 private static final Logger log = Logging.getLoggerInstance(LocalizedEntryListFactory.class); 46 private static final long serialVersionUID = 1L; 48 private int size = 0; private boolean usesCloud = false; 50 51 private static class LocalizedEntry implements Serializable, PublicCloneable { 53 private static final long serialVersionUID = 1L; 54 ArrayList entries = new ArrayList(); ArrayList unusedKeys = new ArrayList(); public Object clone() { 57 try { 58 LocalizedEntry clone = (LocalizedEntry) super.clone(); 59 Iterator i = clone.entries.iterator(); 60 clone.entries = new ArrayList(); 61 while(i.hasNext()) { 62 clone.entries.add(((PublicCloneable)i.next()).clone()); 63 } 64 clone.unusedKeys = (ArrayList) unusedKeys.clone(); 65 return clone; 66 } catch (CloneNotSupportedException cnse) { 67 log.error(cnse); 68 return new LocalizedEntry(); 69 } 70 } 71 public String toString() { 72 return "entries:" + entries + "uu:" + unusedKeys; 73 } 74 } 75 private HashMap localized = new HashMap(); private ArrayList bundles = new ArrayList(); private ArrayList fallBack = new ArrayList(); 79 private DocumentSerializable xml = null; 80 81 public LocalizedEntryListFactory() { 82 localized.put(LocalizedString.getDefault(), new LocalizedEntry()); 83 } 84 85 86 87 public boolean isEmpty() { 88 return bundles.size() == 0 && fallBack.size() == 0 && !usesCloud; 89 } 90 91 95 public Map.Entry add(Locale locale, Serializable key, Serializable value) { 96 if (locale == null) { 97 locale = LocalizedString.getDefault(); 98 } 99 100 Entry entry = new Entry(key, value); 101 List unused = add(locale, entry); 102 if (! fallBack.contains(key)) { 103 size++; 105 fallBack.add(key); 106 Iterator i = localized.entrySet().iterator(); 107 while (i.hasNext()) { 108 Map.Entry e = (Map.Entry) i.next(); 109 if (! e.getKey().equals(locale)) { 110 LocalizedEntry loc = (LocalizedEntry) e.getValue(); 111 loc.unusedKeys.add(key); 112 } 113 } 114 } 115 unused.remove(key); 116 return entry; 117 } 118 119 125 126 protected List add(Locale locale, Object entry) { 127 if (locale == null) { 128 locale = LocalizedString.getDefault(); 129 } 130 LocalizedEntry local = (LocalizedEntry) localized.get(locale); 131 if (local == null) { 132 local = new LocalizedEntry(); 133 local.entries.addAll(bundles); 134 local.unusedKeys.addAll(fallBack); 135 localized.put(locale, local); 136 } 137 138 if (locale.getVariant() != null && !"".equals(locale.getVariant())) { 141 Locale l = new Locale(locale.getLanguage(), locale.getCountry()); 142 if (!localized.containsKey(l)) { 143 add(l, entry); 144 } 145 } 146 147 if (locale.getCountry() != null && !"".equals(locale.getCountry())) { 150 Locale l = new Locale(locale.getLanguage()); 151 if (!localized.containsKey(l)) { 152 add(l, entry); 153 } 154 } 155 local.entries.add(entry); 156 return local.unusedKeys; 157 } 158 159 164 public void addBundle(String baseName, ClassLoader classLoader, Class constantsProvider, Class wrapper, Comparator comparator) { 165 Bundle b = new Bundle(baseName, classLoader, SortedBundle.getConstantsProvider(constantsProvider), wrapper, comparator); 166 if (bundles.contains(b)) { 167 log.info("Adding bundle " + b + " for second time in " + b + ", because " + Logging.stackTrace()); 168 } 169 bundles.add(b); 170 Iterator i = localized.values().iterator(); 171 if (!i.hasNext()) { 172 Locale locale = LocalizedString.getDefault(); 174 LocalizedEntry local = new LocalizedEntry(); 175 local.entries.add(b); 176 local.unusedKeys.addAll(fallBack); 177 } else while(i.hasNext()) { 178 LocalizedEntry local = (LocalizedEntry) i.next(); 179 local.entries.add(b); 180 } 181 } 182 183 185 public void addQuery(Locale locale, Document queryElement) { 186 DocumentSerializable doc = new DocumentSerializable(queryElement); 187 add(locale, doc); 188 usesCloud = true; 189 } 190 191 192 195 public List get(final Locale locale) { 196 return get(locale, usesCloud ? getCloud(locale) : null); 197 } 198 199 protected Cloud getCloud(Locale locale) { 200 CloudContext context = ContextProvider.getDefaultCloudContext(); 201 if (context.isUp()) { 202 try { 203 Cloud cloud = context.getCloud("mmbase", "class", null); 204 if (locale != null) cloud.setLocale(locale); 205 return cloud; 206 } catch (SecurityException se) { 207 log.warn("" + se.getMessage()); 208 try { 209 Cloud cloud = context.getCloud("mmbase"); 210 if (locale != null && cloud != null) cloud.setLocale(locale); 211 return cloud; 212 } catch (SecurityException se2) { 213 return null; 214 } 215 } 216 } else { 217 return null; 218 } 219 } 220 221 231 public List get(final Locale locale, final Cloud cloud) { 232 return new AbstractSequentialList () { 233 234 public int size() { 235 return LocalizedEntryListFactory.this.size(cloud); 236 } 237 public ListIterator listIterator(final int index) { 238 return new ListIterator() { 239 int i = -1; 240 Locale useLocale = locale; 241 Cloud useCloud = cloud; 242 { 243 if (useLocale == null) { 244 useLocale = useCloud != null ? useCloud.getLocale() : LocalizedString.getDefault(); 245 } 246 log.debug("using locale " + useLocale); 247 } 248 private ChainedIterator iterator = new ChainedIterator(); 249 private Iterator subIterator = null; 250 private Map.Entry next = null; 251 252 { 253 LocalizedEntry loc = (LocalizedEntry) localized.get(useLocale); 254 if (loc == null) { 255 loc = (LocalizedEntry) localized.get(LocalizedString.getDefault()); 256 } 257 258 if (loc == null) { 259 iterator.addIterator(bundles.iterator()); 260 iterator.addIterator(fallBack.iterator()); 261 } else { 262 iterator.addIterator(loc.entries.iterator()); 263 iterator.addIterator(loc.unusedKeys.iterator()); 264 } 265 266 findNext(); 267 while (i < index) next(); 268 } 269 protected void findNext() { 270 next = null; 271 i++; 272 while(next == null && iterator.hasNext()) { 273 Object candidate = iterator.next(); 274 if (candidate instanceof Map.Entry) { 275 next = (Map.Entry) candidate; 276 } else if (candidate instanceof Bundle) { 277 subIterator = ((Bundle) candidate).get(useLocale).iterator(); 278 if (subIterator.hasNext()) { 279 break; 280 } else { 281 subIterator = null; 282 } 283 } else if (candidate instanceof DocumentSerializable) { 284 Element element = ((DocumentSerializable) candidate).getDocument().getDocumentElement(); 285 try { 286 if (useCloud == null) { 287 useCloud = getCloud(useLocale); 288 if (useCloud == null) { 289 if (log.isDebugEnabled()) { 290 log.debug("Defined query for " + this + " but no cloud provided. Skipping results."); 291 } 292 continue; 293 } 294 } 295 Query query = QueryReader.parseQuery(element, useCloud, null).query; 296 final org.mmbase.bridge.NodeList list = query.getList(); 297 subIterator = new Iterator() { 298 final NodeIterator nodeIterator = list.nodeIterator(); 299 public boolean hasNext() { 300 return nodeIterator.hasNext(); 301 } 302 public Object next() { 303 org.mmbase.bridge.Node next = nodeIterator.nextNode(); 304 return new Entry(next, next.getFunctionValue("gui", null)); 305 } 306 public void remove() { 307 throw new UnsupportedOperationException (); 308 } 309 }; 310 if (subIterator.hasNext()) { 311 break; 312 } else { 313 subIterator = null; 314 } 315 } catch (Exception e) { 316 log.error(e.getMessage(), e); 317 } 318 } else { 319 next = new Entry(candidate, candidate); 320 } 321 } 322 } 323 324 public boolean hasNext() { 325 return next != null || subIterator != null; 326 } 327 public Object next() { 328 Map.Entry res; 329 if (subIterator != null) { 330 res = (Map.Entry) subIterator.next(); 331 Object key = res.getKey(); 332 if (key != null && key instanceof SortedBundle.ValueWrapper) { 333 res = new Entry(((SortedBundle.ValueWrapper) key).getKey(), res.getValue()); 334 } 335 if (!subIterator.hasNext()) { 336 subIterator = null; 337 findNext(); 338 } 339 } else { 340 res = next; 341 findNext(); 342 } 343 return res; 344 } 345 public int nextIndex() { 346 return i; 347 } 348 public int previousIndex() { 349 return i - 1; 350 } 351 public boolean hasPrevious() { 352 throw new UnsupportedOperationException (); 354 } 355 public Object previous() { 356 throw new UnsupportedOperationException (); 358 } 359 361 362 public void remove() { 363 throw new UnsupportedOperationException (); 364 } 365 public void remove(int index) { 366 throw new UnsupportedOperationException (); 367 } 368 public void add(Object o) { 369 throw new UnsupportedOperationException (); 370 } 371 public void set(Object o) { 372 throw new UnsupportedOperationException (); 373 } 374 }; 375 } 376 }; 377 } 378 381 public int size(Cloud cloud) { 382 if (cloud == null) cloud = getCloud(LocalizedString.getDefault()); 383 int queriesSize = size(); 384 Locale locale = cloud == null ? LocalizedString.getDefault() : cloud.getLocale(); 385 LocalizedEntry localizedList = (LocalizedEntry) localized.get(locale); 386 if (localizedList == null) { 387 locale = LocalizedString.getDefault(); 388 localizedList = (LocalizedEntry) localized.get(locale); 389 } 390 if (localizedList != null) { 391 Iterator i = localizedList.entries.iterator(); 392 while (i.hasNext()) { 393 Object o = i.next(); 394 if (o instanceof Bundle) { 395 } else if (o instanceof DocumentSerializable) { 397 if (cloud == null) { 398 cloud = getCloud(null); 399 if (cloud == null) { 400 log.debug("Found query but didn't provide cloud, skipping"); 401 continue; 402 } 403 } 404 Element element = ((DocumentSerializable) o).getDocument().getDocumentElement(); 405 try { 406 queriesSize += Queries.count(QueryReader.parseQuery(element, cloud, null).query); 407 } catch (Exception e) { 408 log.warn(e); 409 } 410 } else { 411 queriesSize++; 412 } 413 } 414 } 416 417 return queriesSize; 418 } 419 420 public int size() { 421 int bundleSize = 0; 422 Iterator i = bundles.iterator(); 423 while (i.hasNext()) { 424 Bundle b = (Bundle) i.next(); 425 try { 426 bundleSize += b.get(null).size(); 427 } catch (MissingResourceException mre) { 428 log.error(mre); 429 } 430 } 431 return size + bundleSize; 432 } 433 434 public Object castKey(final Object key) { 435 return castKey(key, null); 436 } 437 442 public Object castKey(final Object key, final Cloud cloud) { 443 String string = null; 444 Iterator i = bundles.iterator(); 445 if (i.hasNext()) { 446 string = Casting.toString(key); 447 while (i.hasNext()) { 448 Bundle b = (Bundle) i.next(); 449 Class wrapper = b.wrapper; 450 HashMap constants = b.constantsProvider; 451 Object nk = SortedBundle.castKey(string, null, constants, wrapper); 452 if (string != nk) { 453 if (log.isDebugEnabled()) { 454 log.debug("Cast " + key + " to " + nk); 455 } 456 return nk; 457 } 458 } 459 } 460 if (usesCloud && cloud != null) { 461 if (string == null) string = Casting.toString(key); 462 if (cloud.hasNode(string)) { 463 return cloud.getNode(string); 464 } 465 } 466 return key; 467 468 } 469 470 public Object clone() { 471 try { 472 LocalizedEntryListFactory clone = (LocalizedEntryListFactory) super.clone(); 473 Iterator j = clone.bundles.iterator(); 474 clone.bundles = new ArrayList(); 475 while(j.hasNext()) { 476 clone.bundles.add(((PublicCloneable) j.next()).clone()); 477 } 478 Iterator i = clone.localized.entrySet().iterator(); 479 clone.localized = new HashMap(); 480 while(i.hasNext()) { 481 Map.Entry entry = (Map.Entry) i.next(); 482 clone.localized.put(entry.getKey(), ((PublicCloneable) entry.getValue()).clone()); 483 } 484 clone.fallBack = (ArrayList) fallBack.clone(); 485 return clone; 486 } catch (Exception e) { 487 log.error(e.getMessage(), e); 488 return new LocalizedEntryListFactory(); 489 } 490 } 491 492 495 public void clear() { 496 localized.clear(); 497 bundles.clear(); 498 fallBack.clear(); 499 usesCloud = false; 500 size = 0; 501 } 502 503 504 508 509 public void fillFromXml(final Element enumerationElement, Class wrapperDefault) { 510 xml = new DocumentSerializable(DocumentReader.toDocument(enumerationElement)); 511 org.w3c.dom.NodeList childNodes = enumerationElement.getElementsByTagName("query"); 512 for (int i = 0; i < childNodes.getLength(); i++) { 513 Element queryElement = (Element) childNodes.item(i); 514 Locale locale = LocalizedString.getLocale(queryElement); 515 addQuery(locale, DocumentReader.toDocument(queryElement)); 516 } 517 518 519 childNodes = enumerationElement.getElementsByTagName("entry"); 520 for (int i = 0; i < childNodes.getLength(); i++) { 521 Element entryElement = (Element) childNodes.item(i); 522 if (entryElement.hasAttribute("value")) { 523 String value = entryElement.getAttribute("value"); 524 Locale locale = LocalizedString.getLocale(entryElement); 525 String display = entryElement.getAttribute("display"); 526 if (display.equals("")) display = value; 527 Object key = wrapperDefault != null ? Casting.toType(wrapperDefault, null, value) : value; 528 if (key instanceof java.io.Serializable ) { 529 log.debug("Added " + key + "/" + display + " for " + locale); 530 add(locale, (java.io.Serializable ) key, display); 531 } else { 532 log.error("key " + key + " for " + wrapperDefault + " is not serializable, cannot be added to entrylist factory."); 533 } 534 } else { 535 String resource = entryElement.getAttribute("basename"); 536 if (! resource.equals("")) { 537 Comparator comparator = null; 538 Class wrapper = wrapperDefault; 539 if (wrapper != null && 540 (! Comparable .class.isAssignableFrom(wrapper)) && 541 (! Boolean .class.equals(wrapper)) ) { 543 wrapper = null; 544 } 545 546 { 547 String sorterClass = entryElement.getAttribute("sorterclass"); 548 if (!sorterClass.equals("")) { 549 try { 550 Class sorter = Class.forName(sorterClass); 551 if (Comparator.class.isAssignableFrom(sorter)) { 552 comparator = (Comparator) sorter.newInstance(); 553 } else { 554 wrapper = sorter; 555 } 556 } catch (Exception e) { 557 log.error(e); 558 } 559 } 560 } 561 Class constantsClass = null; 562 { 563 String javaConstants = entryElement.getAttribute("javaconstants"); 564 if (!javaConstants.equals("")) { 565 try { 566 constantsClass = Class.forName(javaConstants); 567 } catch (Exception e) { 568 log.error(e); 569 } 570 } 571 } 572 try { 573 addBundle(resource, getClass().getClassLoader(), constantsClass, 574 wrapper, comparator); 575 } catch (MissingResourceException mre) { 576 log.error(mre); 577 } 578 } else { 579 throw new IllegalArgumentException ("no 'value' or 'basename' attribute on enumeration entry element"); 580 } 581 } 582 if (log.isDebugEnabled()) { 583 log.debug("Found enumeration values now " + this); 584 } 585 } 586 587 } 588 public Element toXml() { 589 if (xml == null) { 590 return null; 592 } else { 593 return xml.getDocument().getDocumentElement(); 594 } 595 } 596 597 public String toString() { 598 return "(localized: " + localized + "bundles: " + bundles + "fallBack: " + fallBack + ")"; 599 } 600 601 private static class Bundle implements Serializable, PublicCloneable { 602 private static final long serialVersionUID = 1L; 604 private String resource; 605 private ClassLoader classLoader; 606 private HashMap constantsProvider; 607 private Class wrapper; 608 private Comparator comparator; 609 610 private void writeObject(ObjectOutputStream out) throws IOException { 612 out.writeUTF(resource); 613 out.writeObject(constantsProvider); 615 out.writeObject(wrapper); 616 if (comparator instanceof Serializable) { 617 out.writeObject(comparator); 618 } else { 619 out.writeObject((Comparator) null); 620 } 621 } 622 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 624 resource = in.readUTF(); 625 classLoader = getClass().getClassLoader(); 626 constantsProvider = (HashMap) in.readObject(); 627 wrapper = (Class ) in.readObject(); 628 comparator = (Comparator) in.readObject(); 629 } 630 631 632 633 Bundle(String r, ClassLoader cl, HashMap cp, Class w, Comparator comp) { 634 resource = r; classLoader = cl; constantsProvider = cp ; wrapper = w; comparator = comp; 635 } 636 639 Collection get(Locale loc) throws MissingResourceException { 640 try { 641 return SortedBundle.getResource(resource, loc, classLoader, constantsProvider, wrapper, comparator).entrySet(); 642 } catch (IllegalArgumentException iae) { 643 log.error(iae); 644 return Collections.EMPTY_LIST; 645 } 646 } 647 648 649 public String toString() { 650 return resource + " " + constantsProvider + " " + wrapper + " " + comparator; 651 } 652 public boolean equals(Object o) { 653 if (o instanceof Bundle) { 654 Bundle b = (Bundle) o; 655 return 656 (resource == null ? b.resource == null : resource.equals(b.resource)) && 657 (classLoader == null ? b.classLoader == null : classLoader.equals(b.classLoader)) && 658 (constantsProvider == null ? b.constantsProvider == null : constantsProvider.equals(b.constantsProvider)) && 659 (wrapper == null ? b.wrapper == null : wrapper.equals(b.wrapper)) && 660 (comparator == null ? b.comparator == null : comparator.equals(b.comparator)); 661 662 } else { 663 return false; 664 } 665 } 666 public int hashCode() { 667 int result = 0; 668 result = HashCodeUtil.hashCode(result, resource); 669 result = HashCodeUtil.hashCode(result, classLoader); 670 result = HashCodeUtil.hashCode(result, constantsProvider); 671 result = HashCodeUtil.hashCode(result, wrapper); 672 result = HashCodeUtil.hashCode(result, comparator); 673 return result; 674 } 675 676 public Object clone() { 677 log.debug("Cloning bundle " + this); 678 try { 679 Bundle clone = (Bundle) super.clone(); 680 clone.constantsProvider = constantsProvider != null ? (HashMap) constantsProvider.clone() : null; 681 return clone; 682 } catch (Exception e) { 683 log.error(e.getMessage(), e); 684 return this; 685 } 686 } 687 688 } 689 690 693 public static void main(String argv[]) { 694 LocalizedEntryListFactory fact = new LocalizedEntryListFactory(); 695 String resource1 = "org.mmbase.datatypes.resources.boolean.onoff"; 696 String resource2 = "org.mmbase.datatypes.resources.boolean.yesno"; 697 Locale nl = new Locale("nl"); 698 Locale en = new Locale("en"); 699 Locale dk = new Locale("dk"); 700 Locale eo = new Locale("eo"); 701 fact.add(nl, "a", "hallo"); 702 System.out.println("nou " + fact); 703 fact.add(new Locale("nl"), "b", "daag"); 704 fact.add(en, "b", "hello"); 705 fact.add(en, "a", "good bye"); 706 fact.addBundle(resource1, null, null, Boolean .class, SortedBundle.NO_COMPARATOR); 707 fact.add(nl, "c", "doegg"); 708 fact.add(dk, new Integer (5), "dk"); 709 fact.add(null, "e", "oi"); 710 fact.addBundle(resource2, null, null, String .class, SortedBundle.NO_COMPARATOR); 711 712 System.out.println("size: " + fact.size() + " " + fact); 713 System.out.println("en" + fact.get(en)); 714 System.out.println("nl" + fact.get(nl)); 715 System.out.println("dk" + fact.get(dk)); 716 System.out.println("eo" + fact.get(eo)); 717 718 LocalizedEntryListFactory fact2 = new LocalizedEntryListFactory(); 719 fact2.addBundle("org.mmbase.datatypes.resources.states", null, org.mmbase.module.builders.MMServers.class, SortedBundle.NO_WRAPPER, SortedBundle.NO_COMPARATOR); 720 721 System.out.println("size: " + fact2.size()); 722 System.out.println("" + fact2.get(en)); 723 System.out.println("" + fact2.get(nl)); 724 Object error = fact2.castKey("ERROR", null); 725 System.out.println("ERROR=" + error.getClass().getName() + " " + error); 726 727 728 } 729 730 } 731 | Popular Tags |