9.6 一个RMI的分布式应用的实例 用RMI编写一个分布式应用,核心有以下三方面: 定位远程对象 与远程对象通信: 2. 可以象操作普通对象一样传送并返回一个远程对象的引用(指针)。 与远程对象通信: 底层的通信由RMI实现,对于系统开发人员来说,远程调用和标准的Java方法调用没有什么区别。 为需要传递的对象装载类的字节码 RMI允许调用者向远程对象传递一个对象,因此 RMI提供这种装载对象的机制。
9.6 一个RMI的分布式应用的实例 Web Server Client Server Web Server registry URL protocol RMI Server RMI URL protocol RMI Web Server registry URL protocol
9.6 一个RMI的分布式应用的实例 一、问题的提出 Server Client task Remote object Compute engin Server Remote object Client task
9.6 一个RMI的分布式应用的实例 分布特点: 前提条件: 技术支持: engin开发,先运行,task后定义.写engin时不对执行什么任务作任何规定.任务可以是任意定制的. 前提条件: 定义任务的类,要规定任务的实现步骤,使得这个任务能够提交给engin去执行.使用server上的 CPU资源. 技术支持: RMI的动态装载功能. The registry may be shared by all servers running on a host, or an individual server process may create and use its own registry, if desired.
9.6 一个RMI的分布式应用的实例 远程对象必须继承远程接口 确定那些方法是远程方法,为此定义远程接口 A.m1() executeTask compute engine Compute execute Task 远程方法 m1 远程对象 A client server 远程对象必须继承远程接口 确定那些方法是远程方法,为此定义远程接口 远程接口只负责提供方法名,不一共实现细节,因此必须由一个对象来实现接口
9.6 一个RMI的分布式应用的实例 二、设计一个服务器 核心协议:提交任务,执行任务,返回结果 client 在java中远程调用是通过定义远程接口来实现的, 一个接口只能有一个方法 不同类型的任务,只要他们实现了Task类型,就可以在engin上运行. 实现这个接口的类,可以包含任何任务计算需要的数据以及和任何任务计算需要的方法. By extending the interface java.rmi.Remote, this interface marks itself as one whose methods can be called from any virtual machine. Any object that implements this interface becomes a remote object. As a member of a remote interface, the executeTask method is a remote method. Therefore the method must be defined as being capable of throwing a java.rmi.RemoteException. This exception is thrown by the RMI system during a remote method call to indicate that either a communication failure or a protocol error has occurred. A RemoteException is a checked exception, so any code making a call to a remote method needs to handle this exception by either catching it or declaring it in its throws clause.
9.6 一个RMI的分布式应用的实例 (1)定义远程接口 第一个接口:compute package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { Object executeTask(Task t) throws RemoteException;} executeTask compute engine Compute execute Task The second interface needed for the compute engine defines the type Task. This type is used as the argument to the executeTask method in the Compute interface. The compute.Task interface defines the interface between the compute engine and the work that it needs to do, providing the way to start the work. The Task interface defines a single method, execute, which returns an Object, has no parameters, and throws no exceptions. Since the interface does not extend Remote, the method in this interface doesn't need to list java.rmi.RemoteException in its throws clause. The return value for the Compute's executeTask and Task's execute methods is declared to be of type Object. This means that any task that wants to return a value of one of the primitive types, such as an int or a float, needs to create an instance of the equivalent wrapper class for that type, such as an Integer or a Float, and return that object instead. Note that the Task interface extends the java.io.Serializable interface. RMI uses the object serialization mechanism to transport objects by value between Java virtual machines. Implementing Serializable marks the class as being capable of conversion into a self-describing byte stream that can be used to reconstruct an exact copy of the serialized object when the object is read back from the stream. package compute; import java.io.Serializable; public interface Task extends Serializable { Object execute(); } 第二个接口:定义一个task类型,作为参数传给executeTask方法, 规定了engin与它的任务之间的接口,以及如何启动它的任务.它 不是一个远程接口
9.6 一个RMI的分布式应用的实例 Compute engin的设计要考虑以下问题: 1. compute engine是一个类 ComputeEngine ,它实现了 Compute接口,只要调用该类的方法executeTask, 任务就能提交上来. 2. 提交任务的Client 端程序并不知道任务是被下载到engin上执行的.因此client在定义任务时并不需要包含如何安装的server端的代码. 3. 返回类型是对象,如果结果是基本类型,需要转化成相应的对等类. 4. 用规定任务如何执行的代码填写execute方法.
9.6 一个RMI的分布式应用的实例 (2)实现远程接口 一般说来,实现一个远程接口的类至少有以下步骤: 1. 声明远程接口 2. 为远程对象定义构造函数 3. 实现远程方法 engin中创建对象的工作可以在实现远程接口类的main函数中实现: 1. 创建并安装安全管理器 2. 创建一个或更多的远程对象的实例 3. 至少注册一个远程对象
9.6 一个RMI的分布式应用的实例 package engine; import java.rmi.*; import java.rmi.server.*; import compute.*; public class ComputeEngine extends UnicastRemoteObject implements Compute { public ComputeEngine() throws RemoteException { super(); } public Object executeTask(Task t) { return t.execute(); } public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } String name = "//host/Compute"; try { Compute engine = new ComputeEngine(); Naming.rebind(name, engine); System.out.println("ComputeEngine bound"); } catch (Exception e) { System.err.println("ComputeEngine exception: " + e.getMessage()); e.printStackTrace(); }} 9.6 一个RMI的分布式应用的实例 UnicastRemoteObject is a convenience class, defined in the RMI public API, that can be used as a superclass for remote object implementations. By extending UnicastRemoteObject, the ComputeEngine class can be used to create a simple remote object that supports unicast (point-to-point) remote communication and that uses RMI's default sockets-based transport for communication. The security manager determines whether downloaded code has access to the local file system or can perform any other privileged operations. . Note that the type of the variable engine is Compute, not ComputeEngine. This declaration emphasizes that the interface available to clients is the Compute interface and its methods, not the Compute-Engine class and its methods. The java.rmi.Naming interface is used as a front-end API for binding, or registering, and looking up remote objects in the registry. Once a remote object is registered with the RMI registry on the local host, callers on any host can look up the remote object by name, obtain its reference, and then invoke remote methods on the object. The registry may be shared by all servers running on a host, or an individual server process may create and use its own registry, if desired.
callexecuteTask(task) 9.6 一个RMI的分布式应用的实例 在构造函数中,通过super(), a UnicastRemoteObject 被启动,即它可以侦听客户端来的请求输入 只有一个远程方法,参数是客户端远程调用这个方法时传来的任务.这个任务被下载到engin,远程方法的内容就是调用客户端任务的方法,并把结果回送给调用者.实际上这个结果是在客户的任务的方法中体现的. executeTask compute engine Compute execute Task callexecuteTask(task)
9.6 一个RMI的分布式应用的实例 参数传递规则: 1. 远程对象通常通过引用传递.一个远程对象的引用是一个stub,它是客户端的代理.它实现远程对象中的远程接口的内容 2. 本地对象通过串行化拷贝到目的. 如果不作制定,对象的所有成员都将被拷贝.
9.6 一个RMI的分布式应用的实例 通过引用传递一个对象,意味着任何由于远程调用引起的变化都能反映在原始的对象中。 当传递一个远程对象时,只有远程接口是可用的, 而在实现类中定义的方法或者是非远程接口中的方法,对接收者来说是不可用的 在远程方法调用中,参数,返回值,异常等非对象是值传送. 这意味着对象的拷贝被传送到接受方。任何在对象上发生的变化不影响原始的对象 一旦服务器用rmi注册了,main方法就存在了,不需要一个守护线程工作维护服务器的工作状态,只要有一个computer engin的引用在另一个虚拟机,computer engin就不会关闭
9.6 一个RMI的分布式应用的实例 三、实现一个客户程序 目标:创建一个任务,并规定如何执行这个任务。 package compute; public interface Task extends java.io.Serializable { Object execute(); } client Pi computePi execute() ExecuteTask() task不是远程接口,但是需要传递到服务器,因此用串行化
Look up(ComputeEngin),获得了stubs Comp.executeTask(task) 9.6 一个RMI的分布式应用的实例 computePi的作用 装载安全管理器 生成一个远程对象 comp Look up(ComputeEngin),获得了stubs 生成任务对象 Pi task=new Pi() 调用ComputeEngin的远程方法 获得计算结果 Comp.executeTask(task)
9.6 一个RMI的分布式应用的实例 package client; import java.rmi.*; import java.math.*; import compute.*; public class ComputePi { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "//" + args[0] + "/Compute"; Compute comp = (Compute) Naming.lookup(name); Pi task = new Pi(Integer.parseInt(args[1])); BigDecimal pi = (BigDecimal) (comp.executeTask(task)); System.out.println(pi); } catch (Exception e) { System.err.println("ComputePi exception: " + e.getMessage()); e.printStackTrace(); } 9.6 一个RMI的分布式应用的实例 由于客户端代理stubs要从服务器下载到客户端,因此客户程序也必须装载安全管理器. The value of the first command line argument, args[0], is the name of the remote host on which the Compute object runs. Using the Naming.lookup method, the client looks up the remote object by name in the remote host's registry. When doing the name lookup, the code creates a URL that specifies the host where the compute server is running. The name passed in the Naming.lookup call has the same URL syntax as the name passed in the Naming.rebind call which was discussed earlier.
9.6 一个RMI的分布式应用的实例 Pi的作用 rmiregistry 实现Task接口 computepi 实现execute算法 engin 实现Task接口 实现execute算法
9.6 一个RMI的分布式应用的实例 package client; import compute.*; import java.math.*; public class Pi implements Task { private static final BigDecimal ZERO = BigDecimal.valueOf(0); private static final BigDecimal ONE = BigDecimal.valueOf(1); private static final BigDecimal FOUR = BigDecimal.valueOf(4); private static final int roundingMode = BigDecimal.ROUND_HALF_EVEN; public Pi(int digits) { this.digits = digits; } 9.6 一个RMI的分布式应用的实例
9.6 一个RMI的分布式应用的实例 public Object execute() { return computePi(digits); } *************************************************** * pi/4 = 4*arctan(1/5) - arctan(1/239) **************************************************** public static BigDecimal computePi(int digits) { int scale = digits + 5; BigDecimal arctan1_5 = arctan(5, scale); BigDecimal arctan1_239 = arctan(239, scale); BigDecimal pi arctan1_5.multiply(FOUR).subtract(arctan1_239).multiply(FOUR); return pi.setScale(digits, BigDecimal.ROUND_HALF_UP); }
/** * Compute the value, in radians, of the arctangent of * the inverse of the supplied integer to the speficied * number of digits after the decimal point. The value * is computed using the power series expansion for the * arctangent: * arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + * (x^9)/9 ... */ 9.6 一个RMI的分布式应用的实例
public static BigDecimal arctan(int inverseX, int scale) { BigDecimal result, numer, term; BigDecimal invX = BigDecimal.valueOf(inverseX); BigDecimal invX2 = BigDecimal.valueOf(inverseX * inverseX); numer = ONE.divide(invX, scale, roundingMode); result = numer; int i = 1; do { numer =numer.divide(invX2, scale, roundingMode); int denom = 2 * i + 1; term = numer.divide(BigDecimal.valueOf(denom), scale, roundingMode); if ((i % 2) != 0) { result = result.subtract(term); } else { result = result.add(term); } i++; } while (term.compareTo(ZERO) != 0); return result; } 9.6 一个RMI的分布式应用的实例
9.6 一个RMI的分布式应用的实例 由于Rmi的存在,系统可以做到: 1、可以直接通过名字定位远程方法的位置 2、以参数的形式将一个对象传递给一个远程方法 3、可以使一个对象到另外一个虚拟机上运行 4、计算结果可以返回
9.6 一个RMI的分布式应用的实例 将接口,远程对象,客户代码分成三个程序包: 1. compute ( Compute and Task interfaces) 2. engine ( ComputeEngine implementation class and its stub) 3. client ( ComputePi client code and Pi task implementation)
c:\home\waldo\src\compute目录下 9.6 一个RMI的分布式应用的实例 接口compute对于编程双方都是需要的,通常将接口文件打成包,分发给server和client的开发者: 假设接口的开发者将写好的接口程序放在 c:\home\waldo\src\compute目录下 cd c:\home\waldo\src javac compute\Compute.java javac compute\Task.java jar cvf compute.jar compute\*.class
9.6 一个RMI的分布式应用的实例 类文件必须是网络可访问的,rmi利用URL定位类文件 假设 ComputeEngine.java 存放在 c:\home\ann\src\engine 假设 compute.jar存放在 c:\home\ann\public_html\classes. 设置环境变量 CLASSPATH=c:\home\ann\src;c:\home\ann\public_html\classes\compute.jar
9.6 一个RMI的分布式应用的实例 编译 ComputeEngine.java,产生一个 stub,并使stub是网络可访问的. 产生stub的命令是rmic,生成的文件形式为: className_Stubs.class和className_skeleton.class 命令如下: cd c:\home\ann\src javac engine\ComputeEngine.java rmic -d . engine.ComputeEngine md c:\home\ann\public_html\classes\engine copy engine\ComputeEngine_*.class c:\home\ann\public_html\classes\engine The -d option tells the rmic compiler to place the generated class files, ComputeEngine_Stub.class and ComputeEngine_Skel.class, in the directory c:\home\ann\src\engine. You also need to make the stubs and the skeletons network accessible, so you must copy the stub and the skeleton class to the area: public_html\classes.
9.6 一个RMI的分布式应用的实例 展开接口文件 cd c:\home\ann\public_html\classes jar xvf compute.jar
9.6 一个RMI的分布式应用的实例 执行程序 1. 在启动‘compute engine’之前, 首先要启动RMI的 registry。 unset CLASSPATH start rmiregistry 2. 启动Server. 确认compute.jar文件和实现远程对象的类在指定的class路径下 set CLASSPATH= c:\home\ann\src;c:\home\ann\public_html\classes\compute.jar RMI registry是一个简单服务器端的名字服务,可以使远程客户得到一个远程对象的引用 Note that before you start the rmiregistry, you must make sure that the shell or window in which you will run rmiregistry either has no CLASSPATH environment variable set or has a CLASSPATH environment variable that does not include the path to any classes, including the stubs for your remote object implementation classes, that you want downloaded to clients of your remote objects. If you do start the rmiregistry and it can find your stub classes in through CLASSPATH, it will not remember that the loaded stub class can be loaded from your server's codebase (that was specified by the java.rmi.server. codebase property when you started up your server application). As a result, the rmiregistry will not convey to clients the true codebase associated with the stub class, and consequently, your clients will not be able to locate and load the stub class (or other server-side classes).
9.6 一个RMI的分布式应用的实例 启动 compute engine时,要规定服务器端的类在什么情况下是可用的。启动’Compute engine’ java -Djava.rmi.server.codebase= file:/c:\home\ann\public_html\classes/ -Djava.rmi.server.hostname= zaphod.east.sun.com -Djava.security.policy=java.policy engine.ComputeEngine when you start the compute engine, you need to specify, using the java.rmi.server.codebase property, where the server‘s classes will be made available. In this example, the server-side classes to be made available for downloading are the ComputeEngine’s stub and the Compute and Task interfaces, available in ann‘s public_html\classes directory. The java command above defines several properties: java.rmi.server.codebase, a property that specifies the location, a codebase URL, of classes originating from this server so that class information for objects sent to other virtual machines will include the location of the class so that a receiver can load it. If the codebase specifies a directory (as opposed to a JAR file), you must include the trailing slash in the codebase URL. java.rmi.server.hostname, a property that indicates the fully qualified host name of your server. In some networked environments, a fully qualified host name is not obtainable by using the Java APIs. RMI makes a best-effort attempt to obtain the fully-qualified hostname. If one cannot be determined, it will fall back and use the IP address. To ensure that RMI will use a hostname that is usable from potential clients, you may want to set the java.rmi.server.hostname property as a safety measure. java.security.policy, a property used to specify the policy file that contains the permissions you intend to grant specific codebases. The ComputeEngine's stub class is dynamically loaded into a client's virtual machine only when the class is not already available locally and the java.rmi.server.codebase property has been set properly, to the network-accessible location of the stub class, when the server is started. Once such a stub is loaded, it will not need to be re-loaded for additional references to ComputeEngine's objects.
9.6 一个RMI的分布式应用的实例 3. 启动 Client 指定类(pi)的位置 输入完上述命令后,得到结果 set CLASSPATH= c:\home\jones\src; c:\home\jones\public_html\classes\compute.jar -java -Djava.rmi.server.codebase= file:/c:\home\jones\public_html\classes/ -Djava.security.policy=java.policy client.ComputePi localhost 20 输入完上述命令后,得到结果 3.14159265358979323846 java.rmi.server.codebase property. as command line arguments, the host name of the server (so that the client knows where to locate the Compute remote object) and the number of decimal places to use in the pi [PENDING: get pi symbol] calculation. java.security.policy, a property used to specify the policy file that contains the permissions you intend to grant specific codebases. First set the CLASSPATH to see jones's client and the JAR file containing the interfaces. Then start the client as follows: Platform-Specific Details: Starting the Client on Host ford Note that the class path is set on the command line so that the interpreter can find jones's client and the JAR file containing the interfaces.
9.6 一个RMI的分布式应用的实例 The figure below illustrates where the rmiregistry, the ComputeEngine server and the ComputePi client obtain classes during program execution. The rmiregistry, ComputeEngine server and ComputePi obtaining classes during program execution. When the ComputeEngine server binds its remote object reference in the registry, the registry downloads the ComputeEngine_Stub, as well as the Compute and Task interfaces on which the stub class depends. These classes are downloaded from the ComputeEngine's web server (or file system, as the case may be). The ComputePi client loads the ComputeEngine_Stub, also from the ComputeEngine's web server, as a result of the Naming.lookup call. Since the ComputePi client has both the Compute and Task interfaces available in its class path, those classes are loaded from the class path, not the remote location. Finally, the Pi class is loaded into the ComputeEngine's virtual machine when the Pi object is passed in the executeTask remote call to the ComputeEngine object. The Pi class is loaded from the client's web server.
9.7 基于CORBA的分布式应用系统的实例 windowsNT (C++) Sun client (Java) Netscape (COBOL)
9.7 基于CORBA的分布式应用系统的实例 CORBA技术和Java技术的结合--Java IDL 什么是IDL? IDL是CORBA规范中的接口定义语言,不依赖于任何具体的编程语言. CORBA提供了到各种不同语言的IDL映射. Java IDL是CORBA到Java的映射,使Java也支持CORBA规范 Java IDL和Java RMI非常相似,RMI只支持Java语言写的分布对象,Java IDL可以和CORBA支持的任何一种语言编写的ORB对象进行交互 Java RMI和Java IDL目前使用的通信协议不同,分别是JRMP和IIOP.
9.7 基于CORBA的分布式应用系统的实例 在Java IDL中,客户端通过引用与远程的对象进行交互,即客户机使用stubs对远程服务器上的对象进行操作,但并不拷贝服务器上的对象. Java RMI即可以通过引用,也可以将对象下载到本地机上运行(因为有串行化功能). Java实现简单,但语言不兼容 Java IDL则可以充分发挥语言无关的优势
9.7 基于CORBA的分布式应用系统的实例 IDL Java的技术组成: IDL至Java的编译器:idltojava 生成客户端的stubs和服务器端的skeleton CORBA API 和 ORB 一个简单的名字服务
9.7 基于CORBA的分布式应用系统的实例 客户应用 C++, Java编译器 客户程序 IDL Stub 应 用 开 发 者 Skeleton C++, Java编译器 服务程序 对象实现
9.7 基于CORBA的分布式应用系统的实例 对象实现 IDL Skeleton BOA ORB内核 从反应式Agent的角度看 应用开发者 事件处理部分 IDL文件 IDL编译器 IDL Skeleton 事件处理分发部分 ORB内核 BOA 事件适配部分 事件感知部分
9.7 基于CORBA的分布式应用系统的实例 CORBA编程实例 运行在浏览器中的客户对象与远程的服务对象交互,客户端的表现是在浏览器中点击一个button,就会在一个文本域中返回服务端的时间,同时也在服务端的标准输出上打印该时间。 时间是一个对象 The data in server side is 2000.6.1 12:56:00 server button
9.7 基于CORBA的分布式应用系统的实例 ORB CLIENT STUBS SKELETONS SERVER IIOP METHOD REQUEST OBJECT REFERENCE SERVANT
9.7 基于CORBA的分布式应用系统的实例 1. 首先是定义交互接口,在文件dateit.idl中。 module TheDate (相当于包) { interface DateIt { string dateit(); }; }; 2. 用IDL接口到Java语言的映射 jidl dateit.idl 该命令会生成几个相关的java文件: DateIt.java DateItHelper.java DateItHolder.java _DateItImplBase.java StubForDateIt.java five files generated by the idltojava are: _HelloImplBase.java This abstract class is the server skeleton, providing basic CORBA functionality for the server. It implements the Hello.java interface. The server class HelloServant extends _HelloImplBase. _HelloStub.java This class is the client stub, providing CORBA functionality for the client. It implements the Hello.java interface. Hello.java This interface contains the Java version of our IDL interface. It contains the single method sayHello. The Hello.java interface extends org.omg.CORBA.Object, providing standard CORBA object functionality as well. HelloHelper.java This final class provides auxiliary functionality, notably the narrow method required to cast CORBA object references to their proper types. HelloHolder.java This final class holds a public instance member of type Hello. It provides operations for out and inout arguments, which CORBA has but which do not map easily to Java's semantics. When you write the IDL interface, you do all the programming required to generate all these files for your distributed application. The only additional work required is the actual implementation of client and server classes. In the lessons that follow, you will create HelloClient.java and HelloApplet.java client classes and the HelloServer.java class.
9.7 基于CORBA的分布式应用系统的实例 3. 编写服务对象的程序,在文件DateIt_impl.java中 package TheDate; // jidl 产生的Java文件放在TheDate包中 import org.omg.CORBA.*; import java.io.*; import java.awt.*;import java.util.Date; import java.lang.System; public class DateIt_impl extends _DateItImplBase //扩展了 jidl 生成的抽象类_DateItImplBase { String date_time; public String dateit() { date_time=(new Date()).toString(); //获取时间 System.out.println(date_time); return date_time;// 向客户端返回时间串 }
9.7 基于CORBA的分布式应用系统的实例 4. 编写服务方的程序,在文件Server.java中。 package TheDate; import org.omg.CORBA.*;import java.io.*; public class Server { public static void main(String args[]) {try { // 创建ORB和BOA对象实例 ORB orb = ORB.init(args, new java.util.Properties()); // 生成服务对象实例 BOA boa = orb.BOA_init(args); DateIt_impl p = new DateIt_impl(); //创建服务对象实例
9.7 基于CORBA的分布式应用系统的实例 // 保存引用 try { String ref = orb.object_to_string(p); //将对象编码成字符串 String refFile = "date.ref"; FileOutputStream file = new FileOutputStream(refFile); PrintStream out = new PrintStream(file); out.println(ref); //存入文件date.ref中 out.flush(); file.close(); }catch(IOException ex) { System.err.println("Can't write to" +ex.getMessage()); System.exit(1); }
9.7 基于CORBA的分布式应用系统的实例 //将引用存入html文件中,参见后面列出的date.html 文 try { String ref = orb.object_to_string(p); String refFile = "c:\\Inetpub\\wwwroot\\Docs\\date.html"; FileOutputStream file = new FileOutputStream(refFile); PrintStream out = new PrintStream(file); out.println("<applet codebase= \"http://202.118.243.55/docs\" ”+ "code= \"TheDate/Client.class\" " +” width=500 height=300>");
9.7 基于CORBA的分布式应用系统的实例 //指由Client.java编译成的class文件 out.println("<param name=ior value=\"" + ref + "\">"); //将由服务对象转化成的字符串存入超文本文件中 out.println("<param name=org.omg.CORBA.ORBClass " + "value=com.aic.CORBA.IIOPORB>"); out.println("<param =com.aic.CORBA.ORBSingleton>"); name=org.omg.CORBA.ORBSingletonClass " + "value out.println("</applet>"); out.flush(); file.close(); //这样浏览器调入该超文本页面时,会运行Client.class的applet,并将包含标识服务对象的字符串由参数ior传递给applet。 } catch(IOException ex) { System.err.println(“Can't write to ”+ex.getMessage()+“”); System.exit(1); } 9.7 基于CORBA的分布式应用系统的实例
9.7 基于CORBA的分布式应用系统的实例 // 服务对象就绪,准备接受请 boa.impl_is_ready(null); System.exit(0); } catch(SystemException ex) { System.err.println(ex.getMessage()); ex.printStackTrace(); System.exit(1); }
5. 编写客户方的程序,在文件Client.java中。 9.7 基于CORBA的分布式应用系统的实例 5. 编写客户方的程序,在文件Client.java中。 package TheDate;//由于jidl产生的JAVA文件放在package TheDate中,因此该语句是必须的 import org.omg.CORBA.*; import java.io.*; import java.awt.*; import java.util.Date; import java.lang.System;
9.6 各种主流技术的主要开发过程--CORBA public class Client extends java.applet.Applet { private DateIt serverdate; private Button button; private TextField outdate; public void init() { String ior = getParameter("ior"); //Applet 只能从包含它的HTML文件获取IOR串 见Server.java. // 产生ORB实例 ORB orb = ORB.init(this, null); // Create client object org.omg.CORBA.Object obj = orb.string_to_object(ior);
9.6 各种主流技术的主要开发过程--CORBA //串到对象的转化 if(obj == null) throw new RuntimeException(); serverdate = DateItHelper.narrow(obj); //产生对象实例,其实是服务对象的映射 // 添加serverdate按钮和文字域 button = new Button("Dateis"); outdate = new TextField("",30); this.add(button); this.add(outdate); }
9.6 各种主流技术的主要开发过程--CORBA // 事件处理 // public boolean action(Event event, java.lang.Object arg) { if(event.target == button) { outdate.setText("please wait..."); outdate.setText(serverdate.dateit()); //调用服务对象的函数,返回服务端的时间 return true; } else return super.action(event, arg);