The Artima Developer Community
Sponsored Link

Generating .serviceui Files
By Bill Venners

Advertisement

Summary
In this document I show a Java application that generates .serviceui files for the BasicPlace services at artima.com that were used in the Cyberspace demo.


In the Cyberspace demo, I showed Jini services being pulled across the network via HTTP from a local copy of artima.com. The files requested via HTTP all ended in the .serviceui extension, and were delivered across the network with the application/x-serviceui MIME type. Each .serviceui file contained a serialized marshalled Jini ServiceItem. This page shows a Java application that I used to generate several of the Jini Place services shown in the demo.

The GenBasicPlaceFile Application

The application shown below will generate a .serviceui file for a BasicPlace initialized with data extracted from an instance of a class whose name is passed as the first argument. For example, to create a .serviceui file for the Artima home place, you start the application like this:

java BasicPlaceFileGen ArtimaHomeData www.artima.com index.serviceui
The first argument, ArtimaHomeData, indicates that BasicPlaceFileGen should dynamically load a class named ArtimaHomeData, instantiate it, and query the resulting object for initialization data for the BasicPlace service. Class ArtimaHomeData is shown just following BasicPlaceFileGen.

I include this code to help people figure out what goes into making a .serviceui file. I have commented the application heavily, and made all the comments bold and blue. Happy reading.

