Listeners.java

00001 /*
00002  * Copyright (c) 2003-2006, KNOPFLERFISH project
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  * - Redistributions in binary form must reproduce the above
00013  *   copyright notice, this list of conditions and the following
00014  *   disclaimer in the documentation and/or other materials
00015  *   provided with the distribution.
00016  *
00017  * - Neither the name of the KNOPFLERFISH project nor the names of its
00018  *   contributors may be used to endorse or promote products derived
00019  *   from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00030  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032  * OF THE POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 package org.knopflerfish.framework;
00036 
00037 import java.util.Set;
00038 import java.util.List;
00039 import java.util.ArrayList;
00040 import java.util.Map;
00041 import java.util.HashSet;
00042 import java.util.HashMap;
00043 import java.util.Iterator;
00044 import java.util.EventListener;
00045 
00046 import org.osgi.framework.*;
00047 
00054 public class Listeners
00055   implements BundleListener, FrameworkListener, ServiceListener {
00056 
00060   private HashSet bundleListeners = new HashSet();
00061   private HashSet syncBundleListeners = new HashSet();
00062 
00066   private HashSet frameworkListeners = new HashSet();
00067 
00071   private ServiceListenerState serviceListeners = new ServiceListenerState();
00072 
00076   private PermissionOps secure;
00077 
00078 
00079   Listeners(PermissionOps perm) {
00080     secure = perm;
00081   }
00082 
00083 
00090   void addBundleListener(Bundle bundle, BundleListener listener) {
00091     ListenerEntry le = new ListenerEntry(bundle, listener);
00092     if (listener instanceof SynchronousBundleListener) {
00093       secure.checkListenerAdminPerm(bundle);
00094       synchronized (syncBundleListeners) {
00095           syncBundleListeners.add(le);
00096       }
00097     } 
00098     else {
00099       synchronized (bundleListeners) {
00100           bundleListeners.add(le);
00101       }
00102     }
00103   }
00104 
00105 
00114   void removeBundleListener(Bundle bundle, BundleListener listener) {
00115     ListenerEntry le = new ListenerEntry(bundle, listener);
00116     if (listener instanceof SynchronousBundleListener) {
00117       synchronized (syncBundleListeners) {
00118         secure.checkListenerAdminPerm(bundle);
00119         syncBundleListeners.remove(le);
00120       }
00121     } else {
00122       synchronized (bundleListeners) {
00123         bundleListeners.remove(le);
00124       }
00125     }
00126   }
00127 
00128 
00135   void addFrameworkListener(Bundle bundle, FrameworkListener listener) {
00136     ListenerEntry le = new ListenerEntry(bundle, listener);
00137     synchronized (frameworkListeners) {
00138       frameworkListeners.add(le);
00139     }
00140   }
00141 
00142 
00151   void removeFrameworkListener(Bundle bundle, FrameworkListener listener) {
00152     synchronized (frameworkListeners) {
00153       frameworkListeners.remove(new ListenerEntry(bundle, listener));
00154     }
00155   }
00156 
00157 
00166   void addServiceListener(Bundle bundle, ServiceListener listener, String filter)
00167     throws InvalidSyntaxException {
00168     serviceListeners.add(bundle, listener, filter);
00169   }
00170 
00171 
00180   void removeServiceListener(Bundle bundle, ServiceListener listener) {
00181     serviceListeners.remove(bundle, listener);
00182   }
00183 
00184 
00190   void removeAllListeners(Bundle b) {
00191     removeAllListeners(syncBundleListeners, b);
00192     removeAllListeners(bundleListeners, b);
00193     removeAllListeners(frameworkListeners, b);
00194     serviceListeners.removeAll(b);
00195   }
00196 
00197 
00204   void frameworkError(Bundle b, Throwable t) {
00205     frameworkEvent(new FrameworkEvent(FrameworkEvent.ERROR, b, t));
00206   }
00207 
00208 
00215   void frameworkInfo(Bundle b, Throwable t) {
00216     frameworkEvent(new FrameworkEvent(FrameworkEvent.INFO, b, t));
00217   }
00218 
00219   //
00220   // BundleListener interface
00221   //
00222 
00228   public void bundleChanged(final BundleEvent evt) {
00229     ListenerEntry [] bl, tmp;
00230     int type = evt.getType();
00231     if(type == BundleEvent.STARTING || type == BundleEvent.STOPPING){
00232         synchronized (syncBundleListeners) {
00233                 bl = new ListenerEntry[syncBundleListeners.size()];
00234                 syncBundleListeners.toArray(bl);
00235         }
00236     }
00237     else{
00238         synchronized (bundleListeners) {
00239                 tmp = new ListenerEntry[bundleListeners.size()];
00240             bundleListeners.toArray(tmp);
00241         }
00242         synchronized (syncBundleListeners) {
00243                 bl = new ListenerEntry[tmp.length + syncBundleListeners.size()];
00244             syncBundleListeners.toArray(bl);
00245         }
00246         System.arraycopy(tmp, 0, bl, bl.length - tmp.length, tmp.length);
00247     }
00248     
00249     for (int i = 0; i < bl.length; i++) {
00250       final ListenerEntry l = bl[i];
00251       try {
00252         secure.callBundleChanged((BundleListener)l.listener, evt);
00253       } catch (Throwable pe) {
00254         frameworkError(l.bundle, pe);
00255       }
00256     }
00257   }
00258 
00259   //
00260   // FrameworkListener interface
00261   //
00262 
00268   public void frameworkEvent(final FrameworkEvent evt) {
00269     if (Debug.errors) {
00270       if (evt.getType() == FrameworkEvent.ERROR) {
00271         Debug.println("errors - FrameworkErrorEvent bundle #" + evt.getBundle().getBundleId());
00272         Debug.printStackTrace("errors - FrameworkErrorEvent throwable: ", evt.getThrowable());
00273       }
00274     }
00275     ListenerEntry [] fl;
00276     synchronized (frameworkListeners) {
00277       fl = new ListenerEntry[frameworkListeners.size()];
00278       frameworkListeners.toArray(fl);
00279     }
00280     for (int i = 0; i < fl.length; i++) {
00281       final ListenerEntry l = fl[i];
00282       try {
00283         secure.callFrameworkEvent((FrameworkListener)l.listener, evt);
00284       } catch (Throwable pe) {
00285         // Don't report Error events again, since probably would go into an infinite loop.
00286         if (evt.getType() != FrameworkEvent.ERROR) {
00287           frameworkError(l.bundle, pe);
00288         }
00289       }
00290     }
00291   }
00292 
00293   //
00294   // ServiceListener interface
00295   //
00296 
00302   public void serviceChanged(final ServiceEvent evt) {
00303     ServiceReferenceImpl sr = (ServiceReferenceImpl)evt.getServiceReference();
00304     String[] classes = (String[])sr.getProperty(Constants.OBJECTCLASS);
00305     Set sl = serviceListeners.getMatchingListeners(sr);
00306     int n = 0;
00307     for (Iterator it = sl.iterator(); it.hasNext(); n++) {
00308       final ServiceListenerEntry l = (ServiceListenerEntry)it.next();
00309       boolean testAssignable = false;
00310       if(!(l.listener instanceof AllServiceListener)){
00311         testAssignable = true;
00312       }
00313       try {
00314         int length = classes.length;
00315         for (int i = 0; i < length; i++) {
00316           if(testAssignable && !sr.isAssignableTo(l.bundle, classes[i])){
00317             continue;
00318           }
00319           if (l.bundle.hasPermission(new ServicePermission(classes[i], 
00320                                                            ServicePermission.GET))) {
00321             try {
00322               secure.callServiceChanged((ServiceListener)l.listener, evt);
00323             } catch (Throwable pe) {
00324               frameworkError(l.bundle, pe);
00325             }
00326             break;
00327           }
00328         }//for
00329       } catch (Exception le) {
00330         frameworkError(l.bundle, le);
00331       }
00332     }//for
00333     if (Debug.ldap) {
00334       Debug.println("Notified " + n + " listeners");
00335     }
00336   }
00337 
00338   //
00339   // Private methods
00340   //
00341 
00349   private void removeAllListeners(Set s, Bundle b) {
00350     synchronized (s) {
00351       for (Iterator i = s.iterator(); i.hasNext();) {
00352         if (((ListenerEntry)i.next()).bundle == b) {
00353           i.remove();
00354         }
00355       }
00356     }
00357   }
00358 
00359   static boolean nocacheldap = 
00360     "true".equals(System.getProperty("org.knopflerfish.framework.ldap.nocache"));
00361 }
00362 
00368 class ListenerEntry {
00369   Bundle bundle;
00370   EventListener listener;
00371 
00372   ListenerEntry(Bundle b, EventListener l) {
00373     bundle = b;
00374     listener = l;
00375   }
00376 
00377   public boolean equals(Object o) {
00378     if (o instanceof ListenerEntry) {
00379       return bundle == ((ListenerEntry)o).bundle &&
00380         listener == ((ListenerEntry)o).listener;
00381     }
00382     return false;
00383   }
00384 
00385   public int hashCode() {
00386     return bundle.hashCode();
00387   }
00388 }
00389 
00395 class ServiceListenerEntry extends ListenerEntry {
00396   LDAPExpr ldap;
00397 
00417   List[] local_cache;
00418 
00419   ServiceListenerEntry(Bundle b, EventListener l, String filter) 
00420     throws InvalidSyntaxException {
00421     super(b, l);
00422     if (filter != null) {
00423       ldap = new LDAPExpr(filter);
00424     } else {
00425       ldap = null;
00426     }
00427   }
00428 
00429   ServiceListenerEntry(Bundle b, EventListener l) {
00430     super(b, l);
00431     ldap = null;
00432   }
00433 
00434 }
00435 
00439 class ServiceListenerState {
00440   protected final static String[] hashedKeys = 
00441     new String[] { Constants.OBJECTCLASS.toLowerCase(),
00442                    Constants.SERVICE_ID.toLowerCase(),
00443                    Constants.SERVICE_PID.toLowerCase()
00444     };
00445   private final static int OBJECTCLASS_IX = 0;
00446   private final static int SERVICE_ID_IX  = 1;
00447   private final static int SERVICE_PID_IX = 2;
00448   protected static List hashedKeysV;
00449 
00450   /* Service listeners with complicated or empty filters */
00451   List complicatedListeners = new ArrayList();
00452 
00453   /* Service listeners with "simple" filters are cached. */
00454   Map[] /* [Value -> List(ServiceListenerEntry)] */
00455     cache = new HashMap[hashedKeys.length];
00456 
00457   Set /* ServiceListenerEntry */ serviceSet = new HashSet();
00458 
00459   ServiceListenerState() {
00460     hashedKeysV = new ArrayList();
00461     for (int i = 0; i < hashedKeys.length; i++) {
00462       hashedKeysV.add(hashedKeys[i]);    
00463       cache[i] = new HashMap();
00464     }
00465   }
00466 
00477   synchronized void add(Bundle bundle, ServiceListener listener, String filter)
00478   throws InvalidSyntaxException {
00479     ServiceListenerEntry sle = new ServiceListenerEntry(bundle, listener, filter);
00480     if (serviceSet.contains(sle)) {
00481       remove(bundle, listener);
00482     }
00483     serviceSet.add(sle);
00484     checkSimple(sle);
00485   }
00486 
00493   synchronized void remove(Bundle bundle, ServiceListener listener) {
00494     for (Iterator it = serviceSet.iterator(); it.hasNext();) {
00495       ServiceListenerEntry sle = (ServiceListenerEntry)it.next();
00496       if (sle.bundle == bundle && sle.listener == listener) {
00497         removeFromCache(sle);
00498         it.remove();
00499         break;
00500       }
00501     }
00502   }
00503 
00508   private void removeFromCache(ServiceListenerEntry sle) {
00509     if (sle.local_cache != null) {
00510       for (int i = 0; i < hashedKeys.length; i++) {
00511         HashMap keymap = (HashMap)cache[i];
00512         List l = (List)sle.local_cache[i];
00513         if (l != null) {
00514           for (Iterator it = l.iterator(); it.hasNext();) {
00515             Object value = it.next();
00516             List sles = (List)keymap.get(value);
00517             sles.remove(sles.indexOf(sle));
00518             if (sles.isEmpty()) {
00519               keymap.remove(value);
00520             }
00521           }       
00522         }
00523       }
00524     } else {
00525       complicatedListeners.remove(sle);
00526     }
00527   }
00528 
00534   synchronized void removeAll(Bundle bundle) {
00535     for (Iterator it = serviceSet.iterator(); it.hasNext();) {
00536       ServiceListenerEntry sle = (ServiceListenerEntry)it.next();
00537       if (sle.bundle == bundle) {
00538         removeFromCache(sle);
00539         it.remove();
00540       }
00541     }
00542   }
00543 
00548   public void checkSimple(ServiceListenerEntry sle) {
00549     if (sle.ldap == null || Listeners.nocacheldap) {
00550       complicatedListeners.add(sle);
00551     } else {
00552       List[] /* Value */ local_cache = new List[hashedKeys.length];
00553       if (sle.ldap.isSimple(hashedKeysV, local_cache)) {
00554         sle.local_cache = local_cache;
00555         for (int i = 0; i < hashedKeys.length; i++) {
00556           if (local_cache[i] != null) {
00557             for (Iterator it = local_cache[i].iterator(); it.hasNext();) {
00558               Object value = it.next();
00559               List sles = (List)cache[i].get(value);
00560               if (sles == null)
00561                 cache[i].put(value, sles = new ArrayList());
00562               sles.add(sle);
00563             }
00564           }
00565         }
00566       } else {
00567         if (Debug.ldap)
00568           Debug.println("Too complicated filter: " + sle.ldap);
00569         complicatedListeners.add(sle);
00570       }
00571     }
00572   }
00573 
00580   synchronized Set getMatchingListeners(ServiceReferenceImpl sr) {
00581     Set set = new HashSet();    
00582     // Check complicated or empty listener filters
00583     int n = 0;
00584     for (Iterator it = complicatedListeners.iterator(); it.hasNext(); n++) {
00585       ServiceListenerEntry sle = (ServiceListenerEntry)it.next();
00586       if (sle.ldap == null || sle.ldap.evaluate(sr.getProperties(), false)) {
00587         set.add(sle);
00588       }
00589     }
00590     if (Debug.ldap) {
00591       Debug.println("Added " + set.size() + " out of " + n + " listeners with complicated filters");
00592     }
00593     // Check the cache
00594     String[] c = (String[])sr.getProperty(Constants.OBJECTCLASS);
00595     for (int i = 0; i < c.length; i++) {
00596       if (Debug.ldap) {
00597         System.err.print("objectclass matches: ");
00598       }
00599       addToSet(set, (List)cache[OBJECTCLASS_IX].get(c[i]));
00600     }
00601     Long service_id = (Long)sr.getProperty(Constants.SERVICE_ID);
00602     if (service_id != null) {
00603       if (Debug.ldap) {
00604         System.err.print("service_id matches: ");
00605       }
00606       addToSet(set, (List)cache[SERVICE_ID_IX].get(service_id.toString()));
00607     }
00608     Object service_pid = sr.getProperty(Constants.SERVICE_PID);
00609     if (service_pid != null && service_pid instanceof String) {
00610       if (Debug.ldap) {
00611         System.err.print("service_pid matches: ");
00612       }
00613       addToSet(set, (List)cache[SERVICE_PID_IX].get(service_pid));
00614     }
00615     return set;
00616   }
00617 
00621   private void addToSet(Set set, List l) {
00622     if (l != null) {
00623       if (Debug.ldap) {
00624         Debug.println(Integer.toString(l.size()));
00625       }
00626       for (Iterator it = l.iterator(); it.hasNext();) {
00627         set.add(it.next());
00628       }
00629     } else {
00630       if (Debug.ldap) { 
00631         Debug.println("0");
00632       }
00633     }
00634   }
00635 }

Generated on Mon Jan 11 21:19:15 2010 for OpenMobileIS by  doxygen 1.5.4