ICE入门(1)

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

ICE 文档翻译(部分,基于3.3.1

Printer.ice

内容

module demo{
    interface Printer{
        void printString(string s);
    };
};
 

 

3.4. 书写一个简单的java 应用程序

 

这个模块向我们展示了我们将如何基于java 实现一个简单的ICE 应用

 

1. 编译基于javaslice 声明

第一步是创建一个基于java 应用的简单的slice 声明,在linux 下面你可以使用面的方法来实现:

$ mkdir generated

$ slice2java --output-dir generated Printer. ice

其中 –output-dir 选项的意义是指定你用slice2java 命令生成的代码的路径,上文的意义是将代码生成在当前目录的generated 下面。如果不出意外的话你会发现slice2java 命令执行完后为你生成了一些javasource 文件,我们不必关心其中的细节,但是我们必须知道他为我们生成了我们在Printer.ice 中定义的Printer 接口(_PrinterDisp ),接下来的实现,将会继承这个类。

 

2. 书写服务器端的代码:

slice 声明好我们服务端的类以后,我们必须得创建一个属于自己的class ,供服务器端调用,下面的是死规定:这个类的类名必须使用我们的定义的接口名+I 的后缀(即PrinterI )而且必须继承_PrinterDisp 类。_PrinterDisp 是抽象类,他里面有个方法,正是你在Printer.ice 中定义的那个方法名,你要在这个方法里添加你想要实现的代码。这里我们实现的很简单,仅仅是让他打印从客户端接收到的字符串而已。

完整的服务前端代码如下:

public class Server {

public static void

main(String[] args)

{

int status = 0;

Ice.Communicator ic = null;

try {

ic = Ice.Util.initialize(args);

Ice.ObjectAdapter adapter

= ic.createObjectAdapterWithEndpoints(

"SimplePrinterAdapter", "default -p 10000");

Ice.Object object = new PrinterI();

adapter.add(

object,

ic.stringToIdentity("SimplePrinter"));

adapter.activate();

ic.waitForShutdown();

} catch (Ice.LocalException e) {

e.printStackTrace();

status = 1;

} catch (Exception e) {

System.err.println(e.getMessage());

status = 1;

}

if (ic != null) {

// Clean up

//

try {

ic.destroy();

} catch (Exception e) {

System.err.println(e.getMessage());

status = 1;

}

}

System.exit(status);

}

} 
 

注意这个代码的结构。

 

main 方法中包含了2try 模块,我们在其中实现了自己的全部的服务器端的代码,其中第一个我们catch 住了ICE 可能抛出的运行时异常,我们的目的是如果ICE 遇到了某种运行时异常,我们就把完整的堆栈打印出来并且返回main 方法,这时虚拟机就会被告知发生了异常并且会退出程序。第二个异常是完全无法预料的,如果发生了我们同样也会告知程序退出。

当程序退出之前,我们先要销毁communicator 对象(当然前提是我们已经正确创建了这个对象),这样做可以正确的终止ICE 运行时,否则后果自负。

 

第一个try 模块包含的如下代码:

 

 ic = Ice.Util.initialize(args);

Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints( "SimplePrinterAdapter", "default -p 10000");

Ice.Object object = new PrinterI();

adapter.add( object, ic.stringToIdentity("SimplePrinter"));

adapter.activate();

ic.waitForShutdown(); 
 

这段代码经历了以下步骤:

*. 通过执行Ice.Util.initialize 方法我们初始化了ICE 服务(我们传递了args 参数,以防服务初始化时需要什么参数。),成功以后将会返回ICE 运行时的主句柄Ice::Communicator 对象。

*. 我们通过调用在Communicator 之上的createObjectAdapterWithEndpoints 方法,创建了一个对象adapter ,命名为“SimplePrinterAdapter” ,和adapter 对象的默认监听端口“default -p 10000” ,端口为10000, 一目了然。

*. 接下来就是服务端运行时的初始化并且我们通过实力化PrinterI 对象实现了Printer 的接口。

 

*. 我们通过执行add 方法来通知这个adapterICE 添加了新的服务,被添加的参数一定是要经过初始化的才可以,这个服务的名字叫做“SimplePrinter” (如果有多个printers ,每一个都要被命名成新的不同名字,并且还添加新的服务名称。也就相当于你添加了新的服务给ICE )。

 

*. 最后我们的waitForShutdown. 方法就是让ICE 线程挂起,直到你调用关闭运行时的方法,或者通过信号响应(貌似翻译的不对)(到目前位置我们只能手动kill 了。)

 

 

请注意,即使只有上面的哪一点点代码,也已经适用于几乎所有的server 了(几乎所有的服务声明都是这样的),你可以把那段代码放入一个Helper 类,然后你以后开发的时候就再也不用去每次都书写那些代码了。我们可以用如下方法编译:

 

$ mkdir classes

$ javac -d classes -classpath classes:$ICEJ_HOME/lib/Ice.jar -source 1.4 Server.java PrinterI.java generated/Demo/*.java

 

当然我本人比较推荐eclipse 或者其他的可以自动编译的工具。

 

上面的命令将编译我们通过slice 生成的代码, 我们定义了ICEJ_HOME 环境变量作为包含ICE 运行库环境的根目录(例如:如果你把ICE 安装在/opt/IceJ 目录下,那么你的$ICEJ_HOME 的意义就是表示目录/opt/IceJ ),另外需要注意的是ICE 所有java 代码都是使用ant 编译的,关于ant 不懂的话可以看看ICEDemo 或者或者google 一下。

 

客户端代码如下:

 

客户端的代码看起来有点像服务器端的代码:

public class Client {

public static void

main(String[] args)

{

int status = 0;

Ice.Communicator ic = null;

try {

ic = Ice.Util.initialize(args);

Ice.ObjectPrx base = ic.stringToProxy(

"SimplePrinter:default -p 10000");

Demo.PrinterPrx printer

= Demo.PrinterPrxHelper.checkedCast(base);

if (printer == null)

throw new Error("Invalid proxy");


printer.printString("Hello World!");

} catch (Ice.LocalException e) {

e.printStackTrace();

status = 1;

} catch (Exception e) {

System.err.println(e.getMessage());

status = 1;

}

if (ic != null) {

// Clean up

//

try {

ic.destroy();

} catch (Exception e) {

System.err.println(e.getMessage());

status = 1;

}

}

System.exit(status);

}

} 
 

 

 

 

注意这客户端的代码布局和服务器端的代码布局是一样的,trycatch 模块来处理异常,功能如下:

 

*. 和服务器端一样,我们通过调用Ice.Util.initialize 初始化Ice 运行时。

 

*. 接下来是为远程打印机获取一个代理,我们通过在communicator 中以"SimplePrinter:default -p 10000" 调用stringToProxy 方法,注意这段字符串中包含了对象名和服务器端使用的端口号,(很明显,硬编码和直接定义端口号是个很糟糕的主意,但到目前为止我们还可以这么做,我们将在第39 章中看到更好的解决方案)

*. 通过stringToProxy 返回的代理是Ice::ObjectPrx 对象的引用,Ice::ObjectPrx 是个基类,其实我们返回的是它的一个子类对象的引用,为了调用打印机方法我们必须通过调用PrinterPrxHelper.checkedCast 来转换,这个类型检查装置将会发送一个消息到服务器端,会去询问服务器:这个代理是实现了Printer 接口的对象吗?如果是,将返回Demo::Printer 的代理,否则将会返回null

*. 如果真的为null 了,我们将会抛出异常并且终止客户端程序。

 

*. 至此我们可以调用pintStringg 方法打印自己想要打印的消息了。服务器端程序将会在终端打印“Hello World!” 字符串。

 

编译客户端程序和服务器端的依然很类似,这里我还是推荐使用一些编译工具编译:

$ javac -d classes -classpath classes:$ICEJ_HOME/lib/Ice.jar\

-source 1.4 Client.java PrinterI.java generated/Demo/*.java

 

 

运行服务器端:

 

$ java Server

 

我还是推荐使用工具运行,至此我么还不能看到什么,因为客户端还没调用呢。

 

接下来:

$java Client

 

 

客户端会运行并且会在不打印任何信息的情况下迅速退出,再服务器端的终端上,将会打印出"Hello World!" 。然后你就可以kill 掉我们的服务器端进程了。

 

 

如果你没能正确输出打印结果:则可能是出现了下面的异常:

 

这种情况是在你还没有运行server 的时候首先运行了client 端程序:

 

 

Ice.ConnectFailedException

at IceInternal.Network.doConnect(Network.java:201)

at IceInternal.TcpConnector.connect(TcpConnector.java:26)

at

IceInternal.OutgoingConnectionFactory.create(OutgoingConnectionFac

tory.java:80)

at Ice._ObjectDelM.setup(_ObjectDelM.java:251)

at Ice.ObjectPrxHelper.__getDelegate(ObjectPrxHelper.java:

642)

at Ice.ObjectPrxHelper.ice_isA(ObjectPrxHelper.java:41)

at Ice.ObjectPrxHelper.ice_isA(ObjectPrxHelper.java:30)

at Demo.PrinterPrxHelper.checkedCast(Unknown Source)

at Client.main(Unknown Source)


Caused by: java.net.ConnectException: Connection refused

at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method

)

at

sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:

518)

at IceInternal.Network.doConnect(Network.java:173)

... 8 more 
 

 

主意,要想正确的运行clientserver ,你必须已经正确的配置了ICE 的库路径,也就是环境变量,例如

 

$ export CLASSPATH=$CLASSPATH:./classes:$ICEJ_HOME/lib/Ice.jar

 

。。。看看和你的平台相关的ICEdemo 吧。。。。反正我的是linux

 

 

你可能感兴趣的:(java,应用服务器,linux,虚拟机,ant)