Compiling and Running the Example
Now that the code for the compute engine example has been written, it needs to be compiled and run.
编译和运行示例
到现在为止,计算引擎的示例已经写完了,现在需要编译和运行。
Compiling the Example Programs
In this section, you learn how to compile the server and the client programs that make up the compute engine example.
Running the Example Programs
Finally, you run the server and client programs and consequently compute the value of .
编译示例程序
在这个章节中,你将学到怎样编译组成计算引擎示例的服务器和客户端程序。
运行示例程序
最后,你可以运行服务器和客户端程序,以计算其结果。
Compiling the Example Programs
In a real-world scenario in which a service such as the compute engine is deployed, a developer would likely create a Java Archive (JAR) file that contains the Compute and Task interfaces for server classes to implement and client programs to use.
Next, a developer, perhaps the same developer of the interface JAR file, would write an implementation of the Compute interface and deploy that service on a machine available to clients. Developers of client programs can use the Compute and the Task interfaces, contained in the JAR file, and independently develop a task and client program that uses a Compute service.
In this section, you learn how to set up the JAR file, server classes, and client classes. You will see that the client's Pi class will be downloaded to the server at runtime. Also, the Compute and Task interfaces will be downloaded from the server to the registry at runtime.
编译示例程序
在一个真实的方案中,像计算引擎这样的服务端程序是需要部署的。开发者可能将包含Compute和Task接口(用于服务端程序实现和客户端程序使用)的类打包成JAR。
紧接着,开发者(和打包的开发人员有可能是同一个)将会实现Compute接口,并将其部署在某台机器上供客户端使用。客户端的开发人员可以使用包含在JAR文件中的Compute和Task接口,使用Compute服务独立地开发一个任务和客户端程序。
在这个章节中,你将了解到怎样设置JAR文件,服务端类,客户端类。你将明白客户端Pi类将会在运行时被下载到服务器端。同时,Compute和Task接口在运行时将会从服务器端下载到注册表中。
This example separates the interfaces, remote object implementation, and client code into three packages:
在这个示例中,将接口,远程对象实现类,客户端代码分到了三个包中:
?compute – Compute and Task interfaces
?engine – ComputeEngine implementation class
?client – ComputePi client code and Pi task implementation
?compute – Compute and Task 接口
?engine – ComputeEngine 实现类
?client – ComputePi 客户端代码和Pi任务实现
First, you need to build the interface JAR file to provide to server and client developers.
首先,你必须创建接口文件给服务端和客户端开发者。
Building a JAR File of Interface Classes
First, you need to compile the interface source files in the compute package and then build a JAR file that contains their class files.
Assume that user waldo has written these interfaces and placed the source files in the directory c:\home\waldo\src\compute on Windows or the directory /home/waldo/src/compute on Solaris OS or Linux.
Given these paths, you can use the following commands to compile the interfaces and create the JAR file:
创建包含接口的JAR文件
首先,你必须编译compute包中的接口源文件,然后创建一个包含它们类文件的JAR文件。
假设用户waldo已经编写了这些接口,并将它们放在目录:c:\home\waldo\src\compute(windows)或/home/waldo/src/compute(Solaris OS或Linux).
根据这些路径,你可以使用如下命令来编译接口和创建JAR文件:
Microsoft Windows:
cd c:\home\waldo\src
javac compute\Compute.java compute\Task.java
jar cvf compute.jar compute\*.class
Solaris OS or Linux:
cd /home/waldo/src
javac compute/Compute.java compute/Task.java
jar cvf compute.jar compute/*.class
--------------------------------------------------------------------------------
The jar command displays the following output due to the -v option:
根据-v可选项,jar命令显示出了以下内容:
added manifest
adding: compute/Compute.class(in = 307) (out= 201)(deflated 34%)
adding: compute/Task.class(in = 217) (out= 149)(deflated 31%)
Now, you can distribute the compute.jar file to developers of server and client applications so that they can make use of the interfaces.
现在,你可以将compute.jar文件分配给服务端开发者和客户端程序,以使他们能使用这些接口。
After you build either server-side or client-side classes with the javac compiler, if any of those classes will need to be dynamically downloaded by other Java virtual machines, you must ensure that their class files are placed in a network-accessible location.
In this example, for Solaris OS or Linux this location is /home/user/public_html/classes because many web servers allow the accessing of a user's public_html directory through an HTTP URL constructed as http://host/~user/.
If your web server does not support this convention, you could use a different location in the web server's hierarchy, or you could use a file URL instead. The file URLs take the form file:/home/user/public_html/classes/ on Solaris OS or Linux and the form file:/c:/home/user/public_html/classes/ on Windows. You may also select another type of URL, as appropriate.
The network accessibility of the class files enables the RMI runtime to download code when needed. Rather than defining its own protocol for code downloading, RMI uses URL protocols supported by the Java platform (for example, HTTP) to download code.
Note that using a full, heavyweight web server to serve these class files is unnecessary. For example, a simple HTTP server that provides the functionality needed to make classes available for downloading in RMI through HTTP can be found at . Also see Remote Method Invocation Home.
在你用javac编译器命令构建了服务端和客户端类后,如果这些类中的任何一个类都需要被其它的JVM动态下载,你必须确保它们的类文件放置在网络可访问的位置上。
在这个示例中,对于Solaris OS或Lunux,这个位置是 /home/user/public_html/classes ,因为许多的web服务器允许通过一个HTTP URL构造的http://host/~user/来访问用户的public_html目录。
如果你的web服务器不支持这种协定,那可以使用web服务器层次中不同的位置,或者你可以使用一个file URL代替。file URLs接受这种格式的文件: file:/home/user/public_html/classes/ on Solaris OS or Linux 或者file:/c:/home/user/public_html/classes/ on Windows。你也可以选用任何恰当类型的URL.
类文件的网络可访问性使得RMI运行时在需要时能够下载代码。对于下载,RMI不定义自己的协议,而是使用Java平台支持的URL协议(如:HTTP)来下载代码。
值得注意的是使用一个完全重量级的web服务器来服务这些类文件是不必要的。如,一个简单的HTTP服务器在RMI中能通过HTTP协议下载代码。也可以参见RMI主页。
Building the Server Classes
The engine package contains only one server-side implementation class, ComputeEngine, the implementation of the remote interface Compute.
Assume that user ann, the developer of the ComputeEngine class, has placed ComputeEngine.java in the directory c:\home\ann\src\engine on Windows or the directory /home/ann/src/engine on Solaris OS or Linux.
She is deploying the class files for clients to download in a subdirectory of her public_html directory, c:\home\ann\public_html\classes on Windows or /home/ann/public_html/classes on Solaris OS or Linux. This location is accessible through some web servers as http://host:port/~ann/classes/.
The ComputeEngine class depends on the Compute and Task interfaces, which are contained in the compute.jar JAR file. Therefore, you need the compute.jar file in your class path when you build the server classes.
Assume that the compute.jar file is located in the directory c:\home\ann\public_html\classes on Windows or the directory /home/ann/public_html/classes on Solaris OS or Linux. Given these paths, you can use the following commands to build the server classes:
构建服务端类
engine包仅包含一个服务端实现类-ComputeEngine,它实现了远程接口Compute.
假设用户ann(ComputeEngine类的开发者),已经将ComputeEngine.java放在了c:\home\ann\src\engine(Windows)或者/home/ann/src/engine(Solaris OS or Linux)目录下.
她正在开发一个客户端类来下载她的public_html目录的子目录,c:\home\ann\public_html\classes(Windows)或/home/ann/public_html/classes(Solaris OS or Linux).可以通过在一些web服务器中使用http://host:port/~ann/classes/来访问这个地址。
ComputeEngine类依赖于Compute和Task接口,这些接口包含在compute.jar JAR文件中。因此,当你构建服务端类文件时,你需要将compute.jar放置在你的构建路径中。
假设compute.jar在c:\home\ann\public_html\classes(Windows)或/home/ann/public_html/classes(Solaris OS or Linux)目录下。你可以如下命令来构建服务端类:
Microsoft Windows:cd c:\home\ann\srcjavac -cp c:\home\ann\public_html\classes\compute.jar engine\ComputeEngine.javaSolaris OS or Linux:cd /home/ann/srcjavac -cp /home/ann/public_html/classes/compute.jar engine/ComputeEngine.java
The stub class for ComputeEngine implements the Compute interface, which refers to the Task interface. So, the class definitions for those two interfaces need to be network-accessible for the stub to be received by other Java virtual machines such as the registry's Java virtual machine.
The client Java virtual machine will already have these interfaces in its class path, so it does not actually need to download their definitions. The compute.jar file under the public_html directory can serve this purpose.
Now, the compute engine is ready to deploy. You could do that now, or you could wait until after you have built the client.
Building the Client Classes
The client package contains two classes, ComputePi, the main client program, and Pi, the client's implementation of the Task interface.
Assume that user jones, the developer of the client classes, has placed ComputePi.java and Pi.java in the directory c:\home\jones\src\client on Windows or the directory /home/jones/src/client on Solaris OS or Linux. He is deploying the class files for the compute engine to download in a subdirectory of his public_html directory, c:\home\jones\public_html\classes on Windows or /home/jones/public_html/classes on Solaris OS or Linux. This location is accessible through some web servers as http://host:port/~jones/classes/.
The client classes depend on the Compute and Task interfaces, which are contained in the compute.jar JAR file. Therefore, you need the compute.jar file in your class path when you build the client classes.
Assume that the compute.jar file is located in the directory c:\home\jones\public_html\classes on Windows or the directory /home/jones/public_html/classes on Solaris OS or Linux. Given these paths, you can use the following commands to build the client classes:
对于ComputeEngine类(实现了Compute接口)的stub类,它还引用了Task接口。因此,这两个接口的定义对于可被其他JVM(如注册表的虚拟机)接收的stub来说,必须是网络可访问的。
客户端JVM的构建路径上已经有了这些接口,因此它没有必要在下载它们的定义。位于public_html目录下的compute.jar文件可以达到这种目的。
现在,计算引擎已经准备好部署。你可以现在部署,也可以在创建好客户端后再来部署。
构建客户端类
client包包含有两个类,ComputePi(主要客户端程序)和Pi(Task接口的客户端实现).
假设用户jones(客户端程序的开发者),已经将ComputePi.java和Pi.java放在了c:\home\jones\src\client(Windows)或/home/jones/src/client(Solaris OS or Linux)目录下.
由于客户端类依赖于Compute和Task接口(包含在compute.jar中)。因此,你必须在类构建路径中包含compute.jar文件。
假设compute.jar在目录c:\home\jones\public_html\classes(Windows)或/home/jones/public_html/classes(Solaris OS or Linux)下。根据这些路径,你可以使用下面的命令来构造客户端:
Microsoft Windows:cd c:\home\jones\srcjavac -cp c:\home\jones\public_html\classes\compute.jar client\ComputePi.java client\Pi.javamkdir c:\home\jones\public_html\classes\clientcp client\Pi.class c:\home\jones\public_html\classes\clientSolaris OS or Linux:cd /home/jones/srcjavac -cp /home/jones/public_html/classes/compute.jar client/ComputePi.java client/Pi.javamkdir /home/jones/public_html/classes/clientcp client/Pi.class /home/jones/public_html/classes/client
Only the Pi class needs to be placed in the directory public_html\classes\client because only the Pi class needs to be available for downloading to the compute engine's Java virtual machine. Now, you can run the server and then the client.
只有Pi类需要被放置在public_html\classes\client 目录下,因为只有Pi类需要被下载到计算引擎的JVM中。现在你可以运行服务器,然后运行客户端了。
Running the Example Programs
A Note About Security
The server and client programs run with a security manager installed. When you run either program, you need to specify a security policy file so that the code is granted the security permissions it needs to run. Here is an example policy file to use with the server program:
运行示例程序
关于安全的记录
服务端和客户端程序需要同一个已安装的安全管理器一起运行。当你无论运行哪一个程序时,你必须指定一个安全策略文件,以保证代码在运行时被授予了安全权限。下面是一个服务端程序使用的样例策略文件:
grant codeBase "file:/home/ann/src/" { permission java.security.AllPermission;};
Here is an example policy file to use with the client program:
下面是一个客户端程序使用的样例策略文件:
grant codeBase "file:/home/jones/src/" { permission java.security.AllPermission;};
For both example policy files, all permissions are granted to the classes in the program's local class path, because the local application code is trusted, but no permissions are granted to code downloaded from other locations.
Therefore, the compute engine server restricts the tasks that it executes (whose code is not known to be trusted and might be hostile) from performing any operations that require security permissions. The example client's Pi task does not require any permissions to execute.
In this example, the policy file for the server program is named server.policy, and the policy file for the client program is named client.policy.
对于两个安全策略文件,所有的权限都被授予了本地类路径的程序,因为本地应用程序代码是可信任的,但需要从其他地方下载的代码却没有授权。
因此,计算引擎的服务器限制了它那些需要安全许可的任务操作。这个示例中的Pi,不需要任何安全许可就可以得到执行。
这个示例中,服务端程序的策略文件命名为server.policy,客户端程序的策略文件命名为client.policy.
Starting the Server
Before starting the compute engine, you need to start the RMI registry. The RMI registry is a simple server-side bootstrap naming facility that enables remote clients to obtain a reference to an initial remote object. It can be started with the rmiregistry command.
Before you execute 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 that you want downloaded to clients of your remote objects.
To start the registry on the server, execute the rmiregistry command. This command produces no output and is typically run in the background. For this example, the registry is started on the host mycomputer.
启动服务器
在启动计算引擎之前,你必须先启动RMI注册表。RMI注册表是一个简单的服务端引用命名设施,它可以使得远程客户端获取最初远程对象的引用。它可以 rmiregistry命令开始。
在你开始执行 rmiregistry之前,你必须确保运行rmiregistry的窗口不需要CLASSPATH环境变量设置或CLASSPATH环境中不包含你从远程对象下载至客户端所需的任何类路径。
执行 rmiregistry命令,先在服务器上启动注册表。这个命令不会产生任何输出,且以后台形式运行的。对这个例子来说,注册表的启动是在mycomputer的计算机上执行的。
Microsoft Windows (use javaw if start is not available):start rmiregistrySolaris OS or Linux:rmiregistry &
By default, the registry runs on port 1099. To start the registry on a different port, specify the port number on the command line.
Do not forget to unset your CLASSPATH environment variable.
默认情况下,注册表运行在1099端口上。如果想在其它端口上启动注册表,可以在命令行上指定端口号。不要忘记还原你的CLASSPATH环境变量。
Microsoft Windows:start rmiregistry 2001Solaris OS or Linux:rmiregistry 2001 &
Once the registry is started, you can start the server. You need to make sure that both the compute.jar file and the remote object implementation class are in your class path.
When you start the compute engine, you need to specify, using the java.rmi.server.codebase property, where the server's classes are network accessible.
In this example, the server-side classes to be made available for downloading are the Compute and Task interfaces, which are available in the compute.jar file in the public_html\classes directory of user ann.
The compute engine server is started on the host mycomputer, the same host on which the registry was started.
一旦注册表启动之后,你就可以启动服务器了。你必须确保compute.jar和远程实现类在你的类构建路径中。当你启动计算引擎时,你需要指定使用java.rmi.server.codebase属性,此属性指定服务器类在此位置是可以网络访问的。
在这个例子中,服务端类被允许下载的类是Compute和Task接口,它们位于用户ann的public_html\classes目录下的compute.jar中。
计算引擎服务器是从主机名为mycomputer上启动的,同注册时启动的主机一样。
Microsoft Windows:java -cp c:\home\ann\src;c:\home\ann\public_html\classes\compute.jar -Djava.rmi.server.codebase=file:/c:/home/ann/public_html/classes/compute.jar -Djava.rmi.server.hostname=mycomputer.example.com -Djava.security.policy=server.policy engine.ComputeEngineSolaris OS or Linux:java -cp /home/ann/src:/home/ann/public_html/classes/compute.jar -Djava.rmi.server.codebase=http://mycomputer/~ann/classes/compute.jar -Djava.rmi.server.hostname=mycomputer.example.com -Djava.security.policy=server.policy engine.ComputeEngine
The above java command defines the following system properties:
?The java.rmi.server.codebase property specifies the location, a codebase URL, from which the definitions for classes originating from this server can be downloaded. If the codebase specifies a directory hierarchy (as opposed to a JAR file), you must include a trailing slash at the end of the codebase URL.
?The java.rmi.server.hostname property specifies the host name or address to put in the stubs for remote objects exported in this Java virtual machine. This value is the host name or address used by clients when they attempt to communicate remote method invocations. By default, the RMI implementation uses the server's IP address as indicated by the java.net.InetAddress.getLocalHost API. However, sometimes, this address is not appropriate for all clients and a fully qualified host name would be more effective. To ensure that RMI uses a host name (or IP address) for the server that is routable from all potential clients, set the java.rmi.server.hostname property.
?The java.security.policy property is used to specify the policy file that contains the permissions you intend to grant.
以上的命令定义了以下系统属性:
?The java.rmi.server.codebase property specifies the location, a codebase URL, from which the definitions for classes originating from this server can be downloaded. If the codebase specifies a directory hierarchy (as opposed to a JAR file), you must include a trailing slash at the end of the codebase URL.
?The java.rmi.server.hostname property specifies the host name or address to put in the stubs for remote objects exported in this Java virtual machine. This value is the host name or address used by clients when they attempt to communicate remote method invocations. By default, the RMI implementation uses the server's IP address as indicated by the java.net.InetAddress.getLocalHost API. However, sometimes, this address is not appropriate for all clients and a fully qualified host name would be more effective. To ensure that RMI uses a host name (or IP address) for the server that is routable from all potential clients, set the java.rmi.server.hostname property.
?The java.security.policy property is used to specify the policy file that contains the permissions you intend to grant.
Starting the Client
Once the registry and the compute engine are running, you can start the client, specifying the following:
?The location where the client serves its classes (the Pi class) by using the java.rmi.server.codebase property
?The java.security.policy property, which is used to specify the security policy file that contains the permissions you intend to grant to various pieces of code
?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 calculation
Start the client on another host (a host named mysecondcomputer, for example) as follows:
启动客户端:
一旦注册表和计算引擎运行后,你可以启动客户端,按下面进行指定:
?通过java.rmi.server.codebase属性来指定它的提供服务的客户端位置
?通过设置java.security.policy属性来指定安全策略文件,此文件包含你给不同代码片断授予的权限
?通过命令行参数,指定在计算机使用到的服务器的主机名和精度数目
Start the client on another host (a host named mysecondcomputer, for example) as follows:
像下面这样,在另一台主机上启动客户端(如,名为mysecondcompute的主机)
--------------------------------------------------------------------------------
Microsoft Windows:java -cp c:\home\jones\src;c:\home\jones\public_html\classes\compute.jar -Djava.rmi.server.codebase=file:/c:/home/jones/public_html/classes/ -Djava.security.policy=client.policy client.ComputePi mycomputer.example.com 45Solaris OS or Linux:java -cp /home/jones/src:/home/jones/public_html/classes/compute.jar -Djava.rmi.server.codebase=http://mysecondcomputer/~jones/classes/ -Djava.security.policy=client.policy client.ComputePi mycomputer.example.com 45
Note that the class path is set on the command line so that the interpreter can find the client classes and the JAR file containing the interfaces. Also note that the value of the java.rmi.server.codebase property, which specifies a directory hierarchy, ends with a trailing slash.
After you start the client, the following output is displayed:
注意,类路径是通过命令行进行设置的,这样解释器能找到客户端类和包含接口的JAR文件。同时也要注意到java.rmi.server.codebase属性的值,以反斜杠指定了一个目录层次
3.141592653589793238462643383279502884197169399
The following figure illustrates where the rmiregistry, the ComputeEngine server, and the ComputePi client obtain classes during program execution.
下图说明了rmiregistry,ComputeEngine Server,ComputePi客户端在程序执行时获取类的情况.
When the ComputeEngine server binds its remote object reference in the registry, the registry downloads the Compute and Task interfaces on which the stub class depends.
These classes are downloaded from either the ComputeEngine server's web server or file system, depending on the type of codebase URL used when starting the server.
Because the ComputePi client has both the Compute and the Task interfaces available in its class path, it loads their definitions from its class path, not from the server's codebase.
Finally, the Pi class is loaded into the ComputeEngine server's Java virtual machine when the Pi object is passed in the executeTask remote call to the ComputeEngine object.
The Pi class is loaded by the server from either the client's web server or file system, depending on the type of codebase URL used when starting the client.
当ComputeEngine server将它的远程对象绑定到注册表中的时候,注册表下载了stub类依赖的Compute和Task接口。
根据启动服务器所使用的codebase URL的类型,这些类可以从ComputeEngine服务器的web服务器中下载,也可以从文件系统中下载.
因为ComputePi客户端在其类路径上含有Compute和Tash接口,它可以从它的类路径加载它们的定义,而不是是服务器的代码基上。
最后,当执行ComputeEngine对象的executeTask远程调用时,Pi类将被加载进ComputeEngine服务器的JVM中。
Pi类被加载到服务器可以通过客户端的web服务器也可以通过文件系统,这要取决于启动客户端时配置的代码基URL类型。