/*
 * This source code (.java) file is Copyright (C) 2000 Artima Software, Inc. All rights reserved.
 * This file accompanies the Jini Place Service Draft Specification, written by Bill
 * Venners and published on the World Wide Web at:
 *
 *     http://www.artima.com/jini/cyberspace/DraftSpec.html,
 *
 * This source file may not be copied, modified, or redistributed EXCEPT as allowed
 * by the following statements: From August 11, 2000 through December 31, 2000, you may
 * copy and/or modify these files to test and experiment with the Place API,
 * described in the Jini Place Service Draft Specification. Any bug fixes must be given
 * back to Artima Software, Inc. You may not redistribute this file or any binary (such
 * as .class) files generated from this file. You may not distribute modified versions
 * this files or any binary (such as .class) files generated from modified versions of
 * this file. You may not remove this copyright notice. You may not use this file in
 * printed media without the express permission of Bill Venners. And if that weren't
 * enough, you must destroy all copies of this file, and any binary (such as
 * .class) files generated from this file, by December 31, 2000.
 *
 * ARTIMA SOFTWARE, INC. MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THIS SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 * BILL VENNERS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY A LICENSEE AS A RESULT
 * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
import net.jini.core.lookup.ServiceItem;

import net.jini.core.entry.Entry;
import net.jini.lookup.entry.Name;

import net.jini.lookup.entry.UIDescriptor;
import net.jini.lookup.ui.*;
import net.jini.lookup.ui.attribute.*;
import net.jini.lookup.ui.factory.*;

import java.io.*;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.lang.reflect.*;

import net.artima.place.*;

// This application generates a file that contains a serialized Jini ServiceItem containing
// a Place service and service UI for BasicPlaces at artima.com, such as the home place
// Jini Corner, Java Corner, etc..
// (The URL of the Artima home place on the internet is: http://www.artima.com/index.serviceui)
//
// The application takes three command line arguments, a class name containing data for the
// BasicPlace, the host name and the output file name. The class is loaded dynamically and
// instantiated, then queried for its data.
// I pass in the host name, because I sometimes want to create .serviceui files for local copies of
// the artima.com web site. The host is embedded in the .serviceui file in the several places
// that objects are marshalled inside of MarshalledObjects.
//
// This is a rather involved program, especially considering it is devoted to just creating
// one kind of .serviceui file. I also have programs like this for other kinds of .serviceui file I
// have placed at artima.com. What we'll need in the future, of course, are nice easy to use tools
// that allow users to enter the information that is hard-coded in this application in a GUI, stores
// the information in a persistent database of some kind, and generates the .serviceui file
// on a button click. Generating the .serviceui file should also be possible from
// the command line, possibly using data from that persistent store, so that makes can
// regenerate all the .serviceui files. In other words, if people are actually going to
// be making these .serviceui files, we'll need tools to make the process quick and easy.
//
// Bill Venners - August 31, 2000
//
public class GenBasicPlaceFile
{

    public static void main (String[] args) {

        if (args.length < 3) {

            System.out.println("Must enter PlaceData class name, host name, and .serviceui output file name as args.");
            System.out.println("Example: java GenPlaceFile ArtimaHomeData www.artima.com index.serviceui");
            return;
        }

        PlaceData placeData = null;
        try {
            Class clazz = Class.forName(args[0]);
            placeData = (PlaceData) clazz.newInstance();
        }
        catch (ClassNotFoundException cnfe) {
            System.out.println("Can't load class: " + args[0]);
        }
        catch (IllegalAccessException iae) {
            System.out.println("Can't access class: " + args[0]);
        }
        catch (InstantiationException ie) {
            System.out.println("Can't instantiate class: " + args[0]);
        }

        // Host from which the JAR files will be retrieved and the links will be activated.
        String host = args[1];

        // Name of the file in which the serialized marshalled ServiceItem will be place. Should
        // probably end in .serviceui extension.
        String outputFileName = args[2];

        String[] keysAndFilenames = placeData.getKeysAndFilenames();

        // Fill an array of keys
        String[] keys = new String[keysAndFilenames.length / 2];
        for (int i = 0; i < keys.length; ++i) {
            keys[i] = keysAndFilenames[i * 2];
            System.out.println("Adding key to array: " + keys[i]);
        };

        try {
            System.setSecurityManager(new RMISecurityManager());

            // The attributes associated with this Jini service will include a Name
            // and a UIDescriptor
            Entry[] attributes = new Entry[2];

            attributes[0] = new Name(placeData.getNameAttribute());

            // *** Create a UIDescriptor for the JFrame
            UIDescriptor descrip = new UIDescriptor();

            // Load the factory class for the Home Place's UI from a codebase built from the
            Class c = RMIClassLoader.loadClass("http://" + host + "/classes/artimaplacesjframe.jar",
                "com.artima.cyberspace.ui.IconPlaceJFrameFactory");

            // Get an appropriate constructor, so the IconPlaceJFrameFactory class
            // can be instantiated.
            Class[] paramTypes = new Class[2];
            paramTypes[0] = String.class;
            paramTypes[1] = Object[].class;
            Constructor constructor = c.getDeclaredConstructor(paramTypes);

            // The constructor takes a String title and an array of Object keys. Pass
            // Pass that information to newInstance(Object[]), to get an instance
            // of the service UI factory class for the Artima Home
            // place, IconPlaceJFrameFactory
            Object[] initArgs = new Object[2];
            initArgs[0] = placeData.getJFrameTitle();
            initArgs[1] = keys;
            Object factory = constructor.newInstance(initArgs);

            // Marshal the UI factory, and assign a reference to the marshalled factory
            // to the UIDescriptor's factory field.
            descrip.factory = new MarshalledObject(factory);

            // Fill in the UIDescriptor's role and toolkit fields
            descrip.role = MainUI.ROLE;
            descrip.toolkit = JFrameFactory.TOOLKIT;

            // Create and fill the UIDescriptor's attributes set
            Set factoryTypesSet = new HashSet();
            factoryTypesSet.add(JFrameFactory.TYPE_NAME);
            UIFactoryTypes factoryTypesAttr = new UIFactoryTypes(factoryTypesSet);
            descrip.attributes = new HashSet();
            descrip.attributes.add(factoryTypesAttr);

            // Make the now finished UIDescriptor the second attribute in the
            // array of attributes for this Jini Place service
            attributes[1] = descrip;

            // Load the class for the ResourceInfo that the Links will contain from
            // the appropriate codebase. (This must be loaded from the codebase because
            // the implementation class, ConcretePropertyFileResourceInfo, is going to
            // be flung across the network as part of the implementation code of
            // this place service's (ConcretePropertyFileResourceInfo will be placed
            // in the place service's JAR file.)
            c = RMIClassLoader.loadClass("http://" + host + "/classes/artimaplaces.jar",
                "com.artima.cyberspace.ConcretePropertyFileResourceInfo");

            // Select an appropriate ConcretePropertyFileResourceInfo constructor
            paramTypes = new Class[2];
            paramTypes[0] = String.class;
            Locale[] emptyLocaleArray = new Locale[0];
            paramTypes[1] = emptyLocaleArray.getClass();
            constructor = c.getDeclaredConstructor(paramTypes);

            // The selected constructor takes a String basename and
            // an array of supported locales 
            initArgs = new Object[2];
            initArgs[1] = emptyLocaleArray;

            // Build a HashMap of URLLinks. Each Link contained in this
            // Place will be represented by one URLLink object in the HashMap.
            Map map = new HashMap();
            for (int i = 0; i < keysAndFilenames.length; i += 2) {

                initArgs[0] = keysAndFilenames[i];

                // Instantiate a ConcretePropertyFileResourceInfo for a Link, using the
                // current basename (keysAndFilenames[i]) and the empty Locales array.
                // In this case, the current basename will cycle through Strings such as
                // "artimahomepage", "jinicornerplace", "javacornerplace", etc.
                ResourceInfo info = (ResourceInfo) constructor.newInstance(initArgs);

                // Place the a URLLink for the current Link in the HashMap with a
                // key based taken from the keysAndFilenames array. The keys in this
                // case will be Strings "artimahomepage", "jinicornerplace",
                // "javacornerplace", and so on.
                map.put(keysAndFilenames[i], new URLLink("http://" + host + keysAndFilenames[i + 1], info));
                System.out.println("Adding URLLink to map with key: " + keysAndFilenames[i]);
            }

            // Load the class for the LinkMap that this place interface will actually
            // return an instance of when its getLinkMap() method is invoked.
            c = RMIClassLoader.loadClass("http://" + host + "/classes/artimaplaces.jar",
                "com.artima.cyberspace.BasicLinkMap");

            // Select an appropriate BasicLinkMap constructor
            paramTypes = new Class[1];
            paramTypes[0] = Map.class;
            constructor = c.getDeclaredConstructor(paramTypes);

            // The selected constructor takes a reference to a Map. Instantiate
            // a BasicLinkMap, passing in the recently built HashMap, which contains
            // key Strings mapped to URLLink objects.
            initArgs = new Object[1];
            initArgs[0] = map;
            LinkMap linkMap = (LinkMap) constructor.newInstance(initArgs);

            // Load the class of the Place service itself from the appropriate codebase
            c = RMIClassLoader.loadClass("http://" + host + "/classes/artimaplaces.jar",
                "com.artima.cyberspace.BasicPlace");

            // Select an appropriate BasicPlace constructor
            paramTypes = new Class[1];
            paramTypes[0] = LinkMap.class;
            constructor = c.getDeclaredConstructor(paramTypes);

            // The selected constructor requires a single parameter, a LinkMap. By sheer luck,
            // a LinkMap happens to be sitting on the heap, referenced from the linkMap local
            // variable. Using this constructor, instantiate the Place service object itself.
            initArgs = new Object[1];
            initArgs[0] = linkMap;
            Object service = constructor.newInstance(initArgs);

            // Plop both the service item and the attribute sets into a Jini ServiceItem.
            // (Here I don't have a service ID, but I think we probably should require
            // that ServiceItem's that are retrieved via the application/x-serviceui
            // have a valid and globally unique ServiceID.)
            ServiceItem serviceItem = new ServiceItem(null, service, attributes);

            // Marshall the ServiceItem. This is the object that will actually be serialized
            // into a file that can then be placed on a web site.
            MarshalledObject mo = new MarshalledObject(serviceItem);

            // Create a file output stream for the name passed as the 2nd arg to this
            // application.
            ObjectOutputStream oos = new ObjectOutputStream(
                new BufferedOutputStream(
                    new FileOutputStream(outputFileName)
                )
            );

            // Serialize the marshalled ServiceItem into the open file. This file can
            // be delivered via HTTP with the application/x-serviceui MIME type.
            oos.writeObject(mo);
            oos.close();
        }
        catch (Exception e) {
            System.out.println("CalcServ Exception:" + e);
            e.printStackTrace(System.err);
        }
    }
}

Class ArtimaHomeData

Rather than parsing XML or some other form of file, I made BasicPlaceFileGen accept the name of a class on its command line. The BasicPlaceFileGen application dynamically loads the class, instantiates it, and queries the resulting object for data. The three pieces of data contained in the class is a service name put in the Name attribute (returned by getNameAttribute()), a service name shown in the UI (returned by getJFrameTitle()), and a mapping of key Strings to URLs (returned by getKeysAndFilenames()). Each link contained in the place is given a key/URL pair in the data. The String key is used ::::

/*
 * This source code (.java) file is Copyright (C)  2000 Artima Software, Inc. All rights reserved.
 * This file accompanies the Jini Place Service Draft Specification, written by Bill
 * Venners and published on the World Wide Web at:
 *
 *     http://www.artima.com/jini/cyberspace/DraftSpec.html,
 *
 * This source file may not be copied, modified, or redistributed EXCEPT as allowed
 * by the following statements: From August 11, 2000 through December 31, 2000, you may
 * copy and/or modify these files to test and experiment with the Place API,
 * described in the Jini Place Service Draft Specification. Any bug fixes must be given
 * back to Artima Software, Inc. You may not redistribute this file or any binary (such
 * as .class) files generated from this file. You may not distribute modified versions
 * this files or any binary (such as .class) files generated from modified versions of
 * this file. You may not remove this copyright notice. You may not use this file in
 * printed media without the express permission of Bill Venners. And if that weren't
 * enough, you must destroy all copies of this file, and any binary (such as
 * .class) files generated from this file, by December 31, 2000.
 *
 * ARTIMA SOFTWARE, INC. MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THIS SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 * BILL VENNERS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY A LICENSEE AS A RESULT
 * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/

public class ArtimaHomeData implements PlaceData {

    private String nameAttribute = "Artima.com Home Place";
    private String jframeTitle = "Artima.com - A Resource for Java and Jini Developers";

    // Maps key names with which Links are placed in the ArtimaHome LinkMap to the file portion
    // of the URLs that indicate the resource to activate for that Link. For example, when someone
    // activates the Link with the "jinicornerplace" key, the resource with the URL:
    //
    //     http:////jini/index.serviceui
    //
    private String[] keysAndFilenames = {

        "artimahomepage", "/index.html",
        "jinicornerplace", "/jini/index.serviceui",
        "javacornerplace", "/java/index.serviceui",
        "designcornerplace", "/javadesign/index.serviceui",
        "jvmcornerplace", "/jvm/index.serviceui",
        "search", "/search.html",
        "subscribe", "/subscribe.html",
        "seminars", "/javaseminars/index.html",
        "cal", "/services/cal.serviceui",
        "colorschemer", "/services/colorschemer.serviceui"
    };

    public String getNameAttribute() {
        return nameAttribute;
    }

    public String getJFrameTitle() {
        return jframeTitle;
    }

    public String[] getKeysAndFilenames() {
        return keysAndFilenames;
    }
}

Discussion Forum

To discuss the ideas presented in this article please post to the cyberspace@jini.org mailing list, or visit:

http://www.artima.com/jini/jf/cyberspace/index.html

For a more in-depth explanation of the cyberspace project, please see the A Walk Through Cyberspace article.

ServiceUI is a trademark of Artima Software, Inc.

Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use