A.3. Chapter 9—Permission-based Security and Administration

A.3.1. Parameter Services

The parameter bundle provides a comprehensive example that illustrates the following features:

  • Service factory

  • Asynchronous event handling

  • Permission checking

  • Performing privileged actions

In a Java run-time environment that does not support permissions, comment out the security-related code.

A.3.1.1. com/acme/service/param/ParamService.java
package com.acme.service.param;
/**
 * This service allows a caller to store and retrieve parameters
 * in the form of a key/value pair.
 */
public interface ParameterService {
   /**
    * Stores a parameter.
    * @param key the name of the parameter.
    * @param value the value of the parameter.
    */
   public void set(String key, String value);

   /**
    * Retrieves a parameter.
    */
   public String get(String key);
}

A.3.1.2. com/acme/service/param/ParameterAdmin.java
package com.acme.service.param;
import java.io.IOException;
import java.util.Properties;

public interface ParameterAdmin {
   /**
    * Stores a parameter set for a bundle.
    * @param bundleLocation the location of the bundle.
    * @param props the parameter set.
    * @exception java.io.IOException if saving to the property file
    *       fails.
    * @exception java.security.SecurityException if the caller does
    *       not have AdminPermission and the Java runtime supports
    *       permissions.
    */
   public void set(String bundleLocation, Properties props)
         throws IOException;

   /**
    * Retrieves the parameter set for a bundle.
    *
    * @exception java.security.SecurityException if the caller does
    *       not have AdminPermission and the Java runtime supports
    *       permissions.
    */
   public Properties get(String bundleLocation)
         throws IOException;
}

A.3.1.3. com/acme/impl/param/ParameterServiceImpl.java
package com.acme.impl.param;
import java.util.*;
import com.acme.service.param.ParameterService;

class ParameterServiceImpl implements ParameterService {
   Properties props;
   public void set(String key, String value) {
      props.put(key, value);
   }

   public String get(String key) {
      return props.get(key);
   }

   ParameterServiceImpl(Properties initProps) {
      if (initProps != null) // copy initial parameters if any
         props = (Properties) initProps.clone();
      else
         props = new Properties();
   }
}

A.3.1.4. com/acme/impl/param/ParameterServiceFactory.java
package com.acme.impl.param;
import java.io.IOException;
import java.util.Properties;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;

class ParameterServiceFactory implements ServiceFactory {
   private ParameterStore store;

   ParameterServiceFactory(ParameterStore store) {
      this.store = store;
   }

   // A client bundle starts using ParameterService.
   public Object getService(Bundle bundle, ServiceRegistration reg)
   {
      try {
         return new ParameterServiceImpl(store.load(bundle));
      } catch (IOException e) {
         // should log the exception
      }
      return new ParameterServiceImpl(null);
   }

   // The client bundle finishes using ParameterService.
   public void ungetService(Bundle bundle, ServiceRegistration reg,
                            Object service)
   {
      ParameterServiceImpl ps = (ParameterServiceImpl) service;
      try {
         store.save(bundle, ps.props);
      } catch (IOException e) {
         // should log the exception
      }
   }
}

A.3.1.5. com/acme/impl/param/ParameterAdminImpl.java
package com.acme.impl.param;
import java.util.Properties;
import java.io.IOException;
import org.osgi.framework.*;
import com.acme.service.param.ParameterAdmin;

class ParameterAdminImpl implements ParameterAdmin {
   private static AdminPermission adminPermission =
      new AdminPermission();
   private BundleContext context;
   private ParameterStore store;

   ParameterAdminImpl(BundleContext ctxt, ParameterStore store) {
      this.context = ctxt;
      this.store = store;
   }

   public void set(String loc, Properties props)
      throws IOException
   {
      sm = System.getSecurityManager();
      if (sm != null) {
         sm.checkPermission(adminPermission);
      }
      Bundle b = getBundle(loc);
      if (b == null)
         throw new IOException("Bundle (" + loc +
            ") not installed");
      store.save(b, props);
   }

   public Properties get(String loc) throws IOException {
      SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
         sm.checkPermission(adminPermission);
      }
      Bundle b = getBundle(loc);
      if (b == null)
         throw new IOException("Bundle (" + loc +
            ") not installed");
      return store.load(b);
   }

   private Bundle getBundle(String loc) {
      Bundle[] bundles = context.getBundles();
      for (int i=0; i<bundles.length; i++) {
         if (bundles[i].getLocation().equals(loc)) {
            return bundles[i];
         }
      }
      return null;
   }
}

