Services.java

00001 /*
00002  * Copyright (c) 2003-2005, 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.Dictionary;
00039 import java.util.HashMap;
00040 import java.util.HashSet;
00041 import java.util.ArrayList;
00042 import java.util.Iterator;
00043 
00044 import org.osgi.framework.*;
00045 import org.osgi.service.packageadmin.PackageAdmin;
00046 import org.osgi.service.permissionadmin.PermissionAdmin;
00047 
00048 
00055 class Services {
00056 
00061   private HashMap /* serviceRegistration -> Array of Class Names */ services = new HashMap();
00062 
00066   private HashMap /* String->ServiceRegistration */ classServices = new HashMap();
00067   
00071   private PermissionOps secure;
00072 
00073 
00074   Services(PermissionOps perm) {
00075     secure = perm;
00076   }
00077 
00094   ServiceRegistration register(BundleImpl bundle,
00095                                String[] classes,
00096                                Object service,
00097                                Dictionary properties) {
00098     if (service == null) {
00099       throw new IllegalArgumentException("Can't register null as a service");
00100     }
00101     ServiceRegistration res;
00102     synchronized (this) {
00103       // Check if service implements claimed classes and that they exist.
00104       Class sc = service.getClass();
00105       ClassLoader scl = sc.getClassLoader();
00106       for (int i = 0; i < classes.length; i++) {
00107         String cls = classes[i];
00108         if (cls == null) {
00109           throw new IllegalArgumentException("Can't register as null class");
00110         }
00111         secure.checkRegisterServicePerm(cls);
00112         if (bundle.id != 0) {
00113           if (cls.equals(PackageAdmin.class.getName())) {
00114             throw new IllegalArgumentException("Registeration of a PackageAdmin service is not allowed");
00115           }
00116           if (cls.equals(PermissionAdmin.class.getName())) {
00117             throw new IllegalArgumentException("Registeration of a PermissionAdmin service is not allowed");
00118           }
00119         }
00120         if (!(service instanceof ServiceFactory)) {
00121           ClassLoader cl = sc.getClassLoader();
00122           Class c = null;
00123           boolean ok = false;
00124           try {
00125             if (cl != null) {
00126               c = cl.loadClass(cls);
00127             } else {
00128               c = Class.forName(cls);
00129             }
00130             ok = c.isInstance(service);
00131           } catch (ClassNotFoundException e) {
00132             for (Class csc = sc; csc != null; csc = csc.getSuperclass()) {
00133               if (cls.equals(csc.getName())) {
00134                 ok = true;
00135                 break;
00136               } else {
00137                 Class [] ic = csc.getInterfaces();
00138                 for (int iic = ic.length - 1; iic >= 0; iic--) {
00139                   if (cls.equals(ic[iic].getName())) {
00140                     ok = true;
00141                     break;
00142                   }
00143                 }
00144               }
00145             }
00146           }
00147           if (!ok) {
00148             throw new IllegalArgumentException("Service object is not an instance of " + cls);
00149           }
00150         }
00151       }
00152 
00153       res = new ServiceRegistrationImpl(bundle, service,
00154                                         new PropertiesDictionary(properties, classes, null));
00155       services.put(res, classes);
00156       for (int i = 0; i < classes.length; i++) {
00157         ArrayList s = (ArrayList) classServices.get(classes[i]);
00158         if (s == null) {
00159           s = new ArrayList(1);
00160           classServices.put(classes[i], s);
00161         }
00162         s.add(res);
00163       }
00164     }
00165     bundle.framework.listeners.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, res.getReference()));
00166     return res;
00167   }
00168 
00169 
00177   synchronized ServiceReference get(BundleImpl bundle, String clazz) {
00178         //TODO spec omits to say when to do the isAssignableTo test
00179     ArrayList v = (ArrayList) classServices.get(clazz);
00180     if (v != null) {
00181       ServiceReference lowestId = ((ServiceRegistration)v.get(0)).getReference();
00182       ServiceReference res = lowestId;
00183       int size = v.size();
00184       if (size > 1) {
00185           int rank_res = ranking(res);
00186           for (int i = 1; i < size; i++) {
00187                   ServiceReference s = ((ServiceRegistration)v.get(i)).getReference();
00188                   int rank_s = ranking(s);
00189                   if (rank_s > rank_res && s.isAssignableTo(bundle, clazz)) {
00190                           res = s;
00191                           rank_res = rank_s;
00192                   }
00193           }
00194       }
00195       if(res == lowestId){
00196           if(res.isAssignableTo(bundle, clazz)){
00197                   return res;
00198           }
00199           else{
00200                   return null;
00201           }
00202       }
00203       else{
00204           return res;
00205       }
00206     } 
00207     else {
00208       return null;
00209     }
00210   }
00211 
00212 
00226   synchronized ServiceReference[] get(String clazz, String filter, BundleImpl bundle,
00227                                               boolean doAssignableToTest)
00228     throws InvalidSyntaxException {
00229     Iterator s;
00230     if (clazz == null) {
00231       s = services.keySet().iterator();
00232       if (s == null) { //TODO can this ever happen?
00233         return null;
00234       }
00235     } else {
00236       ArrayList v = (ArrayList) classServices.get(clazz);
00237       if (v != null) {
00238         s = v.iterator();
00239       } else {
00240         return null;
00241       }
00242     }
00243     ArrayList res = new ArrayList();
00244     while (s.hasNext()) {
00245       ServiceRegistrationImpl sr = (ServiceRegistrationImpl)s.next();
00246       String[] classes = (String[]) services.get(sr);
00247       //should never happen?
00248       if (classes == null) {
00249         return null;
00250       }
00251       if (!secure.okGetServicePerms(classes)) {
00252         continue; //sr not part of returned set
00253       }
00254       if (filter == null || LDAPExpr.query(filter, sr.properties)) {
00255         if (doAssignableToTest) {
00256           int i;
00257           int length = classes.length;
00258           for (i = 0; i < length; i++) {
00259             if(!sr.getReference().isAssignableTo(bundle, classes[i])){
00260               break;
00261             }
00262           }
00263           if (i == length) {
00264             res.add(sr.getReference());
00265           }
00266         } else {
00267           res.add(sr.getReference());
00268         }
00269       }
00270     }
00271     if (res.isEmpty()) {
00272       return null;
00273     } else {
00274       ServiceReference[] a = new ServiceReference[res.size()];
00275       res.toArray((Object[])a);
00276       return a;
00277     }
00278   }
00279 
00280 
00286   synchronized void removeServiceRegistration(ServiceRegistrationImpl sr) {
00287     String[] classes = (String[]) sr.properties.get(Constants.OBJECTCLASS);
00288     services.remove(sr);
00289     for (int i = 0; i < classes.length; i++) {
00290       ArrayList s = (ArrayList) classServices.get(classes[i]);
00291       if (s.size() > 1) {
00292         s.remove(sr);
00293       } else {
00294         classServices.remove(classes[i]);
00295       }
00296     }
00297   }
00298 
00299 
00306   synchronized Set getRegisteredByBundle(Bundle b) {
00307     HashSet res = new HashSet();
00308     for (Iterator e = services.keySet().iterator(); e.hasNext();) {
00309       ServiceRegistrationImpl sr = (ServiceRegistrationImpl)e.next();
00310       if (sr.bundle == b) {
00311         res.add(sr);
00312       }
00313     }
00314     return res;
00315   }
00316 
00317 
00324   synchronized Set getUsedByBundle(Bundle b) {
00325     HashSet res = new HashSet();
00326     for (Iterator e = services.keySet().iterator(); e.hasNext();) {
00327       ServiceRegistrationImpl sr = (ServiceRegistrationImpl)e.next();
00328       if (sr.isUsedByBundle(b)) {
00329         res.add(sr);
00330       }
00331     }
00332     return res;
00333   }
00334 
00335   //
00336   // Private methods
00337   //
00338     
00345   private int ranking(ServiceReference s) {
00346     Object v = s.getProperty(Constants.SERVICE_RANKING);
00347     if (v != null && v instanceof Integer) {
00348       return ((Integer)v).intValue();
00349     } else {
00350       return 0;
00351     }
00352   }
00353 
00354 }

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