Welcome to Bishnu`s JINI Tutorial

home      introduction       My Interest   My Favorites link      Photo gallery

 

Hello Exampleのプログラムをベースに新しいサービスを作成する

前回の解説では、Helloサービスの中身について少し変更を行い、サービスの振る舞いをどう変更したのかを確認しました。前回は、helloパッケージの中で、サービスだけを変更しました。今度はhello からさらに、helloNewにパッケージを変更します。また、helloNewパッケジのhelloNewサービスに足し算するサービスを追加します。足し算を追加できた人は引き算やその他の計算サービスを追加して試してください。 では下記のような準備をして下さい。
  • cd %jini_home%\source\src\com\sun\jini\example
  • mkdir helloNew
上記では、新しいパッケジを作る準備ができました。さて、いままで使っていたhelloパッケジのすべてのファイルをhelloNewディレクトリにコピをして下さい。 コピを終わりましたら、下記の順番で変更して下さい。

Steps

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

import java.rmi.Remote;
import java.rmi.RemoteException;

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

    /**
     * Returns a message string.
     *
     * @return message string
     * @throws RemoteException if a remote communication problem occurs
     */
    String sayHello() throws RemoteException;
	int calculate(int a, int b) throws RemoteException;
}

確認のどおり、int calculate(int a, int b) throws RemoteExceptionメソッドを追加されています。 さて、プログラムファイルを少しづつ変更し、どのように変わったのかを理解して行きましょう。まずはServer.Javaの中身を見てみましょう。
/*
 *
 * 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.helloNew;

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;

/**
 * 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.helloNew.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 Hello, 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 Hello 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("Hello 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.helloNew.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 = (Hello) 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.helloNew.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.helloNew.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 Hello interface. */
    public String sayHello() {
	return "Server Changed two times Hello, world!";
    }

	public int calculate(int a, int b){
			return (a+b);
		}

    /**
     * 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;
    }

}

確認の通り、先頭にはパッケジを自分のプログラムのパースに合わせています。この行は、今後他のすべてのソースファイルにも同じく追加してください。Server.javaの198行目あたりをみてほしいですが、sayHello()のほかにcalculate(int a, int b)というメソッドが実装されています。 他には何も変更していません。 今度はProxy.javaを見てみましょう。

/*
 *
 * 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.hello;

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;

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

    private static final long serialVersionUID = 2L;

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

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

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

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

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

    /** Implement Hello. */
    public String sayHello() throws RemoteException {
	System.out.println("Calling sayHello in smart proxy");
	return serverProxy.sayHello();
    }

	public int calculate(int a, int b) throws RemoteException {
	System.out.println("Calling calculate in smart proxy");
	return serverProxy.calculate(a, b);
    }

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

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

	/** Implement RemoteMethodControl */

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

	public RemoteMethodControl setConstraints(MethodConstraints mc) {
	    return new ConstrainableProxy(
		(Hello) ((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(Hello 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と同じくsayHello()とcalculate(int a, int b) メソッドがありますが、具体的な定義はProxy.javaではなくServer.javaの方でやっていることに注目して欲しいです。 さて、サーバ側の準備はできました。今度はそれらのサービスを利用するクライントプログラムの中身を確認しましょう。
/*
 *
 * 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.helloNew;

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;

/**
 * Defines an application that makes calls to a remote Hello 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.helloNew.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 Hello.
 *
 * @author Sun Microsystems, Inc.
 */
public class Client {

    /**
     * Starts an application that makes calls to a remote Hello 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.helloNew.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.helloNew.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.helloNew.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[] { Hello.class }, null),
	    filter, Long.MAX_VALUE);
	Hello server = (Hello) serviceItem.service;

	/* Use the server */
	System.out.println("Server says: " + server.sayHello());
	System.out.println("Server returns: " +server.calculate(4, 5));

	/* 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
            }
	}
    }
}


クライントプログラムではHello Interfaceに記載されているsayHello以外にint calculate(...)メソッドを呼び出しています。

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

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

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

    Steps

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

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

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

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

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

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

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

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