Serve clients' specific protocol requirements with Brazil, Part 6

Plug Jini, BeanShell, and JAXM into Brazil

1 2 3 Page 2
Page 2 of 3
   try {
   Thread.sleep(5000);
   } catch (InterruptedException ie) {  }
   ServiceItem[] item = null;
   ServiceItemFilter filter = null;
   item = sdm.lookup(tmpl, 50, filter);

Display results, if any:

   System.out.println("Length:" + item.length );
   request.props.put("jini.lookup.number" , Integer.toString(item.length));
   String ids = "";
   String key = "jini.lookup.srvcs.";
   for ( int k = 0; k < item.length; k++) {
      String keyid = key + item[k].serviceID;
      ids += item[k].serviceID + " ";
      msg("Service type found, id=" + item[k].serviceID);
      msg("Service type found, service=" + item[k].service);
      if ( item[k].service instanceof BrazilService ) {
         BrazilService bs = item[k].service;
         try {
            String s = keyid +  ".url";
            request.props.put(s,bs.getURL());
         } catch ( Exception e ) {
            e.printStackTrace();
         }
      }
      Entry[] entry = item[k].attributeSets;
      for ( int i = 0; i < entry.length; i++) {
         msg("Service type found, attributes=" + entry[k] + 
"\n");
      }
      request.props.put(keyid , (item[k].service).toString());
      msg("\n\n");
   }
   request.props.put("jini.lookup.ids" , ids);

Tidy up:

   sdm.terminate();</bsh>

Once the BeanShell code processes, the following BSL generates some output for a user. We could also have generated XML or taken other actions. Here's the generated code:

 <!--   Display results-->
<center>
<if not name=jini.lookup.number value="0">
    <h1>Found <get jini.lookup.number> services</h1>
        <table>
            <tr>
                <th>Service ID</th>
                <th>Name</th>
                <th>Location</th>
            </tr>
            <foreach name=j property=jini.lookup.ids>
                <tr>
                    <td><get name=j> </td>
                    <td><get name=jini.lookup.srvcs.${j}>  </td>
                    <if name=jini.lookup.srvcs.${j}.url>
                        <td>
                        <tag>a href=<get name=jini.lookup.srvcs.${j}.url></tag>
                        <get 
name=jini.lookup.srvcs.${j}.url></a>
                        </td>
                    </if>
                </tr>
             </foreach>
        </table>
<else>
        <h1>No service found, activation system or reggie is 
down</H1>
</if>
</center>

Brazil instances can register themselves with a Jini lookup service by scripting the code required for registration with BeanShell and using the two classes BrazilService.java and BrazilAttribute.java for the required Jini attribute class and the actual service. In our example, the BrazilService returns only a URL to get to this service. Serious applications can expand upon this approach to retrieve more complex objects.

Use JAXM with Brazil

JAXM, the Java API for XML Messaging, provides developers with the ability to send XML documents using SOAP (Simple Object Access Protocol) 1.1, allowing developers to concentrate on their applications and not on low-level messaging technology. For more details, see Resources. In prior articles, you learned how to retrieve weather data from our 1-wire weather station using HTTP, applets, JRMS, and JMS (Java Message Service). The JAXM example expands upon these delivery options.

The code below uses JAXM to make the weather data available; the handler runs in a Brazil instance and provides weather data with JAXM. This small JAXM client queries the Web server for the data and simply dumps the XML document to standard out, as follows:

 import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Enumeration;
import java.io.IOException;
import javax.xml.messaging.*;
import javax.xml.soap.*;
import javax.xml.transform.*;
import java.io.ByteArrayOutputStream;

The example is written as a Brazil handler, so we subclass sunlabs.brazil.server.Handler (see Resources for a quick review of writing handlers). Handler developers can overwrite two methods: init() and request(). init() is called the first time the handler runs; request() is called for each user request. In this case, our users request the server by sending the form URL http://somehost:someport//someprefix/WeatherSample.

Once this URL is received, we grab the current weather data and create an appropriate response:

 /**
 * Class declaration
 *
 *
 * @see
 *
 * @author
 * @version   %I%, %G%
 */
