|
File Classifier UI ExampleThe file classifier has been used throughout this book as a simple example of a service to illustrate various features of Jini. We can use it here too, by supplying simple user interfaces to the service. Such a user interface would consist of a text field for entering a filename, and a display to show the MIME type of the filename. There is only a "main" role for this service, as no administration needs to be performed. Figure 19-1 shows what a user interface for a file classifier could look like. Figure 19-1: FileClassifier user interface After the service has been invoked, it could pop up a dialog box, as shown in Figure 19-2. Figure 19-2: FileClassifier return dialog box A factory for the "main" role that will produce an AWT Frame is shown next : /** * FileClassifierFrameFactory.java */ package ui; import net.jini.lookup.ui.factory.FrameFactory; import net.jini.lookup.entry.UIDescriptor; import java.awt.Frame; import net.jini.core.entry.Entry; import net.jini.core.lookup.ServiceItem; public class FileClassifierFrameFactory implements FrameFactory { /** *Return a new FileClassifierFrame that implements the * MainUI role */ public Frame getFrame(Object roleObject) { // we should check to see what role we have to return if (! (roleObject instanceof ServiceItem)) { // unknown role type object // can we return null? return null; } ServiceItem item = (ServiceItem) roleObject; // Do sanity checking that the UIDescriptor has a MainUI role Entry[] entries = item.attributeSets; for (int n = 0; n < entries.length; n++) { if (entries[n] instanceof UIDescriptor) { UIDescriptor desc = (UIDescriptor) entries[n]; if (desc.role.equals(net.jini.lookup.ui.MainUI.ROLE)) { // Ok, we are in the MainUI role, so return a UI for that Frame frame = new FileClassifierFrame(item, "File Classifier"); return frame; } } } // couldn't find a role the factory can create return null; } } // FileClassifierFrameFactory The user interface object that performs this role is as follows : /** * FileClassifierFrame.java */ package ui; import java.awt.*; import java.awt.event.*; import net.jini.lookup.ui.MainUI; import net.jini.core.lookup.ServiceItem; import common.MIMEType; import common.FileClassifier; import java.rmi.RemoteException; /** * Object implementing MainUI for FileClassifier. */ public class FileClassifierFrame extends Frame implements MainUI { ServiceItem item; TextField text; public FileClassifierFrame(ServiceItem item, String name) { super(name); Panel top = new Panel(); Panel bottom = new Panel(); add(top, BorderLayout.CENTER); add(bottom, BorderLayout.SOUTH); top.setLayout(new BorderLayout()); top.add(new Label("Filename"), BorderLayout.WEST); text = new TextField(20); top.add(text, BorderLayout.CENTER); bottom.setLayout(new FlowLayout()); Button classify = new Button("Classify"); Button quit = new Button("Quit"); bottom.add(classify); bottom.add(quit); // listeners quit.addActionListener(new QuitListener()); classify.addActionListener(new ClassifyListener()); // We pack, but don't make it visible pack(); } class QuitListener implements ActionListener { public void actionPerformed(ActionEvent evt) { System.exit(0); } } class ClassifyListener implements ActionListener { public void actionPerformed(ActionEvent evt) { String fileName = text.getText(); final Dialog dlg = new Dialog((Frame) text.getParent().getParent()); dlg.setLayout(new BorderLayout()); TextArea response = new TextArea(3, 20); // invoke service FileClassifier classifier = (FileClassifier) item.service; MIMEType type = null; try { type = classifier.getMIMEType(fileName); if (type == null) { response.setText("The type of file " + fileName + " is unknown"); } else { response.setText("The type of file " + fileName + " is " + type.toString()); } } catch(RemoteException e) { response.setText(e.toString()); } Button ok = new Button("ok"); ok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dlg.setVisible(false); } }); dlg.add(response, BorderLayout.CENTER); dlg.add(ok, BorderLayout.SOUTH); dlg.setSize(300, 100); dlg.setVisible(true); } } } // FileClassifierFrame The server that delivers both the service and the user interface has to prepare a UIDescriptor . In this case, it only creates one such object for a single user interface, but if the server exported more interfaces, it would simply create more descriptors. Here is the server code: /** * FileClassifierServer.java */ package ui; import complete.FileClassifierImpl; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; import net.jini.discovery.LookupDiscovery; import net.jini.core.lookup.ServiceRegistrar; import java.rmi.RemoteException; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscoveryManager; import net.jini.discovery.DiscoveryEvent; import net.jini.discovery.DiscoveryListener; import net.jini.core.entry.Entry; import net.jini.lookup.ui.MainUI; import net.jini.lookup.ui.factory.FrameFactory; import net.jini.lookup.entry.UIDescriptor; import net.jini.lookup.ui.attribute.UIFactoryTypes; import java.rmi.MarshalledObject; import java.io.IOException; import java.util.Set; import java.util.HashSet; public class FileClassifierServer implements ServiceIDListener { public static void main(String argv[]) { new FileClassifierServer(); // stay around forever Object keepAlive = new Object(); synchronized(keepAlive) { try { keepAlive.wait(); } catch(InterruptedException e) { // do nothing } } } public FileClassifierServer() { JoinManager joinMgr = null; // The typenames for the factory Set typeNames = new HashSet(); typeNames.add(FrameFactory.TYPE_NAME); // The attributes set Set attribs = new HashSet(); attribs.add(new UIFactoryTypes(typeNames)); // The factory MarshalledObject factory = null; try { factory = new MarshalledObject(new FileClassifierFrameFactory()); } catch(Exception e) { e.printStackTrace(); System.exit(2); } UIDescriptor desc = new UIDescriptor(MainUI.ROLE, FileClassifierFrameFactory.TOOLKIT, attribs, factory); Entry[] entries = {desc}; try { LookupDiscoveryManager mgr = new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); joinMgr = new JoinManager(new FileClassifierImpl(), /* service */ entries /* attr sets */, this /* ServiceIDListener*/, mgr /* DiscoveryManagement */, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } } public void serviceIDNotify(ServiceID serviceID) { // called as a ServiceIDListener // Should save the ID to permanent storage System.out.println("got service ID " + serviceID.toString()); } } // FileClassifierServer Finally, a client needs to look for and use this user interface. The client finds a service as usual and then does a search through the Entry objects, looking for a UIDescriptor . Once it has a descriptor, it can check whether the descriptor meets the requirements of the client. Here we shall check whether it plays a MainUI role and can generate an AWT Frame : package client; import common.FileClassifier; import common.MIMEType; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.core.lookup.ServiceTemplate; import net.jini.discovery.LookupDiscoveryManager; import net.jini.lookup.ClientLookupManager; import net.jini.core.lookup.ServiceItem; import net.jini.lease.LeaseRenewalManager; import net.jini.core.entry.Entry; import net.jini.lookup.ui.MainUI; import net.jini.lookup.ui.factory.FrameFactory; import net.jini.lookup.entry.UIDescriptor; import net.jini.lookup.ui.attribute.UIFactoryTypes; import java.awt.*; import javax.swing.*; import java.util.Set; import java.util.Iterator; import java.net.URL; /** * TestFrameUI.java */ public class TestFrameUI { private static final long WAITFOR = 100000L; public static void main(String argv[]) { new TestFrameUI(); // stay around long enough to receive replies try { Thread.currentThread().sleep(2*WAITFOR); } catch(java.lang.InterruptedException e) { // do nothing } } public TestFrameUI() { ClientLookupManager clientMgr = null; System.setSecurityManager(new RMISecurityManager()); try { LookupDiscoveryManager mgr = new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); clientMgr = new ClientLookupManager(mgr, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } Class [] classes = new Class[] {FileClassifier.class}; UIDescriptor desc = new UIDescriptor(MainUI.ROLE, FrameFactory.TOOLKIT, null, null); Entry [] entries = {desc}; ServiceTemplate template = new ServiceTemplate(null, classes, entries); ServiceItem item = null; try { item = clientMgr.lookup(template, null, /* no filter */ WAITFOR /* timeout */); } catch(Exception e) { e.printStackTrace(); System.exit(1); } if (item == null) { // couldn't find a service in time System.out.println("no service"); System.exit(1); } // We now have a service that plays the MainUI role and // uses the FrameFactory toolkit of "java.awt". // We now have to find if there is a UIDescriptor // with a Factory generating an AWT Frame checkUI(item); } private void checkUI(ServiceItem item) { // Find and check the UIDescriptors Entry[] attributes = item.attributeSets; for (int m = 0; m < attributes.length; m++) { Entry attr = attributes[m]; if (attr instanceof UIDescriptor) { // does it deliver an AWT Frame? checkForAWTFrame(item, (UIDescriptor) attr); } } } private void checkForAWTFrame(ServiceItem item, UIDescriptor desc) { Set attributes = desc.attributes; Iterator iter = attributes.iterator(); while (iter.hasNext()) { // search through the attributes, to find a UIFactoryTypes Object obj = iter.next(); if (obj instanceof UIFactoryTypes) { UIFactoryTypes types = (UIFactoryTypes) obj; // see if it produces an AWT Frame Factory if (types.isAssignableTo(FrameFactory.class)) { FrameFactory factory = null; try { factory = (FrameFactory) desc.getUIFactory(this.getClass(). getClassLoader()); } catch(Exception e) { e.printStackTrace(); continue; } Frame frame = factory.getFrame(item); frame.setVisible(true); } } } } } // TestFrameUI |