A.3.1.6. com/acme/impl/param/ParameterStore.java
package com.acme.impl.param;
import java.io.*;
import java.util.Properties;
import java.security.*;
import org.osgi.framework.*;

class ParameterStore {
   static final String FILENAME = "parameters.properties";
   private File dataRoot;
   ParameterStore(BundleContext ctxt) {
      this.dataRoot = ctxt.getDataFile("");
   }

   synchronized void save(final Bundle b, final Properties props)
      throws IOException
   {
       try {
          AccessController.doPrivileged(
             new PrivilegedExceptionAction() {
                public Object run() throws IOException {
                  String id = Long.toString(b.getBundleId());
                  File paramDir = new File(dataRoot, id);
                  if (! paramDir.exists()) {
                     if (! paramDir.mkdir())
                        throw new IOException(
                           "Couldn't create dir: "+ paramDir);
                  }
                  File paramFile = new File(paramDir, FILENAME);
                  FileOutputStream out =
                     new FileOutputStream(paramFile);
                  props.save(out, "Parameters for " +
                     b.getLocation());
                  out.close();
                   return null;
                }
             });
          } catch (PrivilegedActionException e) {
             throw (IOException) e.getException();
          }
   }

   synchronized Properties load(final Bundle b) throws IOException {
      Properties props = null;
      try {
         props = (Properties)
            AccessController.doPrivileged(
               new PrivilegedExceptionAction()
            {
               public Object run() throws IOException {
               Properties p = new Properties();
               String id = Long.toString(b.getBundleId());
               File paramFile = new File(dataRoot,
                    id + File.separator +
                    FILENAME);
               if (!paramFile.exists())
                  return null;
               FileInputStream in =
                  new FileInputStream(paramFile);
               p.load(in);
               in.close();
               return p;
            }
         });
      } catch (PrivilegedActionException e) {
         throw (IOException) e.getException();
      }
      return props;
   }

   synchronized void clear(Bundle b) {
      final long id = b.getBundleId();
      String[] ids = dataRoot.list();
      for (int i=0; i<ids.length; i++) {
         try {
            if (id != Long.parseLong(ids[i]))
               continue;
            AccessController.doPrivileged(
               new PrivilegedAction()
            {
               public Object run() {
                  File paramFile = new File(dataRoot, id +
                     File.separator + FILENAME);
                  paramFile.delete();
                  File paramDir = new File(dataRoot,
                     Long.toString(id));
                  paramDir.delete();
                  return null;
                  }
            });
            break;
         } catch (NumberFormatException e) {
         }
      }
   }
}

A.3.1.7. com/acme/impl/param/Activator.java
package com.acme.impl.param;
import java.io.*;
import org.osgi.framework.*;

public class Activator implements BundleActivator {
   private ServiceRegistration reg;

   public void start(BundleContext ctxt) {
      final ParameterStore store = new ParameterStore(ctxt);
      // add a bundle listener listening to
      // uninstallation of client bundles
      ctxt.addBundleListener(new BundleListener() {
         public void bundleChanged(BundleEvent e) {
            // we are only interested in bundle uninstalled event
            if (e.getType() != BundleEvent.UNINSTALLED)
               return;
            store.clear(e.getBundle());
         }
      });
      reg = ctxt.registerService(
         "com.acme.service.param.ParameterService",
         new ParameterServiceFactory(store), null);
      ctxt.registerService(
         "com.acme.service.param.ParameterAdmin",
         new ParameterAdminImpl(ctxt, store), null);
   }

   public void stop(BundleContext ctxt) {
      if (reg != null)
         reg.unregister();
   }
}

A.3.1.8. com/acme/impl/param/Manifest
Bundle-Activator: com.acme.impl.param.Activator
Export-Package: com.acme.service.param

A.3.2. Parameter Configuration Servlet

A.3.2.1. com/acme/admin/param/AdminServlet.java
package com.acme.admin.param;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.osgi.framework.*;
import com.acme.service.param.ParameterAdmin;

class AdminServlet extends HttpServlet {
   private BundleContext context;
   static final String TAG_NEW_PROP_NAME =
      "com.acme.admin.new.property.name";
   static final String TAG_NEW_PROP_VALUE =
      "com.acme.admin.new.property.value";
   static final String TAG_BUNDLE_ID =
      "com.acme.admin.bundle.id";

