8.5. Putting It Together

In this section we give a comprehensive example showing how the standard services we have covered so far can be used together. We develop a bundle that registers a servlet with the HTTP service and allows you to configure the serial ports through a Web interface as shown in Figure 8.6.

Figure 8.6. A Web interface for configuring the serial port


The servlet looks up the framework service registry for instances of SerialServices. It then presents the parameters—baud rate, data bits, stop bits, and parity—for each SerialService's serial port in an HTML form. A user can select different settings using the pull-down menu and can effect the change by pressing the Set button.

This servlet is only responsible for serial ports that have some device attached to them, because it searches for SerialService instances. This exemplifies how a client bundle can work with DA.

In the bundle's activator, the servlet is registered with the HTTP service. The BundleContext object is passed to the servlet's constructor, because the servlet needs to access the service registry and to get/unget the serial services. (The full listing is located in Appendix A, section A.2.3.1.)

Here is the source code for the servlet. As part of response to a GET request, it displays a user interface in HTML. It changes the settings on the serial port when a POST is received:

package com.acme.gui.serial;
// imports

class SerialServlet extends HttpServlet {

   private BundleContext context;
   private static int[] bauds = { 2400, 4800, 9600, 19200,
      28800, 38400, 57600, 115200 };
   private static int[] dataBits = { SerialPort.DATABITS_5,
      SerialPort.DATABITS_6,
      SerialPort.DATABITS_7,
      SerialPort.DATABITS_8 };
   private static String[] dataBitsLabel = { "5", "6", "7", "8" };
   private static int[] parity = { SerialPort.PARITY_NONE,
      SerialPort.PARITY_ODD,
      SerialPort.PARITY_EVEN,
      SerialPort.PARITY_MARK,
      SerialPort.PARITY_SPACE };
   private static String[] parityLabel = { "None", "Odd", "Even",
      "Mark","Space" };
   private static int[] stopBits = { SerialPort.STOPBITS_1,
      SerialPort.STOPBITS_2,
      SerialPort.STOPBITS_1_5 };
   private static String[] stopBitsLabel = { "1", "2", "1.5" };

   SerialServlet(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);
      try {
         ServiceReference[] refs = context.getServiceReferences(
            "com.acme.service.device.serial.SerialService",
             null);
         if (refs == null) {
            out.println("<i>No device is found to be attached "+
                  "to any of the serial ports.</i>");
         } else {
            for (int i=0; i<refs.length; i++)
                  displayControl(out, refs[i]);
         }
      } catch (InvalidSyntaxException e) {
      }
      displayFooter(out);
      out.close();
   }

   public void doPost(HttpServletRequest req,
            HttpServletResponse resp)
      throws ServletException, IOException
   {
      String message = null;
      String portName = req.getParameter("port");
      try {
            ServiceReference[] refs = context.getServiceReferences(
               "com.acme.service.device.serial.SerialService",
               "(Port=" + portName + ")");
            if (refs != null) {
               SerialService ss = (SerialService)
                  context.getService(refs[0]);
               SerialPort port = ss.getPort();
               int baud = Integer.parseInt(
                  req.getParameter("baud_select"));
               int databits = Integer.parseInt(
                  req.getParameter("databits_select"));
               int stopbits = Integer.parseInt(
                  req.getParameter("stopbits_select"));
               int parity = Integer.parseInt(
                  req.getParameter("parity_select"));
                port.setSerialPortParams(baud, databits,
                  stopbits, parity);
            } else {
               message = "<i>Could not set serial port parameters: "+
                     "no device is attached to " + portName +
                     " any longer.</i>";
            }
      } catch (InvalidSyntaxException e) {
      } catch (UnsupportedCommOperationException e) {
             message = "<i>Failed to set serial port parameters: "+
             e.toString() + "</i>";
       }
      if (message != null) {
            ServletOutputStream out = resp.getOutputStream();
            resp.setContentType("text/html");
            displayHeader(out);
            out.println(message);
            displayFooter(out);
            out.close();
      } else {
            resp.sendRedirect("/serialports");
      }
   }
   private void displayControl(ServletOutputStream out,
         ServiceReference ref)
      throws ServletException, IOException
   {
      SerialService ss = (SerialService) context.getService(ref);
      SerialPort port = ss.getPort();
      String name = port.getName();
      // display an HTML form
      // present four <select> pull-down menus with valid options
      // for baud rate, data bits, stop bits, and parity
      // call port.getBaudRate(), port.getDataBits(),
      // port.getStopBits(), and port.getParity() to
      // obtain the current settings
      // select the current settings in the four pull-down menus
      context.ungetService(ref);
   }

   private void displayHeader(ServletOutputStream out)
      throws ServletException, IOException
   {
      // display HTML headers
   }

   private void displayFooter(ServletOutputStream out)
      throws ServletException, IOException
   {
      // display HTML footers
    }
}

This example depends on DA-related bundles: log.jar, device.jar, and serial.jar, as well as HTTP-related bundles: servlet.jar and http.jar. Their packages needs to be imported to this bundle, whose manifest is defined as follows:

Bundle-Activator: com.acme.gui.serial.Activator
Import-Package: org.osgi.service.http,
 com.acme.service.device.serial,
 javax.servlet, javax.servlet.http

The serial service may come and go. As a result, the servlet is designed to be stateless. Each time it needs to query or modify the parameters for a serial service instance, it retrieves it anew from the framework service registry. If the intended service has disappeared, an error message is displayed in the browser.

A more sophisticated scheme is to maintain up-to-date state of the serial services in the servlet, which can be achieved by listening to the registration/unregistration events of the service. If we program an applet to receive the events, we can provide the user with real-time usage of the serial port. With an HTML-based front end, however, it does not buy us much, because the user has to hit the Reload button on the browser anyway.

Perhaps the most important lesson we can learn from this example is how to expose the control interface through the browser using servlets. On the back end, it may be a thermostat, a gas meter, or a lamp module. Regardless, a flexible and familiar Web user interface can be put together just as easily.

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

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