1 18 19 package org.osgi.util.tracker; 20 21 import java.util.ArrayList ; 22 import java.util.Enumeration ; 23 import java.util.Hashtable ; 24 import java.util.LinkedList ; 25 26 import org.eclipse.osgi.framework.internal.core.FilterImpl; 27 import org.osgi.framework.AllServiceListener; 28 import org.osgi.framework.BundleContext; 29 import org.osgi.framework.Constants; 30 import org.osgi.framework.Filter; 31 import org.osgi.framework.InvalidSyntaxException; 32 import org.osgi.framework.ServiceEvent; 33 import org.osgi.framework.ServiceListener; 34 import org.osgi.framework.ServiceReference; 35 36 63 64 69 70 public class ServiceTracker implements ServiceTrackerCustomizer { 71 72 static final boolean DEBUG = false; 73 77 protected final BundleContext context; 78 83 protected final Filter filter; 84 87 final ServiceTrackerCustomizer customizer; 88 91 private final String listenerFilter; 92 96 private final String trackClass; 97 101 private final ServiceReference trackReference; 102 106 final boolean noUserFilter; 107 111 private volatile Tracked tracked; 112 118 private volatile int trackingCount = -1; 119 124 private volatile ServiceReference cachedReference; 125 130 private volatile Object cachedService; 131 132 152 public ServiceTracker(BundleContext context, ServiceReference reference, 153 ServiceTrackerCustomizer customizer) { 154 this.context = context; 155 this.trackReference = reference; 156 this.trackClass = null; 157 this.customizer = (customizer == null) ? this : customizer; 158 this.listenerFilter = "(&(" + Constants.OBJECTCLASS + "=" + ((String []) reference.getProperty(Constants.OBJECTCLASS))[0] + ")(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + "))" ; this.noUserFilter = true; 161 try { 162 this.filter = context.createFilter(listenerFilter); 163 } 164 catch (InvalidSyntaxException e) { throw new IllegalArgumentException ( 168 "unexpected InvalidSyntaxException: " + e.getMessage()); } 170 } 171 172 191 public ServiceTracker(BundleContext context, String clazz, 192 ServiceTrackerCustomizer customizer) { 193 this.context = context; 194 this.trackReference = null; 195 this.trackClass = clazz; 196 this.customizer = (customizer == null) ? this : customizer; 197 this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")"; this.noUserFilter = true; 199 try { 200 this.filter = context.createFilter(listenerFilter); 201 } 202 catch (InvalidSyntaxException e) { throw new IllegalArgumentException ( 206 "unexpected InvalidSyntaxException: " + e.getMessage()); } 208 } 209 210 230 public ServiceTracker(BundleContext context, Filter filter, 231 ServiceTrackerCustomizer customizer) { 232 this.context = context; 233 this.trackReference = null; 234 235 if (filter instanceof FilterImpl) { 237 this.trackClass = ((FilterImpl)filter).getRequiredObjectClass(); 238 } else { 239 this.trackClass = null; 240 } 241 242 if (this.trackClass != null) { 243 this.listenerFilter = FilterImpl.getObjectClassFilterString(this.trackClass); 244 this.noUserFilter = this.listenerFilter.equals(filter.toString()); 246 } else { 247 this.listenerFilter = null; 248 this.noUserFilter = false; 249 } 250 251 this.filter = filter; 252 this.customizer = (customizer == null) ? this : customizer; 253 if ((context == null) || (filter == null)) { throw new NullPointerException (); 258 } 259 } 260 261 273 public void open() { 274 open(false); 275 } 276 277 298 public synchronized void open(boolean trackAllServices) { 299 if (tracked != null) { 300 return; 301 } 302 if (DEBUG) { 303 System.out.println("ServiceTracker.open: " + filter); } 305 tracked = trackAllServices ? new AllTracked() : new Tracked(); 306 trackingCount = 0; 307 synchronized (tracked) { 308 try { 309 context.addServiceListener(tracked, listenerFilter); 310 ServiceReference[] references; 311 312 if (trackReference != null) { references = new ServiceReference[] {trackReference}; 314 } 315 else { references = getInitialReferences(trackAllServices, trackClass, 317 noUserFilter ? null: filter.toString()); 318 } 319 320 tracked.setInitialServices(references); } 324 catch (InvalidSyntaxException e) { 325 throw new RuntimeException ( 326 "unexpected InvalidSyntaxException: " + e.getMessage()); } 328 } 329 330 tracked.trackInitialServices(); } 332 333 344 private ServiceReference[] getInitialReferences(boolean trackAllServices, 345 String trackClass, String filterString) 346 throws InvalidSyntaxException { 347 if (trackAllServices) { 348 return context.getAllServiceReferences(trackClass, filterString); 349 } 350 else { 351 return context.getServiceReferences(trackClass, filterString); 352 } 353 } 354 355 362 public synchronized void close() { 363 if (tracked == null) { 364 return; 365 } 366 if (DEBUG) { 367 System.out.println("ServiceTracker.close: " + filter); } 369 tracked.close(); 370 ServiceReference[] references = getServiceReferences(); 371 Tracked outgoing = tracked; 372 tracked = null; 373 try { 374 context.removeServiceListener(outgoing); 375 } 376 catch (IllegalStateException e) { 377 378 } 379 if (references != null) { 380 for (int i = 0; i < references.length; i++) { 381 outgoing.untrack(references[i]); 382 } 383 } 384 trackingCount = -1; 385 if (DEBUG) { 386 if ((cachedReference == null) && (cachedService == null)) { 387 System.out 388 .println("ServiceTracker.close[cached cleared]: " + filter); } 390 } 391 } 392 393 418 public Object addingService(ServiceReference reference) { 419 return context.getService(reference); 420 } 421 422 437 public void modifiedService(ServiceReference reference, Object service) { 438 } 439 440 462 public void removedService(ServiceReference reference, Object service) { 463 context.ungetService(reference); 464 } 465 466 482 public Object waitForService(long timeout) throws InterruptedException { 483 if (timeout < 0) { 484 throw new IllegalArgumentException ("timeout value is negative"); } 486 Object object = getService(); 487 while (object == null) { 488 Tracked tracked = this.tracked; 492 if (tracked == null) { 493 return null; 494 } 495 synchronized (tracked) { 496 if (tracked.size() == 0) { 497 tracked.wait(timeout); 498 } 499 } 500 object = getService(); 501 if (timeout > 0) { 502 return object; 503 } 504 } 505 return object; 506 } 507 508 515 public ServiceReference[] getServiceReferences() { 516 Tracked tracked = this.tracked; 520 if (tracked == null) { 521 return null; 522 } 523 synchronized (tracked) { 524 int length = tracked.size(); 525 if (length == 0) { 526 return null; 527 } 528 ServiceReference[] references = new ServiceReference[length]; 529 Enumeration keys = tracked.keys(); 530 for (int i = 0; i < length; i++) { 531 references[i] = (ServiceReference) keys.nextElement(); 532 } 533 return references; 534 } 535 } 536 537 558 public ServiceReference getServiceReference() { 559 ServiceReference reference = cachedReference; 560 if (reference != null) { 561 if (DEBUG) { 562 System.out 563 .println("ServiceTracker.getServiceReference[cached]: " + filter); } 565 return reference; 566 } 567 if (DEBUG) { 568 System.out.println("ServiceTracker.getServiceReference: " + filter); } 570 ServiceReference[] references = getServiceReferences(); 571 int length = (references == null) ? 0 : references.length; 572 if (length == 0) 573 { 574 return null; 575 } 576 int index = 0; 577 if (length > 1) 578 { 579 int rankings[] = new int[length]; 580 int count = 0; 581 int maxRanking = Integer.MIN_VALUE; 582 for (int i = 0; i < length; i++) { 583 Object property = references[i] 584 .getProperty(Constants.SERVICE_RANKING); 585 int ranking = (property instanceof Integer ) ? ((Integer ) property) 586 .intValue() 587 : 0; 588 rankings[i] = ranking; 589 if (ranking > maxRanking) { 590 index = i; 591 maxRanking = ranking; 592 count = 1; 593 } 594 else { 595 if (ranking == maxRanking) { 596 count++; 597 } 598 } 599 } 600 if (count > 1) 601 { 602 long minId = Long.MAX_VALUE; 603 for (int i = 0; i < length; i++) { 604 if (rankings[i] == maxRanking) { 605 long id = ((Long ) (references[i] 606 .getProperty(Constants.SERVICE_ID))) 607 .longValue(); 608 if (id < minId) { 609 index = i; 610 minId = id; 611 } 612 } 613 } 614 } 615 } 616 return cachedReference = references[index]; 617 } 618 619 629 public Object getService(ServiceReference reference) { 630 Tracked tracked = this.tracked; 634 if (tracked == null) { 635 return null; 636 } 637 synchronized (tracked) { 638 return tracked.get(reference); 639 } 640 } 641 642 649 public Object [] getServices() { 650 Tracked tracked = this.tracked; 654 if (tracked == null) { 655 return null; 656 } 657 synchronized (tracked) { 658 ServiceReference[] references = getServiceReferences(); 659 int length = (references == null) ? 0 : references.length; 660 if (length == 0) { 661 return null; 662 } 663 Object [] objects = new Object [length]; 664 for (int i = 0; i < length; i++) { 665 objects[i] = getService(references[i]); 666 } 667 return objects; 668 } 669 } 670 671 682 public Object getService() { 683 Object service = cachedService; 684 if (service != null) { 685 if (DEBUG) { 686 System.out 687 .println("ServiceTracker.getService[cached]: " + filter); } 689 return service; 690 } 691 if (DEBUG) { 692 System.out.println("ServiceTracker.getService: " + filter); } 694 ServiceReference reference = getServiceReference(); 695 if (reference == null) { 696 return null; 697 } 698 return cachedService = getService(reference); 699 } 700 701 711 public void remove(ServiceReference reference) { 712 Tracked tracked = this.tracked; 716 if (tracked == null) { 717 return; 718 } 719 tracked.untrack(reference); 720 } 721 722 728 public int size() { 729 Tracked tracked = this.tracked; 733 if (tracked == null) { 734 return 0; 735 } 736 return tracked.size(); 737 } 738 739 760 public int getTrackingCount() { 761 return trackingCount; 762 } 763 764 770 775 void modified() { 776 trackingCount++; 777 cachedReference = null; 778 cachedService = null; 779 if (DEBUG) { 780 System.out.println("ServiceTracker.modified: " + filter); } 782 } 783 784 785 796 class Tracked extends Hashtable implements ServiceListener { 797 static final long serialVersionUID = -7420065199791006079L; 798 813 private final ArrayList adding; 814 815 821 private volatile boolean closed; 822 823 841 private final LinkedList initial; 842 843 846 protected Tracked() { 847 super(); 848 closed = false; 849 adding = new ArrayList (6); 850 initial = new LinkedList (); 851 } 852 853 864 protected void setInitialServices(ServiceReference[] references) { 865 if (references == null) { 866 return; 867 } 868 int size = references.length; 869 for (int i = 0; i < size; i++) { 870 if (DEBUG) { 871 System.out 872 .println("ServiceTracker.Tracked.setInitialServices: " + references[i]); } 874 initial.add(references[i]); 875 } 876 } 877 878 886 protected void trackInitialServices() { 887 while (true) { 888 ServiceReference reference; 889 synchronized (this) { 890 if (initial.size() == 0) { 891 894 return; 895 } 896 900 reference = (ServiceReference) initial.removeFirst(); 901 if (this.get(reference) != null) { 902 903 if (DEBUG) { 904 System.out 905 .println("ServiceTracker.Tracked.trackInitialServices[already tracked]: " + reference); } 907 continue; 908 } 909 if (adding.contains(reference)) { 910 914 if (DEBUG) { 915 System.out 916 .println("ServiceTracker.Tracked.trackInitialServices[already adding]: " + reference); } 918 continue; 919 } 920 adding.add(reference); 921 } 922 if (DEBUG) { 923 System.out 924 .println("ServiceTracker.Tracked.trackInitialServices: " + reference); } 926 trackAdding(reference); 931 } 932 } 933 934 938 protected void close() { 939 closed = true; 940 } 941 942 949 public void serviceChanged(ServiceEvent event) { 950 954 if (closed) { 955 return; 956 } 957 ServiceReference reference = event.getServiceReference(); 958 if (DEBUG) { 959 System.out 960 .println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference); } 962 963 switch (event.getType()) { 964 case ServiceEvent.REGISTERED : 965 case ServiceEvent.MODIFIED : 966 if (noUserFilter) { track(reference); 968 972 } 973 else { if (filter.match(reference)) { 975 track(reference); 976 980 } 981 else { 982 untrack(reference); 983 987 } 988 } 989 break; 990 case ServiceEvent.UNREGISTERING : 991 untrack(reference); 992 996 break; 997 } 998 } 999 1000 1005 private void track(ServiceReference reference) { 1006 Object object; 1007 synchronized (this) { 1008 object = this.get(reference); 1009 } 1010 if (object != null) 1011 { 1012 if (DEBUG) { 1013 System.out 1014 .println("ServiceTracker.Tracked.track[modified]: " + reference); } 1016 synchronized (this) { 1017 modified(); 1018 } 1019 1020 customizer.modifiedService(reference, object); 1021 1025 return; 1026 } 1027 synchronized (this) { 1028 if (adding.contains(reference)) { 1033 if (DEBUG) { 1034 System.out 1035 .println("ServiceTracker.Tracked.track[already adding]: " + reference); } 1037 return; 1038 } 1039 adding.add(reference); 1040 } 1041 1042 trackAdding(reference); 1046 } 1047 1048 1055 private void trackAdding(ServiceReference reference) { 1056 if (DEBUG) { 1057 System.out 1058 .println("ServiceTracker.Tracked.trackAdding: " + reference); } 1060 Object object = null; 1061 boolean becameUntracked = false; 1062 1063 try { 1064 object = customizer.addingService(reference); 1065 1069 } 1070 finally { 1071 synchronized (this) { 1072 if (adding.remove(reference)) { 1077 if (object != null) { 1078 this.put(reference, object); 1079 modified(); 1080 notifyAll(); 1084 } 1085 } 1086 else { 1087 becameUntracked = true; 1088 } 1089 } 1090 } 1091 1094 if (becameUntracked) { 1095 if (DEBUG) { 1096 System.out 1097 .println("ServiceTracker.Tracked.trackAdding[removed]: " + reference); } 1099 1100 customizer.removedService(reference, object); 1101 1105 } 1106 } 1107 1108 1113 protected void untrack(ServiceReference reference) { 1114 Object object; 1115 synchronized (this) { 1116 if (initial.remove(reference)) { 1122 if (DEBUG) { 1123 System.out 1124 .println("ServiceTracker.Tracked.untrack[removed from initial]: " + reference); } 1126 return; 1130 } 1131 1132 if (adding.remove(reference)) { 1136 if (DEBUG) { 1137 System.out 1138 .println("ServiceTracker.Tracked.untrack[being added]: " + reference); } 1140 return; 1144 } 1145 object = this.remove(reference); 1150 if (object == null) { 1151 return; 1152 } 1153 modified(); 1154 } 1155 if (DEBUG) { 1156 System.out 1157 .println("ServiceTracker.Tracked.untrack[removed]: " + reference); } 1159 1160 customizer.removedService(reference, object); 1161 1165 } 1166 } 1167 1168 1175 class AllTracked extends Tracked implements AllServiceListener { 1176 static final long serialVersionUID = 4050764875305137716L; 1177 1178 1181 protected AllTracked() { 1182 super(); 1183 } 1184 } 1185} 1186 | Popular Tags |