public class JAXMServiceHandler implements Handler {
    public static final String PREFIX = "prefix";
    /**
     * One time initialization
     */
    private String prefix;
    private String propsPrefix;
    private Hashtable commands;
    // The commands we support are
    private static Hashtable defaultCommands;
    static {
        defaultCommands = new Hashtable();
        defaultCommands.put("Ping", "");
        defaultCommands.put("WeatherSample", "");
    }

Our init() method initializes the prefix set in the configuration file. Brazil uses a configuration file to determine what handlers, filters, ports, log levels, and so on to use:

              /**
     * Method declaration
     *
     *
     * @param server
     * @param prefix
     *
     * @return
     *
     * @see
     */
    public boolean init(Server server, String prefix) {
        this.propsPrefix = prefix;
        return (true);
    }

The respond() method does the real work. It puts out some diagnostics checks to see if the request is for JAXMServiceHandler, since Brazil presents every user request to every handler.

If the request is for JAXMServiceHandler, we process it. Here are the first few lines of the respond() method:

   /**
   * Method declaration
   *
   *
   * @param request
   *
   * @return
   *
   * @exception IOException
   *
   * @see
   */
   public boolean respond(Request request) throws IOException {
      Properties props = request.props;
      String prefix = props.getProperty(propsPrefix + PREFIX, "/jaxm/");
      request.log(Server.LOG_DIAGNOSTIC, "prefix=" + prefix);
      request.log(Server.LOG_DIAGNOSTIC, "request.url=" + request.url);
      if (request.url.startsWith(prefix) == false) {
      return false;
      }
      System.out.println(new String(request.postData));
      // Get the command name from the URL
      // http:.../SecureTokenServices/<command>?name=value...
      String command = request.url.substring(prefix.length());
      Hashtable args = request.getQueryData();
      request.log(Server.LOG_DIAGNOSTIC, prefix + " " + request.url + ":
      " + args);
      Properties r = new Properties();

At this point, we know the request is for JAXMServiceHandler; so, let's see which specific function the user is requesting. We understand two types of user requests: http://thisserver:thisport/Ping and http://thisserver:thisport/WeatherSample. If the request is either of these URLs, we process it by setting some values in a properties object, then use a method to get those properties, and, with the JAXM APIs, create a SOAP message that carries the properties to the requestor:

      try {
         if (command.startsWith("Ping")) {
            r.put("Ping", "TIME");
            } else if (command.startsWith("WeatherSample")) {
               String x = "remotews";
                r.put("Temperature", props.getProperty(x + "Temperature", "N/A"));
                r.put("WindSpeed", props.getProperty(x + "WindSpeed", "N/A"));
                r.put("WindDirection", props.getProperty(x + "WindDirection", "N/A"));
                r.put("Precipitation", props.getProperty(x + "BucketCount", "N/A"));
                r.put("Time", props.getProperty(x + "Time", "N/A"));
            } else {
                r.put("ErrorNumber", "404");
                r.put("ErrorDescription", "Not Found");
                for (Enumeration e = defaultCommands.keys();
                e.hasMoreElements(); ) {
                   r.put("Try", (String) e.nextElement());
                }
             }
           } catch (Exception e) {
                r.put("Number", "500");
                r.put("Description", e.getMessage());
           }
           finally {
             try {
                String s = makeSoapMessage(r);
                request.sendResponse(s, "text/xml");
            } catch (Exception soap) {
                request.sendError(500, "Server Error : " + soap.getMessage());
                return (true);
            }
      }
      return (true);
   }

The makeSoapMessage() method takes the Properties object passed by reference and creates a SOAP message that returns as a string.

The Brazil server then returns that string as type text/XML:

   /**
   * Method declaration
   *
   *
   * @param p
   *
   * @return
   *
   * @exception Exception
   *
   * @see
   */
   public String makeSoapMessage(Properties p) throws Exception {
      MessageFactory mf = MessageFactory.newInstance();
      SOAPMessage msg = mf.createMessage();
      SOAPEnvelope env = msg.getSOAPPart().getEnvelope(true);
      for (Enumeration e = p.propertyNames(); e.hasMoreElements(); ) {
         String tag = (String) e.nextElement();
         String text = new String( '"' + p.getProperty(tag) + '"');
         System.out.println(tag + " " + text);
         env.getBody().addChildElement(env.createName(tag))
            .addTextNode(text);
     }
     ByteArrayOutputStream b = new ByteArrayOutputStream();
     msg.writeTo(b);
     return (new String(b.toByteArray()));
   }
1 2 3 Page 2
Page 2 of 3