001package com.hammurapi.common.concurrent; 002 003import java.util.Arrays; 004import java.util.HashSet; 005import java.util.Map; 006import java.util.Set; 007import java.util.concurrent.Callable; 008import java.util.concurrent.ExecutorService; 009import java.util.concurrent.Future; 010import java.util.concurrent.ScheduledExecutorService; 011import java.util.concurrent.TimeUnit; 012import java.util.concurrent.locks.ReadWriteLock; 013 014import com.hammurapi.common.Context; 015import com.hammurapi.convert.Converter; 016import com.hammurapi.convert.ConvertingService; 017 018/** 019 * 020 * @author Pavel Vlasov 021 * 022 * @param <KP> Key path 023 * @param <KE> Key path element 024 */ 025public abstract class AbstractPropertySet<KP,KE> implements PropertySet<KP>, ReadWriteLock { 026 027 protected Converter converter; 028 protected ExecutorService executorService; 029 protected PropertySet<KP>[] shadows; 030// protected ClassLoader classLoader; 031 protected Context context; 032 033 private PropertySet<KP> shadowPropertySet = new PropertySet<KP>() { 034 035 @Override 036 public <T> T getAdapter(Class<T> type, Context context) { 037 throw new UnsupportedOperationException(); // Maybe implement. 038 } 039 040 @Override 041 public Set<KP> keySet() { 042 HashSet<KP> ret = new HashSet<KP>(); 043 044 for (PropertySet<KP> ch: shadows) { 045 if (ch!=null) { 046 ret.addAll(ch.keySet()); 047 } 048 } 049 return ret; 050 } 051 052 @Override 053 public PropertySet<KP> subset(KP prefix) { 054 return new AbstractSubSet<KP>(this, prefix) { 055 056 @Override 057 protected KP buildPath(KP prefix, KP key) { 058 return AbstractPropertySet.this.buildPath(prefix, key); 059 } 060 061 }; 062 } 063 064 @Override 065 public void remove(KP key) { 066 throw new UnsupportedOperationException(); 067 } 068 069 @Override 070 public void clear() { 071 throw new UnsupportedOperationException(); 072 } 073 074 @Override 075 public void mount(KP prefix, PropertySet<KP> source) { 076 throw new UnsupportedOperationException(); 077 } 078 079 @Override 080 public void unmount(KP prefix) { 081 throw new UnsupportedOperationException(); 082 } 083 084 @Override 085 public void setAll(PropertySet<KP> source) { 086 throw new UnsupportedOperationException(); 087 } 088 089 @Override 090 public Object get(KP key) { 091 for (PropertySet<KP> ch: shadows) { 092 if (ch!=null) { 093 Object ret = ch.get(key); 094 if (ret!=null) { 095 return ret; 096 } 097 } 098 } 099 return null; 100 } 101 102 @Override 103 public Object get(KP key, Object defaultValue) { 104 for (PropertySet<KP> ch: shadows) { 105 if (ch!=null) { 106 Object ret = ch.get(key); 107 if (ret!=null) { 108 return ret; 109 } 110 } 111 } 112 return defaultValue; 113 } 114 115 @Override 116 public <T> T get(KP key, Class<T> type) { 117 for (PropertySet<KP> ch: shadows) { 118 if (ch!=null) { 119 T ret = ch.get(key, type); 120 if (ret!=null) { 121 return ret; 122 } 123 } 124 } 125 return null; 126 } 127 128 @Override 129 public <T> T get(KP key, Class<T> type, T defaultValue) { 130 for (PropertySet<KP> ch: shadows) { 131 if (ch!=null) { 132 T ret = ch.get(key, type); 133 if (ret!=null) { 134 return ret; 135 } 136 } 137 } 138 return defaultValue; 139 } 140 141 @Override 142 public Object get(KP key, long timeout, TimeUnit unit) { 143 for (PropertySet<KP> ch: shadows) { 144 if (ch!=null) { 145 Object ret = ch.get(key, timeout, unit); 146 if (ret!=null) { 147 return ret; 148 } 149 } 150 } 151 return null; 152 } 153 154 @Override 155 public Object get(KP key, Object defaultValue, long timeout, TimeUnit unit) { 156 for (PropertySet<KP> ch: shadows) { 157 if (ch!=null) { 158 Object ret = ch.get(key, timeout, unit); 159 if (ret!=null) { 160 return ret; 161 } 162 } 163 } 164 return defaultValue; 165 } 166 167 @Override 168 public <T> T get(KP key, Class<T> type, long timeout, TimeUnit unit) { 169 for (PropertySet<KP> ch: shadows) { 170 if (ch!=null) { 171 T ret = ch.get(key, type, timeout, unit); 172 if (ret!=null) { 173 return ret; 174 } 175 } 176 } 177 return null; 178 } 179 180 @Override 181 public <T> T get(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) { 182 for (PropertySet<KP> ch: shadows) { 183 if (ch!=null) { 184 T ret = ch.get(key, type, timeout, unit); 185 if (ret!=null) { 186 return ret; 187 } 188 } 189 } 190 return defaultValue; 191 } 192 193 @Override 194 public void set(KP key, Object value) { 195 throw new UnsupportedOperationException(); 196 197 } 198 199 @Override 200 public void setInvocable(KP key, Invocable<PropertySet<KP>, ?, KP, ?> invocable) { 201 throw new UnsupportedOperationException(); 202 } 203 204 @Override 205 public void cook(KP key, Callable<?> callable) { 206 throw new UnsupportedOperationException(); 207 } 208 209 @Override 210 public void cook(KP key, Callable<?> callable, long delay, TimeUnit timeUnit) { 211 throw new UnsupportedOperationException(); 212 } 213 214 @Override 215 public void cooking(KP key, Future<?> future) { 216 throw new UnsupportedOperationException(); 217 } 218 219 @Override 220 public void lazy(KP key, Callable<?> callable) { 221 throw new UnsupportedOperationException(); 222 } 223 224 @Override 225 public void cancel(KP key) { 226 throw new UnsupportedOperationException(); 227 } 228 229 @Override 230 public void cancelAll() { 231 throw new UnsupportedOperationException(); 232 } 233 234 @Override 235 public Object invoke(KP key, Object... args) { 236 throw new UnsupportedOperationException(); 237 } 238 239 @Override 240 public Object shadowInvoke(KP key, Object... args) { 241 throw new UnsupportedOperationException(); 242 } 243 244 @Override 245 public Object shadowGet(KP key) { 246 throw new UnsupportedOperationException(); 247 } 248 249 @Override 250 public Object shadowGet(KP key, Object defaultValue) { 251 throw new UnsupportedOperationException(); 252 } 253 254 @Override 255 public <T> T shadowGet(KP key, Class<T> type) { 256 throw new UnsupportedOperationException(); 257 } 258 259 @Override 260 public <T> T shadowGet(KP key, Class<T> type, T defaultValue) { 261 throw new UnsupportedOperationException(); 262 } 263 264 265 @Override 266 public Object shadowGet(KP key, long timeout, TimeUnit unit) { 267 throw new UnsupportedOperationException(); 268 } 269 270 @Override 271 public Object shadowGet(KP key, Object defaultValue, long timeout, TimeUnit unit) { 272 throw new UnsupportedOperationException(); 273 } 274 275 @Override 276 public <T> T shadowGet(KP key, Class<T> type, long timeout, TimeUnit unit) { 277 throw new UnsupportedOperationException(); 278 } 279 280 @Override 281 public <T> T shadowGet(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) { 282 throw new UnsupportedOperationException(); 283 } 284 285 @Override 286 public PropertySet<KP> createVersion() { 287 throw new UnsupportedOperationException(); 288 } 289 290 }; 291 292 /** 293 * @return Store for values. 294 */ 295 protected abstract Map<KE, Object> getValueStore(); 296 297 /** 298 * 299 * @return 300 */ 301 protected abstract Map<KE, AbstractPropertySet<KP,KE>> getSubSetStore(); 302 303 /** 304 * Creates a property set which shares lock and chain with this one. 305 * @return 306 */ 307 protected abstract AbstractPropertySet<KP,KE> newInstance(KE key); 308 309 protected abstract Map<KE, PropertySet<KP>> getMounts(); 310 311 protected AbstractPropertySet( 312 ExecutorService executorService, 313 Converter converter, 314// ClassLoader classLoader, 315 Context context, 316 PropertySet<KP>... shadows) { 317 this.executorService = executorService; 318 this.converter = converter==null ? ConvertingService.CONVERTER : converter; 319// this.classLoader = classLoader==null ? getClass().getClassLoader() : classLoader; 320 this.context = context; 321 this.shadows = shadows; 322 } 323 324 protected abstract KP buildPath(int startIdx, Object... elements); 325 326 protected KP buildPath(Object... elements) { 327 return buildPath(0, elements); 328 } 329 330 protected abstract KP buildPath(KP prefix, Object... elements); 331 332 protected abstract KP buildPath(KE prefix, KP suffix); 333 334 protected abstract KE[] tokenize(KP path); 335 336 /** 337 * Versions object for forward-only change propagation purposes. 338 * @param <T> 339 * @param source 340 * @return 341 */ 342 protected abstract <T> T version(T source); 343 344 @Override 345 public Set<KP> keySet() { 346 readLock().lock(); 347 HashSet<KP> ret = new HashSet<KP>(); 348 try { 349 for (KE key: getValueStore().keySet()) { 350 ret.add(buildPath(key)); 351 } 352 353 for (Map.Entry<KE, PropertySet<KP>> entry: getMounts().entrySet()) { 354 for (KP path: entry.getValue().keySet()) { 355 ret.add(buildPath(entry.getKey(), path)); 356 } 357 } 358 359 for (Map.Entry<KE, AbstractPropertySet<KP, KE>> entry: getSubSetStore().entrySet()) { 360 if (!getMounts().containsKey(entry.getKey())) { // If not shadowed 361 for (KP path: entry.getValue().keySet()) { 362 ret.add(buildPath(entry.getKey(), path)); 363 } 364 } 365 } 366 } finally { 367 readLock().unlock(); 368 } 369 370 ret.addAll(shadowPropertySet.keySet()); 371 return ret; 372 } 373 374 @Override 375 public PropertySet<KP> subset(KP prefix) { 376 writeLock().lock(); 377 try { 378 return subset(tokenize(prefix),0,true); 379 } finally { 380 writeLock().unlock(); 381 } 382 } 383 384 protected PropertySet<KP> subset(KE[] prefix, int idx, boolean create) { 385 PropertySet<KP> mount = getMounts().get(prefix[idx]); 386 if (mount!=null) { 387 if (prefix.length==idx+1) { 388 return mount; 389 } 390 391 return mount.subset(buildPath(idx+1, prefix)); 392 } 393 394 AbstractPropertySet<KP, KE> ret = getSubSetStore().get(prefix[idx]); 395 if (ret==null) { 396 if (!create) { 397 return null; 398 } 399 ret = newInstance(prefix[idx]); 400 getSubSetStore().put(prefix[idx], ret); 401 } 402 403 if (prefix.length==idx+1) { 404 return ret; 405 } 406 407 return ret.subset(prefix, idx+1, create); 408 } 409 410 @Override 411 public void remove(KP key) { 412 writeLock().lock(); 413 try { 414 remove(tokenize(key), 0); 415 } finally { 416 writeLock().unlock(); 417 } 418 } 419 420 protected void remove(KE[] path, int idx) { 421 if (path.length==idx+1) { 422 getValueStore().remove(path[idx]); 423 } else { 424 PropertySet<KP> mount = getMounts().get(path[idx]); 425 if (mount!=null) { 426 mount.remove(buildPath(idx+1, path)); 427 } else { 428 AbstractPropertySet<KP, KE> ss = getSubSetStore().get(path[idx]); 429 if (ss!=null) { 430 ss.remove(path, idx+1); 431 } 432 } 433 } 434 } 435 436 @Override 437 public void clear() { 438 writeLock().lock(); 439 try { 440 getValueStore().clear(); 441 for (PropertySet<KP> m: getMounts().values()) { 442 m.clear(); 443 } 444 for (Map.Entry<KE, AbstractPropertySet<KP, KE>> e: getSubSetStore().entrySet()) { 445 if (!getMounts().containsKey(e.getKey())) { 446 e.getValue().clear(); 447 } 448 } 449 for (int i=0; i<shadows.length; ++i) { 450 shadows[i]=null; 451 } 452 } finally { 453 writeLock().unlock(); 454 } 455 } 456 457 @Override 458 public void mount(KP prefix, PropertySet<KP> source) { 459 writeLock().lock(); 460 try { 461 mount(tokenize(prefix), 0, source); 462 } finally { 463 writeLock().unlock(); 464 } 465 } 466 467 protected void mount(KE[] path, int idx, PropertySet<KP> source) { 468 if (path.length==idx+1) { 469 getMounts().put(path[idx], source); 470 } else { 471 AbstractPropertySet<KP, KE> ss = getSubSetStore().get(path[idx]); 472 if (ss==null) { 473 ss = newInstance(path[idx]); 474 getSubSetStore().put(path[idx], ss); 475 } 476 477 ss.mount(path, idx+1, source); 478 } 479 } 480 481 @Override 482 public void unmount(KP prefix) { 483 writeLock().lock(); 484 try { 485 unmount(tokenize(prefix), 0); 486 } finally { 487 writeLock().unlock(); 488 } 489 } 490 491 protected void unmount(KE[] path, int idx) { 492 if (path.length==idx+1) { 493 getMounts().remove(path[idx]); 494 } else { 495 AbstractPropertySet<KP, KE> ss = getSubSetStore().get(path[idx]); 496 if (ss!=null) { 497 ss.unmount(path, idx+1); 498 } 499 } 500 } 501 502 @Override 503 public void setAll(PropertySet<KP> source) { 504 writeLock().lock(); 505 try { 506 for (KP path: source.keySet()) { 507 set(path, source.get(path)); 508 } 509 } finally { 510 writeLock().unlock(); 511 } 512 } 513 514 @Override 515 public Object get(KP key) { 516 Object ret; 517 Object[] va = {null}; 518 readLock().lock(); 519 try { 520 ret = get(tokenize(key), 0, va); 521 } finally { 522 readLock().unlock(); 523 } 524 525 // Chained version 526 if (va[0]!=null) { 527 set(key, va[0]); 528 } 529 530 return ret; 531 } 532 533 @Override 534 public Object get(KP key, long timeout, TimeUnit unit) { 535 Object ret; 536 Object[] va = {null}; 537 readLock().lock(); 538 try { 539 ret = get(tokenize(key), 0, va, timeout, unit); 540 } finally { 541 readLock().unlock(); 542 } 543 544 // Chained version 545 if (va[0]!=null) { 546 set(key, va[0]); 547 } 548 549 return ret; 550 } 551 552 private static class CookEntry { 553 554 CookEntry(Future<?> future, Callable<?> callable) { 555 this.future = future; 556 this.callable = callable; 557 } 558 559 Future<?> future; 560 Callable<?> callable; 561 Object value; 562 563 synchronized Object get() throws Exception { 564 if (future!=null) { 565 value = future.get(); 566 future = null; 567 } else if (callable!=null) { 568 value = callable.call(); 569 callable = null; 570 } 571 return value; 572 } 573 574 synchronized Object get(long timeout, TimeUnit unit) throws Exception { 575 if (future!=null) { 576 value = future.get(timeout, unit); 577 future = null; 578 } else if (callable!=null) { 579 value = callable.call(); 580 callable = null; 581 } 582 return value; 583 } 584 585 void cancel() { 586 if (future!=null && callable!=null && !future.isDone()) { 587 future.cancel(false); 588 future = null; 589 } 590 } 591 592 } 593 594 protected Object get(KE[] path, int idx, Object[] va) { 595 if (path.length==idx+1) { 596 if (getValueStore().containsKey(path[idx])) { 597 Object ret = getValueStore().get(path[idx]); 598 599 if (ret instanceof Invocable) { 600 Invocable<PropertySet<KP>,?, KP, ?> i = (Invocable<PropertySet<KP>,?, KP, ?>) ret; 601 if (i.getParameterTypes()==null || i.getParameterTypes().length==0) { 602 InvocationImpl<KP> invocation = new InvocationImpl<KP>(); 603 invocation.setPropertySet(this); 604 try { 605 return i.invoke(this, invocation, executorService); 606 } catch (Exception e) { 607 throw new PropertySetException(e); 608 } 609 } 610 return i; 611 } 612 613 if (ret instanceof CookEntry) { 614 try { 615 ret = ((CookEntry) ret).get(); 616 va[0] = ret; // To replace cook entry with value 617 return ret; 618 } catch (Exception e) { 619 throw new PropertySetException(e); 620 } 621 } 622 623 return ret; 624 } 625 } else { 626 PropertySet<KP> mount = getMounts().get(path[idx]); 627 if (mount!=null) { 628 return mount.get(buildPath(idx+1, path)); 629 } 630 631 AbstractPropertySet<KP, KE> ss = getSubSetStore().get(path[idx]); 632 if (ss!=null) { 633 Object ret = ss.get(path, idx+1, va); 634 if (ret!=null) { 635 return ret; 636 } 637 } 638 } 639 640 va[0] = version(shadowGet(buildPath(idx, path))); 641 return va[0]; 642 } 643 644 protected Object get(KE[] path, int idx, Object[] va, long timeout, TimeUnit unit) { 645 if (path.length==idx+1) { 646 if (getValueStore().containsKey(path[idx])) { 647 Object ret = getValueStore().get(path[idx]); 648 649 if (ret instanceof Invocable) { 650 Invocable<PropertySet<KP>,?, KP, ?> i = (Invocable<PropertySet<KP>,?, KP, ?>) ret; 651 if (i.getParameterTypes()==null || i.getParameterTypes().length==0) { 652 InvocationImpl<KP> invocation = new InvocationImpl<KP>(); 653 invocation.setPropertySet(this); 654 try { 655 return i.invoke(this, invocation, executorService); 656 } catch (Exception e) { 657 throw new PropertySetException(e); 658 } 659 } 660 return i; 661 } 662 663 if (ret instanceof CookEntry) { 664 try { 665 ret = ((CookEntry) ret).get(timeout, unit); 666 va[0] = ret; // To replace cook entry with value 667 return ret; 668 } catch (Exception e) { 669 throw new PropertySetException(e); 670 } 671 } 672 673 return ret; 674 } 675 } else { 676 PropertySet<KP> mount = getMounts().get(path[idx]); 677 if (mount!=null) { 678 return mount.get(buildPath(idx+1, path), timeout, unit); 679 } 680 681 AbstractPropertySet<KP, KE> ss = getSubSetStore().get(path[idx]); 682 if (ss!=null) { 683 Object ret = ss.get(path, idx+1, va, timeout, unit); 684 if (ret!=null) { 685 return ret; 686 } 687 } 688 } 689 690 va[0] = version(shadowGet(buildPath(idx, path), timeout, unit)); 691 return va[0]; 692 } 693 694 @Override 695 public Object get(KP key, Object defaultValue) { 696 Object ret = get(key); 697 return ret == null ? defaultValue : ret; 698 } 699 700 @Override 701 public Object get(KP key, Object defaultValue, long timeout, TimeUnit unit) { 702 Object ret = get(key, timeout, unit); 703 return ret == null ? defaultValue : ret; 704 } 705 706 @Override 707 public <T> T get(KP key, Class<T> type) { 708 return get(key, type, null); 709 } 710 711 @Override 712 public <T> T get(KP key, Class<T> type, long timeout, TimeUnit unit) { 713 return get(key, type, null, timeout, unit); 714 } 715 716 @Override 717 public <T> T get(KP key, Class<T> type, T defaultValue) { 718 Object ret = get(key); 719 if (ret==null) { 720 if (type!=null && type.isInterface()) { 721 PropertySet<KP> toWrap = subset(tokenize(key), 0, false); 722 if (toWrap!=null) { 723 return toWrap.getAdapter(type, null); 724 } 725 } 726 return defaultValue; 727 } 728 if (type.isInstance(ret)) { 729 return (T) ret; 730 } 731 T converted = converter.convert(ret, type, context); 732 if (converted==null) { 733 throw new PropertySetException("Cannot convert "+ ret +" to "+type); 734 } 735 return converted; 736 } 737 738 @Override 739 public <T> T get(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) { 740 Object ret = get(key, timeout, unit); 741 if (ret==null) { 742 if (type!=null && type.isInterface()) { 743 PropertySet<KP> toWrap = subset(tokenize(key), 0, false); 744 if (toWrap!=null) { 745 return toWrap.getAdapter(type, null); 746 } 747 } 748 return defaultValue; 749 } 750 if (type.isInstance(ret)) { 751 return (T) ret; 752 } 753 T converted = converter.convert(ret, type, context); 754 if (converted==null) { 755 throw new PropertySetException("Cannot convert "+ ret +" to "+type); 756 } 757 return converted; 758 } 759 760 @Override 761 public void set(KP key, Object value) { 762 writeLock().lock(); 763 try { 764 set(tokenize(key), 0, value); 765 } finally { 766 writeLock().unlock(); 767 } 768 } 769 770 protected void set(KE[] path, int idx, Object value) { 771 if (path.length==idx+1) { 772 getValueStore().put(path[idx], value); 773 } else { 774 PropertySet<KP> mount = getMounts().get(path[idx]); 775 if (mount!=null) { 776 mount.set(buildPath(idx+1, path), value); 777 } else { 778 AbstractPropertySet<KP, KE> ret = getSubSetStore().get(path[idx]); 779 if (ret==null) { 780 ret = newInstance(path[idx]); 781 getSubSetStore().put(path[idx], ret); 782 } 783 784 ret.set(path, idx+1, value); 785 } 786 } 787 } 788 789 @Override 790 public void setInvocable(KP key, Invocable<PropertySet<KP>, ?, KP, ?> invocable) { 791 set(key, invocable); 792 } 793 794 @Override 795 public void cook(KP key, Callable<?> callable) { 796 cook(key, callable, 0, null); 797 } 798 799 protected void cook(KE[] path, int idx, Callable<?> callable, long delay, TimeUnit timeUnit) { 800 if (path.length==idx+1) { 801 Future<?> future = null; 802 if (delay>0 && timeUnit!=null && executorService instanceof ScheduledExecutorService) { 803 future = ((ScheduledExecutorService) executorService).schedule(callable, delay, timeUnit); 804 } else if (executorService!=null) { 805 future = executorService.submit(callable); 806 } 807 getValueStore().put(path[idx], new CookEntry(future, callable)); 808 } else { 809 PropertySet<KP> mount = getMounts().get(path[idx]); 810 if (mount!=null) { 811 mount.cook(buildPath(idx+1, path), callable, delay, timeUnit); 812 } 813 814 AbstractPropertySet<KP, KE> ret = getSubSetStore().get(path[idx]); 815 if (ret==null) { 816 ret = newInstance(path[idx]); 817 getSubSetStore().put(path[idx], ret); 818 } 819 820 ret.cook(path, idx+1, callable, delay, timeUnit); 821 } 822 } 823 824 @Override 825 public void cook(KP key, Callable<?> callable, long delay, TimeUnit timeUnit) { 826 writeLock().lock(); 827 try { 828 cook(tokenize(key), 0, callable, delay, timeUnit); 829 } finally { 830 writeLock().unlock(); 831 } 832 } 833 834 @Override 835 public void cooking(KP key, Future<?> future) { 836 set(key, new CookEntry(future, null)); 837 } 838 839 @Override 840 public void lazy(KP key, Callable<?> callable) { 841 set(key, new CookEntry(null, callable)); 842 } 843 844 @Override 845 public void cancel(KP key) { 846 readLock().lock(); 847 try { 848 cancel(tokenize(key),0); 849 } finally { 850 readLock().unlock(); 851 } 852 } 853 854 protected void cancel(KE[] path, int idx) { 855 if (path.length==idx+1) { 856 Object v = getValueStore().get(path[idx]); 857 if (v instanceof CookEntry) { 858 ((CookEntry) v).cancel(); 859 } 860 } else { 861 PropertySet<KP> mount = getMounts().get(path[idx]); 862 if (mount!=null) { 863 mount.cancel(buildPath(idx+1, path)); 864 } 865 866 AbstractPropertySet<KP, KE> ret = getSubSetStore().get(path[idx]); 867 if (ret!=null) { 868 ret.cancel(path, idx+1); 869 } 870 } 871 } 872 873 @Override 874 public void cancelAll() { 875 readLock().lock(); 876 try { 877 for (PropertySet<KP> mount: getMounts().values()) { 878 mount.cancelAll(); 879 } 880 for (PropertySet<KP> ss: getSubSetStore().values()) { 881 ss.cancelAll(); 882 } 883 for (Object v: getValueStore().values()) { 884 if (v instanceof CookEntry) { 885 ((CookEntry) v).cancel(); 886 } 887 } 888 } finally { 889 readLock().unlock(); 890 } 891 } 892 893 @Override 894 public Object invoke(KP key, Object... args) { 895 return invoke(this, key, args); 896 } 897 898 private Object invoke(PropertySet<KP> contextPropertySet, KP key, Object... args) { 899 writeLock().lock(); // To avoid deadlocks if invocable has side effects. 900 try { 901 Object i = contextPropertySet.get(key); 902 if (i instanceof Invocable) { 903 Invocable invocable = (Invocable) i; 904 Class[] parameterTypes = invocable.getParameterTypes(); 905 if (args!=null && parameterTypes!=null) { 906 if (parameterTypes.length!=args.length) { 907 throw new PropertySetException("Cannot invoke "+key+" - invalid number of arguments"); 908 } 909 args = Arrays.copyOf(args, args.length); 910 for (int j=0; j<args.length; ++j) { 911 if (args[j]!=null && !parameterTypes[j].isInstance(args[j])) { 912 Object newVal = converter.convert(args[j], parameterTypes[j], context); 913 if (args[j]==null) { 914 throw new PropertySetException("Cannot covert "+args[j]+" to "+parameterTypes[j]); 915 } 916 args[j] = newVal; 917 } 918 } 919 } 920 InvocationImpl invocation = new InvocationImpl(args, contextPropertySet, null); 921 try { 922 return invocable.invoke(contextPropertySet, invocation, executorService); 923 } catch (Exception e) { 924 throw new PropertySetException(e); 925 } 926 } 927 928 throw new PropertySetException("Not invocable: "+i); 929 } finally { 930 writeLock().unlock(); 931 } 932 } 933 934 @Override 935 public Object shadowInvoke(KP key, Object... args) { 936 return invoke(shadowPropertySet, key, args); 937 } 938 939 @Override 940 public Object shadowGet(KP key) { 941 return shadowPropertySet.get(key); 942 } 943 944 @Override 945 public Object shadowGet(KP key, Object defaultValue) { 946 return shadowPropertySet.get(key, defaultValue); 947 } 948 949 @Override 950 public <T> T shadowGet(KP key, Class<T> type) { 951 return shadowPropertySet.get(key, type); 952 } 953 954 @Override 955 public <T> T shadowGet(KP key, Class<T> type, T defaultValue) { 956 return shadowPropertySet.get(key, type, defaultValue); 957 } 958 959 @Override 960 public Object shadowGet(KP key, long timeout, TimeUnit unit) { 961 return shadowPropertySet.get(key, timeout, unit); 962 } 963 964 @Override 965 public Object shadowGet(KP key, Object defaultValue, long timeout, TimeUnit unit) { 966 return shadowPropertySet.get(key, defaultValue, timeout, unit); 967 } 968 969 @Override 970 public <T> T shadowGet(KP key, Class<T> type, long timeout, TimeUnit unit) { 971 return shadowPropertySet.get(key, type, timeout, unit); 972 } 973 974 @Override 975 public <T> T shadowGet(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) { 976 return shadowPropertySet.get(key, type, defaultValue, timeout, unit); 977 } 978 979 980}