   AdminServlet(BundleContext ctxt) {
      this.context = ctxt;
   }

   public void doGet(HttpServletRequest req,
           HttpServletResponse resp)
      throws ServletException, IOException
   {
      ServletOutputStream out = resp.getOutputStream();
      resp.setContentType("text/html");
      displayHeader(out);
      String idstr = req.getParameter("id");
      if (idstr == null) {
         displayAllBundles(out);
      } else {
         long bundleId = Long.parseLong(idstr);
         displayForm(out, bundleId);
      }
      displayFooter(out);
      out.close();
   }

   public void doPost(HttpServletRequest req,
             HttpServletResponse resp)
      throws ServletException, IOException
   {
      Properties props = new Properties();
      String newPropName = null;
      String newPropVal  = null;
      Enumeration propNames = req.getParameterNames();
      while (propNames.hasMoreElements()) {
         String k = (String) propNames.nextElement();
         String v = req.getParameter(k);
         if (TAG_NEW_PROP_NAME.equals(k))
            newPropName = v;
         else if (TAG_NEW_PROP_VALUE.equals(k))
            newPropVal  = v;
         else if (! (TAG_BUNDLE_ID.equals(k))) {
            if (v.length() > 0)
               props.put(k, v);
         }
      }
      if (newPropName.length() > 0 && newPropVal.length() > 0)
         props.put(newPropName, newPropVal);
      ServiceReference ref = context.getServiceReference(
         "com.acme.service.param.ParameterAdmin");
      ParameterAdmin admin =
         (ParameterAdmin) context.getService(ref);
      long id = Long.parseLong(req.getParameter(TAG_BUNDLE_ID));
      Bundle b = context.getBundle(id);
      admin.set(b.getLocation(), props);
      context.ungetService(ref);
      resp.sendRedirect(Activator.SERVLET_ALIAS + "?id=" + id);
   }
   private void displayAllBundles(ServletOutputStream out)
      throws ServletException, IOException
   {
      Bundle[] bundles = context.getBundles();
      if (bundles == null) {
         out.println("<i>No bundle is installed " +
            "in the framework.</i>");
      } else {
         out.println("The following bundles are currently " +
            "installed in the framework:
" +
            "<p>
" +
            "<ul>
");
         for (int i=0; i<bundles.length; i++)
            out.println("<li>" +
               "<a href="" + Activator.SERVLET_ALIAS +
               "?id=" + bundles[i].getBundleId() +
               "">" +  bundles[i].getLocation() +
               "</a>
");
         out.println("</ul>
");
      }
   }

   private void displayForm(ServletOutputStream out, long id)
      throws ServletException, IOException
   {
      Bundle b = context.getBundle(id);
      ServiceReference ref = context.getServiceReference(
         "com.acme.service.param.ParameterAdmin");
      ParameterAdmin admin =
         (ParameterAdmin) context.getService(ref);
      Properties props = admin.get(b.getLocation());
      context.ungetService(ref);
      out.println("<b>Bundle</b>: " + b.getLocation() + "<p>
");
      if (props == null) {
         out.println("<i>There is no property " +
            "for this bundle.</i>");
      }
      out.println("<form action="" +
         Activator.SERVLET_ALIAS + "" method=post>
");
      out.println("<table border=0>
" +
         "<tr><th align=left>Property Name</th>" +
         "<th align=left>Value</th></tr>
");
      if (props != null)
         for (Enumeration propNames = props.propertyNames();
            propNames.hasMoreElements(); )
         {
            String propName = (String) propNames.nextElement();
            String propVal  = props.getProperty(propName);
            out.println("<tr>
" +
               "<td>" + propName + "</td>" +
               "<td><input name="" + propName + "" " +
               "value="" + propVal + "" size=" +
               (propVal.length() + 5) +"></td>
" +
               "</tr>
");
         }
      out.println("<tr>
" +
         "<td><input name="" + TAG_NEW_PROP_NAME + "" "+
         "size=25></td>" +
         "<td><input name="" + TAG_NEW_PROP_VALUE + "" "+
         "size=25></td>
" +
         "</tr>
");
      out.println("</table><p>
" +
         "<input type=hidden name="" + TAG_BUNDLE_ID + "" " +
         "value="" + id + "">
" +
         "<input type=submit value="Set"> " +
         "<input type=reset> " +
         "[<a href="" + Activator.SERVLET_ALIAS +
         "">Done</a>]
" +
         "</form>
");
   }

   private void displayHeader(ServletOutputStream out)
      throws ServletException, IOException
   {
      out.println("<HTML>
" +
         "<HEAD>
" +
         "<TITLE>Bundle Parameter Configuration</TITLE>
" +
         "</HEAD>
" +
         "<BODY BGCOLOR=white>
" +
         "<h2>Bundle Parameter Configuration</h2>
" +
         "<p>
");
   }
   private void displayFooter(ServletOutputStream out)
      throws ServletException, IOException
   {
      out.println("</BODY>
" +
         "</HTML>");
   }
}

A.3.2.2. com/acme/admin/param/Activator.java
package com.acme.admin.param;
import java.net.*;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.osgi.framework.*;
import org.osgi.service.http.*;
import com.acme.service.param.ParameterAdmin;

public class Activator implements BundleActivator {
   private HttpService http;
   final static String SERVLET_ALIAS = "/admin/parameters";

   public void start(BundleContext context) throws Exception   {
      ServiceReference ref = context.getServiceReference(
         "org.osgi.service.http.HttpService");
      http = (HttpService) context.getService(ref);
         AdminServlet servlet = new AdminServlet(context);
         http.registerServlet(SERVLET_ALIAS, servlet, null, null);
   }

   public void stop(BundleContext context) throws Exception {
      if (http != null) {
         http.unregister(SERVLET_ALIAS);
      }
   }
}

A.3.2.3. com/acme/admin/param/Manifest
Bundle-Activator: com.acme.admin.param.Activator
Import-Package: com.acme.service.param,
 org.osgi.service.http,
 javax.servlet, javax.servlet.http
Bundle-Name: The Administrative Bundle
Bundle-Description: This bundle can access and modify parameters for
 other bundles. It requires org.osgi.framework.AdminPermission, and
 provides a web user interface at http://<host>:8080/admin.
Bundle-Vendor: Acme Systems, Inc.
Bundle-Version: 1.0
Bundle-DocURL: http://www.acme.com/bundles/admin/index.html
Bundle-ContactAddress: [email protected]
Import-Service: com.acme.service.param.ParameterAdmin

A.3.3. Facilitator

A.3.3.1. com/acme/admin/resolv/Facilitator.java
package com.acme.admin.resolv;
import java.util.*;
import java.net.*;
import java.io.*;
import org.osgi.framework.*;

/**
 * This class performs recursive bundle resolution. It parses a
 * bundle's Import-Package manifest header and installs/activates
 * the bundles that export the needed packages.
 */
class Facilitator {
   private BundleContext context;
   /**
    * The map that encapsulates the knowledge of given a package,
    * which bundle exports that package, and at what version. It maps
    * a package name to the exporting bundle's location and the
    * package version.
    */
   private Properties packageExporterMap;
   // Flag a visited bundle to prevent following circular dependency
   // during recursion.
   private Hashtable visited = new Hashtable();
   // Identify the unsatisfied bundle when resolution fails.
   // maps an unresolved bundle to a vector of missing package names
   private Hashtable unsatisfiedBundles = new Hashtable();

   /**
    * The constructor. It reads the package exporter map from a
    * property file inside this bundle.
    */
   Facilitator(BundleContext ctxt) throws IOException {
      this.context = ctxt;
      this.packageExporterMap = new Properties();
      String resourceName =
         "/com/acme/admin/resolv/package-exporters.map";
      InputStream in =
         this.getClass().getResourceAsStream(resourceName);
      packageExporterMap.load(in);
   }

   /**
    * Reset the internal state so that the resolution process can be
    * run anew.
    */
   void reset() {
      visited.clear();
      unsatisfiedBundles.clear();
   }

   /**
    * Resolve a bundle. It follows this algorithm: (1) install the
    * bundle whose location is given, (2) parse the bundle's
    * Import-Package manifest header, (3) based on the packages it
    * needs to import, look up the package exporter map to find
    * out what additional bundles should be installed,
    * (4) recursively perform this sequence until all bundles are
    * resolved or a bundle cannot be resolved.
    *
    * @param urlstr the location string of the bundle to be resolved.
    * @return true if all bundles are resolved, false otherwise. If
    * not resolved, the unsatisfied bundle can be retrieved by
    * calling getUnsatisfiedBundle and the missing package name is
    * returned by getMissingPackage method.
    */
   boolean resolve(String urlstr) throws BundleException {
      if (urlstr == null)
         return false;
      if (visited.get(urlstr) != null) {
         // if a bundle is processed, don't run in circles
         return true;
      }
      Bundle b = context.installBundle(urlstr);
      // flag that the bundle is processed
      visited.put(urlstr, Boolean.TRUE);
      Dictionary headers = b.getHeaders();
      String imports = (String) headers.get("Import-Package");
      boolean r = true;
      if (imports != null) {
         String[] loc = findExporters(imports, b);
         for (int i=0; i<loc.length; i++) {
            r = r & resolve(loc[i]);
         }
      }
      if (r) {
         b.start();
      }
      return r;
   }

   /**
    * Return the names of the missing packages for the given bundle,
    * or null if all bundles are resolved.
    */
   String[] getMissingPackages(Bundle b) {
      if (b == null)
         return null;
      Vector pkgsVec = (Vector) unsatisfiedBundles.get(b);
      String[] pkgs = null;
      if (pkgsVec != null && pkgsVec.size() > 0) {
         pkgs = new String[pkgsVec.size()];
         pkgsVec.copyInto(pkgs);
      }
      return pkgs;
   }
   /**
    * Return the unsatisfied bundles, or an empty enumeration if
    * all bundles are resolved.
    */
   Enumeration getUnsatisfiedBundles() {
      return unsatisfiedBundles.keys();
   }

   /**
    * Find the exporters for the packages needed by the given bundle.
    *
    * @param imports the value of the Import-Package header.
    * @param b the bundle that defines the Import-Package header.
    * @return the locations of the bundles that export the needed
    * package at the compatible versions.
    */
   private String[] findExporters(String imports, Bundle b) {
      StringTokenizer st = new StringTokenizer(imports, ",");
      Vector missingPkgs = null;
      Vector v = new Vector(st.countTokens());
      while (st.hasMoreTokens()) {
         String token = st.nextToken().trim();
         int semicolonPos = token.indexOf(';'),
         String pkgname = token;
         String importVersion = "";
         if (semicolonPos != -1) {
            pkgname = token.substring(0, semicolonPos).trim();
            int eqPos = token.indexOf('=', semicolonPos);
            importVersion = token.substring(eqPos + 1);
         }
         if (isFromClasspath(pkgname))
            continue;
         String loc = (String) packageExporterMap.get(pkgname);
         if (loc != null) {
            String exportVersion = "";
            int commaPos = loc.indexOf(','),
            if (commaPos != -1) {
               exportVersion = loc.substring(commaPos + 1);
               loc = loc.substring(0, commaPos);
            }
            if (! areVersionsCompatible(importVersion,
               exportVersion))
            {
               loc = null;
            }
         }
         if (loc == null) {
            if (missingPkgs == null)
               missingPkgs = new Vector();
            missingPkgs.addElement(pkgname);
         }
         v.addElement(loc);
      }
      String[] locations = new String[v.size()];
         v.copyInto(locations);
      if (missingPkgs != null)
         unsatisfiedBundles.put(b, missingPkgs);
      return locations;
   }

   /**
    * Check if a package is on the CLASSPATH.
    */
   private boolean isFromClasspath(String pkg) {
      URL u = ClassLoader.getSystemResource(pkg.replace('.','/')
         + "/");
      return u != null;
   }

   /**
    * Check if a package version for export is equal to or greater
    * than the version required for importing the same package.
    *
    * @param impVerStr the package version string required for
    * import.
    * @param expVerStr the package version string for export.
    * @return true if the check passes, false otherwise.
    */
   private boolean areVersionsCompatible(String impVerStr,
      String expVerStr)
   {
      StringTokenizer impst = new StringTokenizer(impVerStr, ".");
      StringTokenizer expst = new StringTokenizer(expVerStr, ".");
      try {
         while (impst.hasMoreTokens() && expst.hasMoreTokens()) {
            int iv = Integer.parseInt(impst.nextToken().trim());
            int ev = Integer.parseInt(expst.nextToken().trim());
            if (ev < iv) {
               // E.g., if import needs 1.4.5, export is 1.3.6,
               // then import > export and no need to scan
               // further because at the second component, 4 > 3
               return false;
            } else if (ev > iv) {
               // E.g., if import needs 1.4.5, export is
               // 1.5.1, then import < export and no need to scan
               // further because at the second component, 4 < 5
               return true;
            }
         }
         if (impst.hasMoreTokens()) {
            // E.g., if import needs 1.4.5, export is 1.4, then
            // import > export
            return false;
         }
      } catch (NumberFormatException e) {
            return false;
      }
      return true;
   }
}

A.3.3.2. com/acme/admin/resolv/Activator.java
package com.acme.admin.resolv;
import java.net.*;
import java.io.*;
import java.util.*;
import org.osgi.framework.*;

public class Activator implements BundleActivator {
   private ServerThread server;

   public void start(BundleContext context) throws IOException {
      server = new ServerThread(context);
      server.start();
   }

   public void stop(BundleContext context) throws IOException {
      server.terminate();
   }
}

class ServerThread extends Thread {
   private Facilitator facilitator;
   private ServerSocket ss;
   private boolean running = true;
   private Vector clientConnections = new Vector(16);

   ServerThread(BundleContext ctxt) throws IOException {
      this.ss = new ServerSocket(8082, 5);
      facilitator = new Facilitator(ctxt);
   }

   public void run() {
      try {
         while(running) {
            Socket s = ss.accept();
            if (!running) {
               // server is being shut down
               break;
            }
            // accept a client connection
            ConnectionThread conn = this.new ConnectionThread(s);
            clientConnections.addElement(conn);
            // start a thread to handle it
            conn.start();
         }
         ss.close();
         ss = null;
      } catch (IOException e) {
         System.out.println(e);
      }
   }
   // terminate the server and clean up
   void terminate() throws IOException {
      // terminate each client connection
      for (int i=0; i<clientConnections.size(); i++) {
         ConnectionThread conn = (ConnectionThread)
            clientConnections.elementAt(i);
         conn.terminate();
      }
      clientConnections.removeAllElements();
      running = false;
      // force the server socket to return from accept
       if (ss != null) {
          ss.close();
       }
   }

   class ConnectionThread extends Thread {
      private Socket socket;

      ConnectionThread(Socket s) {
         this.socket  = s;
      }

      public void run() {
         PrintWriter out = null;
         try {
            InputStream  is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            BufferedReader in  =
               new BufferedReader(new InputStreamReader(is));
            out = new PrintWriter(os, true);
            out.print("
Bundle Resolution
" +
               "
Enter the bundle's URL: ");
            out.flush();
            // get command from remote host
            String url = in.readLine();
            facilitator.reset();
            if (facilitator.resolve(url)) {
               out.println("
OK");
            } else {
               Enumeration e =
                  facilitator.getUnsatisfiedBundles();
               while (e.hasMoreElements()) {
                  Bundle b = (Bundle) e.nextElement();
                  String[] pkgs =
                     facilitator.getMissingPackages(b);
                  out.println("Bundle " + b.getLocation() +
                     " needs the missing packages below:");
                  for (int i=0; i<pkgs.length; i++) {
                     out.println("  " + pkgs[i]);
                  }
               }
            }
            out.println();
         } catch (BundleException e) {
            out.println("
" + e);
            Throwable t = e.getNestedException();
            if (t != null)
               out.println("Nested exception: " + t);
            out.println();
         } catch (IOException e) {
         } finally {
            try {
               if (socket != null)
               socket.close();
            } catch(IOException e) {}
            clientConnections.removeElement(this);
         }
      }

      void terminate() throws IOException {
         // this will cause IOException to be raised from the
         // readLine call in the client thread
         socket.close();
         socket = null;
      }
   } // ConnectionThread
}

A.3.3.3. com/acme/admin/resolv/package-exporters.map
org.osgi.service.http=file:jes_path/bundles/http.jar
javax.servlet=file:jes_path/bundles/servlet.jar, 2.1.1
javax.servlet.http=file:jes_path/bundles/servlet.jar, 2.1.1
org.osgi.service.log=file:jes_path/bundles/log.jar, 1.0
com.acme.service.param=file:/home/joe/bundles/param.jar

A.3.3.4. com/acme/admin/resolv/Manifest
Bundle-Activator: com.acme.admin.resolv.Activator

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.232.189