Welcome to Bishnu`s JINI Tutorial

home      introduction       My Interest   My Favorites link      Photo gallery

 

Lets develop more complex program than Hello

前回の解説では、HelloサービスをベースにhellNew Serviceを構成しました。今回はHelloではなくもう少し複雑なプログラム構成し、そのプログラムをどのようにJiniのサービスとして利用できるようにするのかまたは、どのあたりを工夫すればJiniServiceとして使えるようになるのかについて説明します。 具体的には、JavaでEditorを開発します。そのEditorをサーバ側が用意し、それをクライント側が利用できるようにするのにどのようにすればよいのかを説明します。
  • cd %jini_home%\source\src\com\sun\jini\example
  • mkdir cal
上記では、新しいパッケジを作る準備ができました。さて、いままで使っていたhelloパッケジのすべてのファイルをcalディレクトリにコピをして下さい。 コピを終わりましたら、下記の順番で変更して下さい。

Steps

  1. configファイルの中身を変更する。
  2. cd cal\config\META-INF
    META-INFの中にあるPREFERRED.LISTファイルにあるPathを自分のパッケジのPathに合わすこと。
    例: Name: com/sun/jini/example/hello/ConfirmingInvocationHandler.class -->Name: com/sun/jini/example/cal/ConfirmingInvocationHandler.class
  3. configディレクトリの直下にある必要なファイルの設定を変更する
    • jrmp-reggieの中身を変える
    • 例:initialMemberGroups = new String[] { "nonsecure.example.jini.sun.com" }; -->initialMemberGroups = new String[] { "nonsecure.helloN.example.jini.sun.com" }; 上記と同じように下記のファイルも変更してください。
    • jrmp-server.config
    • client.config
    本 チュートリアルではシンプルな例だけを動かすことにする。興味のある人はもっとSecureなプログラムを例えばKerberosなどの設定を行い色々な環境で動けるように必要なファイルを変更して実行環境を会わせて試してください。
  4. ソースファイルの中身を変更する
では、新しいサービスを開発するため、まずは、インタフェースを用意しましょう。前回はHelloインタフェースを利用したのですが、今回はEditorサービスを使うので下記のようなプログラムを用意します。
package com.sun.jini.example.cal;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.awt.*;
import javax.swing.*;


/**
 * Defines a simple remote interface.
 *
 * @author Sun Microsystems, Inc.
 *
 */
public interface JavaEditorServiceInterface extends Remote {

    /**
     * Returns a message string.
     *
     * @return message string
     * @throws RemoteException if a remote communication problem occurs
     */
	public JFrame getJavaEditor() throws RemoteException;
}

確認のどおり、getJavaEditor()メソッドを用意されています。このメソッドのデータ型はJFrameになっていることを確認して欲しい。要するに、サービス側はJFrameを返さなければならないこととクライント側もJFrameを受ける手続きをしなければならないわけですね。それは後ほどのプログラム郡を確認すればわかると思います。 では、このインタフェースを実装するServerプログラムをどうなっているのかを確認しましょう。
/*
 *
 * Copyright 2005 Sun Microsystems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.sun.jini.example.cal;

import java.rmi.RemoteException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import net.jini.config.ConfigurationProvider;
import net.jini.config.NoSuchEntryException;
import net.jini.core.lookup.ServiceID;
import net.jini.discovery.DiscoveryManagement;
import net.jini.discovery.LookupDiscovery;
import net.jini.export.Exporter;
import net.jini.export.ProxyAccessor;
import net.jini.id.Uuid;
import net.jini.id.UuidFactory;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;
import net.jini.lookup.JoinManager;
import net.jini.security.TrustVerifier;
import net.jini.security.proxytrust.ServerProxyTrust;
import java.awt.*;
import javax.swing.*;



/**
 * Defines an application server that provides an implementation of the Hello
 * interface.
 *
 * The application uses the following arguments:
 *
 * [all] - All arguments are used as options when getting the configuration
 *
 * The application uses the following configuration entries, with component
 * com.sun.jini.example.cal.Server:
 *
 * discoveryManager
 *   type: DiscoveryManagement
 *   default: new LookupDiscovery(new String[] { "" }, config)
 *   Object used to discover lookup services to join.
 *
 * exporter
 *   type: Exporter
 *   default: none
 *   The object to use for exporting the server
 *
 * loginContext
 *   type: LoginContext
 *   default: null
 *   If non-null, specifies the JAAS login context to use for performing a JAAS
 *   login and supplying the Subject to use when running the server. If null,
 *   no JAAS login is performed.
 *
 * @author Sun Microsystems, Inc.
 */
public class Server implements JavaEditorServiceInterface, ServerProxyTrust, ProxyAccessor {

    /**
     * If the impl gets GC'ed, then the server will be unexported.
     * Store the instance here to prevent this.
     */
    private static Server serverImpl;

    /* The configuration to use for configuring the server */
    protected final Configuration config;

    /** The server proxy, for use by getProxyVerifier */
    protected JavaEditorServiceInterface serverProxy;

    /**
     * Starts and registers a server that implements the Hello interface.
     *
     * @param args options to use when getting the Configuration
     * @throws ConfigurationException if a problem occurs with the
     *	       configuration
     * @throws RemoteException if a remote communication problem occurs
     */
    public static void main(String[] args) throws Exception {
	serverImpl = new Server(args);
	serverImpl.init();
	System.out.println("JavaEditorServiceInterface server is ready");
    }

    /**
     * Creates the server.
     *
     * @param configOptions options to use when getting the Configuration
     * @throws ConfigurationException if a problem occurs creating the
     *	       configuration
     */
    protected Server(String[] configOptions) throws ConfigurationException {
	config = ConfigurationProvider.getInstance
                       ( configOptions, (this.getClass()).getClassLoader() );
    }

    /**
     * Initializes the server, including exporting it and storing its proxy in
     * the registry.
     *
     * @throws Exception if a problem occurs
     */
    protected void init() throws Exception {
	LoginContext loginContext = (LoginContext) config.getEntry(
	    "com.sun.jini.example.cal.Server", "loginContext",
	    LoginContext.class, null);
	if (loginContext == null) {
	    initAsSubject();
	} else {
	    loginContext.login();
	    Subject.doAsPrivileged(
		loginContext.getSubject(),
		new PrivilegedExceptionAction() {
		    public Object run() throws Exception {
			initAsSubject();
			return null;
		    }
		},
		null);
	}
    }

    /**
     * Initializes the server, assuming that the appropriate subject is in
     * effect.
     */
    protected void initAsSubject() throws Exception {
	/* Export the server */
	Exporter exporter = getExporter();
	serverProxy = (JavaEditorServiceInterface) exporter.export(this);

	/* Create the smart proxy */
	Proxy smartProxy = Proxy.create(serverProxy);

	/* Get the discovery manager, for discovering lookup services */
	DiscoveryManagement discoveryManager;
	try {
	    discoveryManager = (DiscoveryManagement) config.getEntry(
		"com.sun.jini.example.cal.Server", "discoveryManager",
		DiscoveryManagement.class);
	} catch (NoSuchEntryException e) {
            /* Use the public group */
	    discoveryManager = new LookupDiscovery(
		new String[] { "" }, config);
	}

	/* Get the join manager, for joining lookup services */
	JoinManager joinManager =
	    new JoinManager(smartProxy, null /* attrSets */, getServiceID(),
			    discoveryManager, null /* leaseMgr */, config);
    }

    /**
     * Returns the exporter for exporting the server.
     *
     * @throws ConfigurationException if a problem occurs getting the exporter
     *	       from the configuration
     * @throws RemoteException if a remote communication problem occurs
     */
    protected Exporter getExporter()
	throws ConfigurationException, RemoteException
    {
	return (Exporter) config.getEntry(
	    "com.sun.jini.example.cal.Server", "exporter", Exporter.class,
	    new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
				  new BasicILFactory()));
    }

    /** Returns the service ID for this server. */
    protected ServiceID getServiceID() {
	return createServiceID();
    }

    /** Creates a new service ID. */
    protected static ServiceID createServiceID() {
	Uuid uuid = UuidFactory.generate();
	return new ServiceID(
	    uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
    }

    /** Implement the JavaEditorService interface. */


		public JFrame getJavaEditor()
			 throws RemoteException {
			       // f  = new CalcFrame();
			       //f = CalcFrame.getFrame();
			       //Frame f2 = f.getFrame();
			     // f = CalcFrame.getFrame();
			      //f2.setSize(300,150);

			     // return f.setVisible(true);
			     return new JavaEditor();
	}

    /**
     * Implement the ServerProxyTrust interface to provide a verifier for
     * secure smart proxies.
     */
    public TrustVerifier getProxyVerifier() {
	return new Proxy.Verifier(serverProxy);
    }

    /**
     * Returns a proxy object for this remote object.
     *
     * @return our proxy
     */
    public Object getProxy() {
        return serverProxy;
    }

}

上記のプログラムを見て、前回のHelloServiceを書くときのServerプログラムと今回はどう違うのかを比較してみてください。確認の通り、インタフェースを実装するメソッド以外は何も変わっていないことに注意して欲しいですね。 上記のgetJavaEditor()メソッドではJavaEditorを返していますが、具体的な手続きはJavaEditor.javaの方で行っています。JavaEditor.javaの中身については説明しませんが、要するにServer.javaではJFrameとして受け皿を用意してあるので、JavaEditor.javaからReturnされる要素がJFrameでなければなりません。簡単なJavaEditorを作って試してください。この用にJavaのクラスをJiniでラップするわけですね。
では、今度はHelloサービスと同じくこのJavaEditorServiceのProxyはどうなっているのかを確認しましょう。
package com.sun.jini.example.cal;

import java.io.Serializable;
import java.rmi.RemoteException;
import net.jini.core.constraint.MethodConstraints;
import net.jini.core.constraint.RemoteMethodControl;
import net.jini.security.TrustVerifier;
import net.jini.security.proxytrust.ProxyTrustIterator;
import net.jini.security.proxytrust.SingletonProxyTrustIterator;
import net.jini.security.proxytrust.TrustEquivalence;
import java.awt.*;
import javax.swing.*;


/** Define a smart proxy for the server. */
class Proxy implements Serializable, JavaEditorServiceInterface {

    private static final long serialVersionUID = 2L;

    /** The server proxy */
    final JavaEditorServiceInterface serverProxy;

    /**
     * Create a smart proxy, using an implementation that supports constraints
     * if the server proxy does.
     */
    static Proxy create(JavaEditorServiceInterface serverProxy) {
	return (serverProxy instanceof RemoteMethodControl)
	    ? new ConstrainableProxy(serverProxy)
	    : new Proxy(serverProxy);
    }

    Proxy(JavaEditorServiceInterface serverProxy) {
	this.serverProxy = serverProxy;
    }

    public boolean equals(Object o) {
	return getClass() == o.getClass()
	    && serverProxy.equals(((Proxy) o).serverProxy);
    }

    public int hashCode() {
	return serverProxy.hashCode();
    }




    public JFrame getJavaEditor() throws RemoteException{
		return serverProxy.getJavaEditor();
		}



    /** A constrainable implementation of the smart proxy. */
    private static final class ConstrainableProxy extends Proxy
	implements RemoteMethodControl
    {
        private static final long serialVersionUID = 2L;

	ConstrainableProxy(JavaEditorServiceInterface serverProxy) {
	    super(serverProxy);
	}

	/** Implement RemoteMethodControl */

	public MethodConstraints getConstraints() {
	    return ((RemoteMethodControl) serverProxy).getConstraints();
	}

	public RemoteMethodControl setConstraints(MethodConstraints mc) {
	    return new ConstrainableProxy(
		(JavaEditorServiceInterface) ((RemoteMethodControl) serverProxy).setConstraints(
		    mc));
	}

	/*
	 * Provide access to the underlying server proxy to permit the
	 * ProxyTrustVerifier class to verify the proxy.
	 */
	private ProxyTrustIterator getProxyTrustIterator() {
	    return new SingletonProxyTrustIterator(serverProxy);
	}
    }

    /** A trust verifier for secure smart proxies. */
    final static class Verifier implements TrustVerifier, Serializable {

        private static final long serialVersionUID = 2L;

	private final RemoteMethodControl serverProxy;

	/**
	 * Create the verifier, throwing UnsupportedOperationException if the
	 * server proxy does not implement both RemoteMethodControl and
	 * TrustEquivalence.
	 */
	Verifier(JavaEditorServiceInterface serverProxy) {
	    if (serverProxy instanceof RemoteMethodControl &&
		serverProxy instanceof TrustEquivalence)
	    {
		this.serverProxy = (RemoteMethodControl) serverProxy;
	    } else {
		throw new UnsupportedOperationException();
	    }
	}

	/** Implement TrustVerifier */
	public boolean isTrustedObject(Object obj, TrustVerifier.Context ctx)
	    throws RemoteException
	{
	    if (obj == null || ctx == null) {
		throw new NullPointerException();
	    } else if (!(obj instanceof ConstrainableProxy)) {
		return false;
	    }
	    RemoteMethodControl otherServerProxy =
		(RemoteMethodControl) ((ConstrainableProxy) obj).serverProxy;
	    MethodConstraints mc = otherServerProxy.getConstraints();
	    TrustEquivalence trusted =
		(TrustEquivalence) serverProxy.setConstraints(mc);
	    return trusted.checkTrustEquivalence(otherServerProxy);
	}
    }
}


上記のプログラムProxy.javaではServer.javaと同じくJFrame getJavaEditor() メソッドがありますが、具体的な定義はProxy.javaではなくServer.javaの方でやっていることに注目して欲しいです。 さて、サーバ側の準備はできました。今度はそれらのサービスを利用するクライントプログラムの中身を確認しましょう。
package com.sun.jini.example.cal;

import java.rmi.RemoteException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationProvider;
import net.jini.config.NoSuchEntryException;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.discovery.LookupDiscovery;
import net.jini.lookup.ServiceDiscoveryManager;
import net.jini.lookup.ServiceItemFilter;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;


import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
import net.jini.discovery.LookupDiscoveryManager;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.awt.*;
import javax.swing.*;


/**
 * Defines an application that makes calls to a remote JavaEditorServiceInterface server.
 *
 * The application uses the following arguments:
 *
 * [all] - All arguments are used as options when getting the configuration
 *
 * The application uses the following configuration entries, with component
 * com.sun.jini.example.cal.Client:
 *
 * loginContext
 *   type: LoginContext
 *   default: null
 *   If non-null, specifies the JAAS login context to use for performing a JAAS
 *   login and supplying the Subject to use when running the client. If null,
 *   no JAAS login is performed.
 *
 * preparer
 *   type: ProxyPreparer
 *   default: new BasicProxyPreparer()
 *   Proxy preparer for the server proxy
 *
 * serviceDiscovery
 *   type: ServiceDiscoveryManager
 *   default: new ServiceDiscoveryManager(
 *                new LookupDiscovery(new String[] { "" }, config),
 *                null, config)
 *   Object used for discovering a server that implement JavaEditorServiceInterface.
 *
 * @author Sun Microsystems, Inc.
 */
public class Client {

    /**
     * Starts an application that makes calls to a remote JavaEditorServiceInterface implementation.
     */
    public static void main(String[] args) throws Exception {
	/*
	 * The configuration contains information about constraints to apply to
	 * the server proxy.
	 */
	final Configuration config = ConfigurationProvider.getInstance(args);
	LoginContext loginContext = (LoginContext) config.getEntry(
	    "com.sun.jini.example.cal.Client", "loginContext",
	    LoginContext.class, null);
	if (loginContext == null) {
	    mainAsSubject(config);
	} else {
	    loginContext.login();
	    Subject.doAsPrivileged(
		loginContext.getSubject(),
		new PrivilegedExceptionAction() {
		    public Object run() throws Exception {
			mainAsSubject(config);
			return null;
		    }
		},
		null);
	}
    }

    /**
     * Performs the main operations of the application with the specified
     * configuration and assuming that the appropriate subject is in effect.
     */
    static void mainAsSubject(Configuration config) throws Exception {

	/* Get the service discovery manager, for discovering other services */
	ServiceDiscoveryManager serviceDiscovery;
	try {
	    serviceDiscovery = (ServiceDiscoveryManager) config.getEntry(
		"com.sun.jini.example.cal.Client", "serviceDiscovery",
		ServiceDiscoveryManager.class);
	} catch (NoSuchEntryException e) {
	    /* Default to search in the public group */
	    serviceDiscovery = new ServiceDiscoveryManager(
		new LookupDiscovery(new String[] { "" }, config),
		null, config);
	}

        /* Retrieve the server proxy preparer from the configuration */
	ProxyPreparer preparer = (ProxyPreparer) config.getEntry(
	    "com.sun.jini.example.cal.Client",
	    "preparer", ProxyPreparer.class, new BasicProxyPreparer());

        /* Create the filter to pass to the SDM for proxy preparation */
        ServiceItemFilter filter = new ProxyPreparerFilter(preparer);

	/* Look up the remote server (SDM performs proxy preparation) */
	ServiceItem serviceItem = serviceDiscovery.lookup(
	    new ServiceTemplate(null, new Class[] { JavaEditorServiceInterface.class }, null),
	    filter, Long.MAX_VALUE);
	//JavaEditorServiceInterface server = (JavaEditorServiceInterface) serviceItem.service;
	JavaEditorServiceInterface server = (JavaEditorServiceInterface) serviceItem.service;

	/* Use the server */
	//System.out.println("Server says: " + server.sayHello());
	//System.out.println("Server returns: " +server.calculate(4, 5));
	//server.getJavaEditor();
	JFrame f = server.getJavaEditor( );
                                  f.setVisible(true);

	/* Exit to close any thread created by the callback handler's GUI */
	System.exit(0);
    }

    /** Performs proxy preparation on discovered services. For more information
     *  see the javadoc for the net.jini.lookup.ServiceItemFilter interface.
     */
    private static class ProxyPreparerFilter implements ServiceItemFilter {
        private ProxyPreparer preparer;

        ProxyPreparerFilter(ProxyPreparer preparer) {
            this. preparer = preparer;
        }

        /** See the javadoc for the ServiceItemFilter.check method. */
	public boolean check(ServiceItem item) {
            try {
                item.service = preparer.prepareProxy(item.service);
                return true;  //pass
            } catch(SecurityException e) {//definite exception
                return false; //fail: don't try again
            } catch(RemoteException e) {//indefinite exception
                item.service = null;
                return true;  //null & true == indefinite: will retry later
            }
	}
    }
}


クライントプログラムではJavaEditorServiceInterfaceに記載されているJFrame getJavaEditor()メソッドを呼び出しています。

変更したプログラムをコンパイルする

cd %JINI_HOME%\source\src\com\sun\jini\example\cal

  • ant clean
  • ant
  • ant this.jars
  • コンパイルが終了したら、プログラムを実行してみましょう。

    Steps

    1. クラスサーバー(Htttp Server)を動かす

    cd %JINI_HOME%\source\src\com\sun\jini\example\cal
    start scripts\httpd.bat (これはCommand promptで動かす)うまくいったら以下のようながめんが出ます。

    2. 以下のコマンドを順番に打ってください。

    (これも%JINI_HOME%\source\src\com\sun\jini\example\calのところで動かすこと)
  • a. start scripts\jrmp-reggie

  • b. start scripts\jrmp-server(JavaEditorServiceぷろぐらむのサーバー)

  • c. start scripts\client (クライントの起動)
  • うまくいったら変更したサービスを利用することができると思います。

    以上で変更したJavaEditorServiceのプログラムを動かすことが完了します

     http://www.wakhok.ac.jp/~gautam
    page design by Gautam
    send comments to gautam@wakhok.ac.jp