随笔:25 文章:1 评论:66 引用:0
BlogJava 首页 发新随笔
发新文章 联系 聚合管理

2006年3月9日

Sorry, I have already moved to JavaEye and Fanfou, please update if you have questions.
posted @ 2009-05-09 22:13 steeven 阅读(225) | 评论 (0)编辑 收藏
 
最近让新来的实习生写订餐机器人,羽毛球活动预定机器人,两个人写了几个星期,看得我心急火燎。现在的研究生啊。。。。

自己拿来skype4java看了一下,感觉很好用。里面提供了一个application机制,类似socket,又强于socket。为什么说强呢?因为是基于skype, 穿透防火墙啦。
windows自带的远程桌面很好用,在速度上,比以前基于位图传送的netmeeting/pcanywhere之类的都要强。
linux下面的远程桌面做的比较好的是nx系列。但是这些远程桌面的致命问题就是网关、防火墙问题。
就是说你要在家访问公司电脑,基本上要在防火墙上凿洞,或者借助于vpn,softether之类的东东。

skype的application利用skype自身的通讯机制,屏蔽了这些问题,当然,你的应用也必须依赖skype了。

java做远程桌面要能截屏、控制鼠标键盘,所幸有java.awt.Robot, 原来这个东西是为了做自动化测试,刚好。
剩下就是穿数据的问题。屏幕图片,如果是bmp,比较硕大,即使是上网等文本界面,压缩下来也要几十k, 如果网络带宽不够的话,比如公司有几个下载爱好者,会比较惨。所以呢,决定传差异,缓存前面的屏幕,看看如果差别不大,就只传变化的部分。这样数据量就比较小。但是呢,压缩图片的时候就不能采用有损压缩啦,否则屏幕会变得越来越怪异。。。

比较遗憾的是没能象windows自带的rdp那样拦截绘图操作,在点阵图的方案上效率还是比较低的。希望有高手指点!

skype4java是个日本人写的,几个听了我介绍的朋友都有这疑问:日本人写的?
呵呵,如果你能写出更好的,咱就不用它。那个日本作者还不错,上班比较忙,还是答应抽空fix几个bug,感谢中~

体验一下吧:skypeRDP
posted @ 2006-12-06 20:18 steeven 阅读(2597) | 评论 (6)编辑 收藏
 

适用版本GWT 1.0.21。
由于目前google web toolkit还没有正式release, 所以问题多多。记录一下碰到的问题:

1. Shell调试模式和实际编译结果有差异。
shell中报告的异常在运行中只是一些凌乱的脚本错误,或者干脆没有响应。
shell中通过的程序在实际运行时还会有错误。
2. 避免错误的方法是捕获异常,
在onModuleLoad方法中try catch
或者GWT.setUnCaughtExceptionHandler()//全局异常捕获
3. LOG, 利用GWT.log(). shell模式下会输出到控制台。
4. 远程调用属于异步。同步远程调用可以自己包装ClientCallback,在一个结束后调用另外一个.
5. RPC调用中Set传递有bug, 暂时用List
6. Eclipse直接运行Compiler/Shell, 加入gwt-dev-windows.jar。
main: com.google.gwt.dev.GWTCompiler/GWTShell
arguments: -out ${project_loc}\WebContent real/Index.html
classpath->UserEnties->advanced->add folder->选择项目的src目录,要在第一位。
7. Tomcat5问题多多, 用tomcat4.
8. gwt-user中非法包含javax.servlet, tomcat认为其无效。直接放到tomcat/common/lib中。或者在jar中去掉。
9. Exception.getStackTrace() 在Shell模式下有效, GWT.isScript()可以判断
10. 静态中文在html中乱码,要在html header中加入<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

posted @ 2006-07-14 18:10 steeven 阅读(2938) | 评论 (6)编辑 收藏
 
开发设计两个类:
鸡,构造的时候要带入蛋.
蛋,构造的时候要带入鸡.

编译没问题,初始化数据的时候问题出来了.
new 鸡(new 蛋(???)) //蛋是谁下的?
作为一个正统的进化论学生,解决如下:构造原始鸡类,鸡开始是不下蛋的,把鸡的构造函数改成空的,这时候初始化一条原始鸡的数据没问题.然后进化出来蛋,鸡下的,类不用改,把蛋的数据初始化好.这时候鸡进化,由蛋孵出来,构造方法要带蛋进来,初始化一只新鸡,删除原始鸡数据.

OK,问题解决了吗?这样程序每次初始化数据的时候要改造鸡类,好像不大容易啊....

那上帝造物学说怎样解决问题呢?:
鸡1 = new 鸡(null);
蛋1 = new 蛋(null);
鸡1.set蛋(蛋1);
蛋1.set鸡(鸡1);
save(鸡1,蛋1);
鸡和蛋同时出来了.上帝造物法胜利

是不是我的类设计有问题,怎么会碰到鸡生蛋蛋孵鸡这种郁闷的问题呢?
posted @ 2006-07-02 20:28 steeven 阅读(1447) | 评论 (2)编辑 收藏
 

db4o目前还没有unique index/primary key机制。(5.4)

     public   static   void  main(String[] args)  {
        ObjectContainer db 
=  Db4o.openFile( " test.yap " );
        db.set(
new  User( " abc " , 234 ));
        db.set(
new  User( " abc " , 234 ));
        ObjectSet
< User >  list  =  db.query(User. class );
        System.out.println(list);
        db.close(); 
// halt without this line in 5.2
    }

上面的例子会存储两个同样的User对象。
仅有的ID是一个存储文件中的ID, 经过碎片整理之后会发生变化,显然不适用。
要实现一个auto_increament的主键恐怕要自行实现。或者用已有的UUID实现。

可能db4o太年轻的关系,目前还没有支援这些功能。建议用@Annotation来实现。并且控制存储。
@ID
@Unique
@Index
在EJB3里面已经有现成的定义可以参考。
posted @ 2006-06-19 18:15 steeven 阅读(907) | 评论 (0)编辑 收藏
 
原来说是xaml只是随着下一个版本的windows放出,后来改编到winfx里面,最近听说作为.net3.0出现.这样的直接后果就是这个b/s+c/s通吃的UI框架不但要寄生在新版windows里面,也要被用来在xp上攻城略地.

微软这回蓄势待发xaml有多强大呢?3d(感觉不够纯粹)/强大的数据绑定/动画/多媒体支持...
这里可怕的不仅仅是框架,还有配套的GUI开发工具.有趣的是Interactive Designer据说就是用wpf开发的.
xaml只是个xml描述文件,里面可以包含代码,编译成UI界面.所有的界面内容也可以由程序动态运行.
这样未来运行在browser里面的UI不是复杂的ajax,是和后台一致的托管代码.

Java怎样应对呢?Java+Flash? 开发bs都困难重重.除非Flash能放弃as,直接同java结合,或者两个公司合作开发一个新框架.这个新框架应该是什么样子呢?完全的3D视角,时间轴控制...重演c#后来居上的历史.

Java在Sun的手里一直半死不活,真希望能赶快被google并购,或者sun主动把java捐赠出来.

如果没有"意外",在wpf正式发行以后,桌面应用将逐步过渡到wpf开发.HTML由于其跨平台,可能会平分秋色.

面对wpf,如何反抗?java.net是太监,在.net阵营里面连二奶都不算,等于投降.
利用xaml? xaml被编译加载,其执行框架还是.net,机会似乎不大.在浏览器上可能会有类似lasszlo的组合.

作为Java爱好者,祈祷奇迹发生吧,还好在Java世界中奇迹是家常便饭 :)
posted @ 2006-06-18 22:57 steeven 阅读(2444) | 评论 (3)编辑 收藏
 

一般Apply按钮应该在用户有输入时有效,输入没有变化时无效。
为了达到这个效果,一般界面上每个输入控件要监听,并且和以前的值做比较,实现起来相当麻烦。

因为我们已有的界面是基于数据绑定,绑定到一个克隆的对象上。这样判断有没有变化就很简单,updateInput之后,比较两个对象是否一致即可。

什么时候去判断呢?在用户输入之后:捕捉键盘、鼠标事件。

拦截键盘鼠标事件目前找到两种方法:
1. Toolkit.getDefaultToolkit().addAWTEventListener(listener,eventMask);
这个方法注册全局的监听机制,无论哪个窗口。里面注册为weakHashmap,应该不用考虑垃圾回收问题。因为是全局的,不建议采用。
2. 拦截每个component自己的事件。
正常来说,如果在textbox里面打字,事件不会交给window处理。enableInputMethods(true)可以帮忙。
enable以后调用getInputContext(),取得InputContext处理。
注意,InputContext的dispatchEvent(AWTEvent)会接到各种消息,感兴趣的getID()有以下三个:
   MouseEvent.MOUSE_CLICKED
   MouseEvent.MOUSE_WHEEL
   KeyEvent.KEY_TYPED

posted @ 2006-06-13 16:52 steeven 阅读(1618) | 评论 (2)编辑 收藏
 
上海这方面活动比较少,难得逮到一个,跑去凑个热闹。天不作美,下班前一场大雨,让参加的人少了很多。

零星记了一些笔记,对我这个ajax门外汉来说收获还是很大。主讲是ajaxcn.org的两位高手。robbin的Rubby讲座因为时间关系要改期。

1. JS2的一些新特性:class/extend/interface/package/import/块作用域/操作符函数. 明年底会有browser开始支持。
//干脆把java直接搬到browser里面算了。
//以后是不是弄个标准接口允许加载不同语言的脚本引擎?大家就不用受js的鸟气了。
2. 推荐的ajax框架:Dojo/DWR/Prototype/GWT/YUI
//排名有先后
3. 新技术:
canvas 画图,已有多数浏览器支持。据说有人用它实现了3D游戏
SVG 基于xml的矢量图。据说和canvas都支持3d绘图。
E4X: xml的包装, firefox支持
4. 技术和需求水涨船高 //我们不会失业了
5. HiJax:
用传统方式快速开发。在传统网页基础上hack成ajax应用。
对禁用js的浏览器表现为传统网页。
前期开发和后期改造独立性很强。
//后期要改造为完美的ajax,对server端要做些小的改动来适应。
6. 推荐用FireFox调试AJAX, 插件三剑客:
firebug/web develope tool/temper data分别用来调试脚本,观察页面dom,监听通信。
//js调试的日子好过多了,但不要忘记总体效率。。。

回来路上和一位tx聊起来ajax在企业中的地位好像不高,他对敏捷开发很有好感,对办公室环境的要求很有趣。
本次活动的主要心得是:自助餐很好吃,以后有活动还要去吃 :)
posted @ 2006-06-07 23:44 steeven 阅读(1315) | 评论 (4)编辑 收藏
 
gwt的这些特性还是很有意思的,感觉比echo更贴近html, 比如说尺寸等数据,写"20%"和"200px"都可以。echo则尽量封装的象swing, 屏蔽掉html.

anyway, 对于大多数逻辑都在客户端的应用,gwt可以大展身手。比如小游戏~

guess number demo看这里:http://steeven.googlepages.com/MyApp.html
完全在浏览器上运行的玩意,没有写一句js,感觉还是很爽的~

代码如下:
package org.steeven.gwt.test.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * 
@author steeven@gmail.com
 
*/

public class MyApp implements EntryPoint {

    TextBox txtCount 
= new TextBox();

    
private Grid pnlMain;

    
private Button[] numbers = new Button[100];

    
private int target;

    
private int count;

    
private DialogBox box;

    
private Button btnRetry;

    
private Button btnClose;

    
/**
     * This is the entry point method.
     
*/

    
public void onModuleLoad() {
        VerticalPanel pnlStatus 
= new VerticalPanel();
        pnlStatus.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
        pnlStatus.setSpacing(
20);

        txtCount.setEnabled(
false);
        txtCount.setVisibleLength(
10);
        pnlStatus.add(txtCount);
        btnRetry 
= new Button();
        btnRetry.setHTML(
"<img src=\"replay.gif\"/> <u>R</u>etry");
        btnRetry.setAccessKey(
'r');
        btnRetry.addClickListener(
new ClickListener() {
            
public void onClick(Widget sender) {
                doInit();
            }

        }
);
        pnlStatus.add(btnRetry);

        Button btnAbout 
= new Button();
        btnAbout.setHTML(
"<img src='about.gif'/> <u>A</u>bout");
        btnAbout.setAccessKey(
'a');
        btnAbout.addClickListener(
new ClickListener() {
            
public void onClick(Widget sender) {
                doAbout();
            }

        }
);
        pnlStatus.add(btnAbout);

        RootPanel.get(
"status").add(pnlStatus);

        pnlMain 
= new Grid(1010);
        RootPanel.get(
"main").add(pnlMain);

        
for (int i = 0; i < 100; i++{
            numbers[i] 
= new Button();
            numbers[i].setText(i 
+ "");
            numbers[i].addClickListener(
new ClickListener() {
                
public void onClick(Widget sender) {
                    doGuess(sender);
                }

            }
);
            pnlMain.setWidget(i 
/ 10, i % 10, numbers[i]);
        }


        box 
= new DialogBox();
        box.setPopupPosition(
400200);
        btnClose 
= new Button("<u>C</u>lose"new ClickListener() {
            
public void onClick(Widget sender) {
                box.hide();
                doInit();
            }

        }
);
        btnClose.setAccessKey(
'c');
        box.add(btnClose);
        doInit();
    }


    
protected void doGuess(Widget sender) {
        Button btn 
= (Button) sender;
        btnRetry.setEnabled(
true);
        
int n = Integer.parseInt(btn.getText());
        txtCount.setText(
"" + (++count));
        
if (n == target) {
            numbers[n].setEnabled(
false);
            btnClose.setFocus(
true);
            box.clear();
            box
                    .setHTML(
"<center><img src='win.gif'/><h1>YOU WIN!!!</h1><br/><br/><br/>");
            box.add(btnClose);
            box.show();
        }
 else {
            
if (n < target)
                
for (int i = 0; i <= n; i++)
                    numbers[i].setEnabled(
false);
            
else
                
for (int i = n; i < 100; i++)
                    numbers[i].setEnabled(
false);
        }


    }


    
protected void doAbout() {
        box.clear();
        box
                .setHTML(
"<img src='about.gif'/><h1>Guess Number</h1><h3>Google web toolkit test</h3>");
        box.add(btnClose);
        box.show();
    }


    
private void doInit() {
        btnRetry.setEnabled(
false);
        target 
= Random.nextInt(99);
        count 
= 0;
        txtCount.setText(
"0");
        
for (int i = 0; i < 100; i++{
            numbers[i].setVisible(
true);
            numbers[i].setEnabled(
true);
        }

    }


}


第一次玩gwt, 总共花了3个小时,菜呀
posted @ 2006-06-02 15:23 steeven 阅读(1836) | 评论 (13)编辑 收藏
 

前面转贴Liebeck(echo的主要开发者,我的偶像)关于echo2和gwt的对比:http://www.blogjava.net/steeven/archive/2006/06/01/49379.html

今天仔细做了一些笔记,并且加入了一些自己的想法,供选型者参考:

综合对比:
1. 两个都是非传统的b/s框架,都是用AJAX来构造动态网站。编程过程都和SWT/Swing差不多。
2. 区别在于一个运行于客户端,一个运行于服务器

3. gwt把代码编译为html+js, 目前只支持java1.4规范。echo没这限制。
4. gwt可以运行于任何web server, echo则需要传统的servlet容器。(意义不大,现在哪有静态网站啊,后台交互肯定还是需要的)
5. echo2的客户端引擎通过ajax提交用户动作,对用户界面增量更新。
 
性能:
1. gwt的页面logic都在浏览器上,所以很快。但是如果需要和中间层交互,就会碰到同样的网络问题。
2. echo2的代码跑在server上,所以所有的交互都需要反馈给server。echo2在设计上尽量减少这种交互,比如客户对文本的修改都是延迟发送到服务器,而服务器只发送页面的变化部分到浏览器。
3. gwt应用被编译成一个页面,虽然应用的复杂化,这个编译结果也随之变得可怕。。。(个人认为随着编译器的发展,不同的页面可以做到lazy load)
4. echo的js模块是lazy加载到浏览器的,界面上呈现哪些控件才去加载并且缓存对应的js模块。发送到客户端的不是逻辑代码,只有用户状态(个人认为echo2现在过于lazy,导致初始化阶段多次访问server加载一些基本的js模块,应该揉合到一起。另外,因为echo逻辑代码在服务器上,相对来说可以防止盗版)
 
中间层和数据访问:
1. 如果要访问数据,gwt还是要回到传统的模式,通过rpc访问servlet。gwt提供把远程服务透明的包装起来,中间传送pojo. 尽管包装了,中间的安全和和校验还是必须要开发者考虑。
2. echo支持SOA,但是不必须。大多数情况下安全不是问题,因为数据和逻辑都不会暴露到浏览器上。(以前给echo提过建议,浏览器用户很可能去模拟一个被disabled按钮提交,这种问题现在无需考虑)
 
运行环境:
1. gwt运行在浏览器上,并非所有的java类都能编译成js. gwt现在只支持java.lang/java.util下面的一个子集(版本 1.0.21):27 classes, 11 interfaces, and 18 exception(这让人想起了j2me开发). 一些现有的类库就别想了。
 
调试:
1. gwt调试需要一套和运行时完全不同的环境:HOST模式,代码作为真正的java在运行。(个人认为这里因为是纯java调试,比echo的web调试要稍微方便一些。做单元测试也更方便些,但不是对最终browser的测试)
2. echo调试就是传统的servlet调试。
 
授权:
1. gwt的api是开源的,编译器和host模式浏览器不公开。整体来说:free. (个人认为,如果要扩充gwt可能会遇到麻烦)
2. echo2开源,mozilla public license. free(个人认为:echostudio也free就好了。nextapp毕竟要生存)
 
应用:
1. gwt可以嵌入传统的静态html, 也能作为一个完整应用。做大应用要考虑编译后的重量、本地化、库支持等问题(关于18n, 可以在gwt支持论坛上搜索i18n,似乎已经有方案)
2. echo2成熟得可以适用各种应用,但是不能作为静态页面的一部分使用。(有点吹牛,在大访问量下,服务器的压力肯定不会小)
 
 
 
个人结论:
1. 开发方式都很优秀,用纯java开发b/s
2. gwt可用于大型网站,把压力转嫁给客户端。
3. echo可用于快速开发复杂的企业应用,把压力丢给服务器(企业里面最清闲的就是前台和服务器)

两个产品都很优秀,GWT是2006年的IT飓风,波及后面几年。M$的日子要难过了, GOOGLE的确是个令人头痛的对手。

然而,还有比gwt/echo2更美好的未来吗?
有!把他们的输出变成flash,用java开发flash应用。去年探索过一段时间,原型已经出来,因为flash开发调试太ugly, 没有继续下去。
另外,微软的WPF(AVALON)相当值得关注。
posted @ 2006-06-01 11:32 steeven 阅读(1928) | 评论 (3)编辑 收藏
 

Google Web Toolkit 虽然还是beta版本,和google的其他产品一样,刚出生就注定不凡,也许将影响后面几年的b/s开发。

gwt利用了java开发的一切成熟条件,包括Unit test, refactor, IDE(eclipse...),传统的b/s framework必将受到重创,横扫过后,JSF/ECHO等Server side framework可能幸存。如果哪天google加上serverside支持(从包命名上看是留有余地的)。。。虽然gwt目前还是小样一个,但是背后站的是重量级的google,强大的资源和数不完的银子。。。。

看到这玩意首先想到的是echo2, 客户端技术都是ajax, 编码都是java. 不同的是gwt发行时编译成HTML+JS,Echo2则是完全的服务器端生成+更新。gwt跟server端交互依靠类似于ws的service把前后台完全区分开。

在echo的论坛里面已经有人在讨论这玩意了,并且八卦了一下gwt的前身似乎是Morfik的一部分(待证实)
从原理上,echo的开发者作出了对比,这个网站似乎被封锁,这里转贴一下:


===============================
http://echotwo.blogspot.com/ 作者tod liebeck

Comparing the Google Web Toolkit to Echo2
The Google Web Toolkit (GWT) is being compared to Echo2 quite frequently. Some of these comparisons have been fairly accurate, while others contain bits of misinformation. This article, written by the lead developer of Echo2, discusses the similarities and differences between these two frameworks.

Overview

The Google Web Toolkit and Echo2 definitely make for an interesting comparison. Both of these frameworks take a non-traditional approach toward web application development, even considering the latest crop of "AJAX-based frameworks" available today.

The most obvious similarity between GWT and Echo2 is that they both enable the developer to create dynamic, AJAX-driven web user interfaces using only Java. In both projects, UIs are developed in a fashion similar to SWT or Swing: by assembling hierarchies of components and registering event handlers. Neither project requires the developer to work with HTML, JavaScript, or XML.

The most obvious difference between GWT and Echo2 is that all of your GWT code is executed on the client, whereas your Echo2 code is executed on the server. There are advantages and disadvantages to both of these approaches, which will be highlighted throughout the article.

GWT's defining attribute is the Java-to-JavaScript compiler. This compiler allows you to develop the web interface to your application in Java, then compile it to JavaScript. GWT limits the developer to a subset of the Java 1.4 libraries. GWT applications can be served by any web server, such as Apache, without the need for server-side processing.

Echo2 applications are compiled to Java byte code and run on a Java server. Their Java code is executed by Echo2's "Web Application Container" layer, which sits atop a Java Servlet. On the web browser, the Echo2 "Client Engine" communicates user input to the Web Application Container via AJAX requests, with the server responding with directives to perform incremental updates to the state of the client web browser.

User Interface Performance

With GWT, all of your user interface code exists on the client browser. In operations that do not require server communication--that is, that do not require retrieving data from the middle tier--this configuration results in response times that are not dependent on the server. When data must be retrieved from the application's middle tier or business logic layer, the response time is subject to the same criteria as any other AJAX application, i.e., network latency, bandwidth, and server performance.

Echo2 application code is run on the server, so for each user interaction that requires a call to the middle tier or immediate execution of the application's Java code, an AJAX connection is made to the server. Echo2 components are designed to minimize the client/server communication as much as is possible, limiting it to times when the server must be notified immediately of events. For example, simple events such as user input to a TextField component will not result in server contact. The server's response is the minimum set of instructions to incrementally update the client to reflect the new screen state.

GWT applications are served to the client as a single HTML/JavaScript file, containing the entirety of the user interface. The size of this file will be proportional to the size of your user interface code and the toolkit libraries used by your application.

Echo2 JavaScript modules are lazy-loaded to the client, and thereafter cached. A module will be retrieved when a component first appears on-screen that requires it. Application code is never sent to the client, only the state of the user interface.

Middle Tier / Data Retrieval

To access business data or perform a business process, a GWT user interface makes a remote procedure call (RPC) from the browser to a Servlet. GWT provides a mechanism to make the RPC invocation transparent to the developer, allowing the developer to build the application with "Plain Old Java Objects" (POJOs). However, any application that provides an RPC capability is a distributed application -- even when the RPC is accomplished transparently to the developer. Distributed applications in businesses and enterprises usually have security considerations and the remote objects serving the GWT clients must be designed with a focus on security to deflect attacks from imitated or hostile client applications.

Echo2 applications support, but do not require, the use of distributed application logic or a Service Oriented Architecture (SOA). Alternatively, Echo2 applications can be built to run entirely within a single JVM instance, backed by a POJO-based middle tier. This allows Echo2 developers to build applications without the security concerns of distributed application logic -- and leverage the many strong frameworks built around POJO development such as the Spring Framework and Hibernate. Echo2 accomplishes this by keeping the state of a user's web interface on the server so that no remote objects need to be exposed.

Run-time Environment

GWT has some limitations due to the fact that applications are run on the client browser. First, GWT applications are limited to using a subset of the core Java class libraries, consisting of 27 classes, 11 interfaces, and 18 exception types found in the java.util and java.lang packages (as of GWT 1.0.21). This limitation prevents GWT applications from linking to most existing Java libraries. Additionally, all Java code must be compliant with the Java 1.4 specification; 1.5 is not supported. Localization-related portions of the Java API are not provided.

Debugging

GWT provides an alternate deployment environment for applications to facilitate debugging. The environment, called "Hosted Mode", allows a GWT application to be run as Java byte code in a local JVM, to which an IDE's debugger can be connected. In this mode, the application's user interface is displayed in a special web browser (a Mozilla/Firefox derivative).

Echo2 applications may be debugged in the conventional manner, by connecting an IDE's debugger to a JVM running a Servlet container.

Licensing

The primary component of GWT, the Java-to-JavaScript cross-compiler, is proprietary, binary-only software. The Java API libraries are open source software, distributed under the Apache License. The API libraries have essentially no value without the proprietary compiler. The (non-critical) hosted-mode browser is also under the proprietary license. GWT is provided free of charge.

Echo2 is open source software, licensed under the Mozilla Public License, and provided free of charge.

Applicability

GWT can be used as a means of creating AJAX components to embed in traditional web applications (or even in static web pages) as well as for creating complete application user interfaces. There are some issues to using it for the creation of large applications, where downloading an entire application to a client web browser in one shot would not be practical. The lack of localization and full Java API support also presents a problem for larger solutions.

Echo2 is practical for creating web applications of any size. It is however not intended to scale downward to function as a platform for simply creating AJAX components in traditional web frameworks (or static web sites).

More Information

Google Web Toolkit:
Home Page, Example Applications, Getting Started Guide, Developer Guide

Echo2:
Home Page, Example Applications, Tutorial
posted by Tod Liebeck at 5:13 AM | 0 comments  

======================================
毕竟gwt还是小baby, 以后怎么发展还难说,现在下结论太早。这两天试用一下,有空从细节上对比一下。

posted @ 2006-06-01 00:55 steeven 阅读(593) | 评论 (0)编辑 收藏
 

测试一下getResource(URI,boolean):

        System.out.println(EcorePackage.eINSTANCE.eResource());  // 1
        System.out.println(XMLTypePackage.eINSTANCE.eResource());  // 2

        ResourceSet rs 
=   new  ResourceSetImpl();
        rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
                Resource.Factory.Registry.DEFAULT_EXTENSION,
                
new  XMIResourceFactoryImpl());
        String uri 
=   " http://abc.eg/asdf " ;
//         System.out.println(rs.createResource(URI.createURI(uri)));  //  如果创建过临时的,得到这个
//         System.out.println(rs.createResource(URI.createURI(uri)));  //  如果创建过多个临时的,返回第一个,这个忽略
        rs.getPackageRegistry().put(uri, EcorePackage.eINSTANCE);  // 得到结果同1,如果上面取消注释,本地创建的优先

        System.out.println(rs.getResource(URI.createURI(uri), 
false ));  // 同1


createResource每次创建新的,getResource则是唯一实例的。

每个生成的XxxPackage.eINSTANCE会自行创建自己的Resource。如果在插件中修改了EcorePackge.eInstance.eResource(),会不会天下大乱呢?

==================
eclispe编辑器右边的Mark Occurrence很方便,但是家里电脑上的这个黄色小标记很不清楚。前几天调整了老半天,修改配色方案,换显示器驱动,调整显示器对比度、亮度都收效不大。昨天偶然把XP的桌面风格换回传统模式,搞定了。

ecore.ecore这个问题很有意思,以前看过schema.xsd,就是自己定义自己。据说JDK也是用java开发编译出来的。。。
先有鸡还是现有蛋呢?

posted @ 2006-05-26 10:22 steeven 阅读(1009) | 评论 (1)编辑 收藏
 

在RS中同一URI可以createResource多个Resource,List方式存放。还存在另外一种Map存放方式, getResource(URI,boolean loadOnDemand)就是通过这种方式存取,如果不存在的话创建。这两个方法看起来有些冲突。似乎用于不同场合。

再来看看怎样通过URL存取EObject:
RS整个相当于一个DataBase, Resource相当于表,存放的是EObject, 每个EObject可以看成对象或者XML。
表用URI来区分,URI中的Segment用来定位EObject。URI的例子参见探索(1)
getEObject(URL, boolean loadOnDemand)很简单,getResource找到对应的Resource,在里面根据Segment查找,就是那个#///@xxx.n格式的东西,注意,还有ID方式。

getPackageRegistry()用来返回RS的URL->Package注册表,它也是个本地的注册表,代理了全局的EPackage.Registry.INSTANCE。这个注册表用于取得EPackage(类型信息)和EFactory(创建实例)


Resource就不说了,主要load,save, 一些具体子类,比如XmlResourceImpl可以直接使用,指定Encoding之类。

看看ResourceSet对EMF了解了很多~

posted @ 2006-05-26 01:23 steeven 阅读(1084) | 评论 (0)编辑 收藏
 
来看看ResourceSet.createResource(URI):Resource方法,从URI到Resource的过程如下:
1. getResourceFactoryRegistry()
  public Resource.Factory.Registry getResourceFactoryRegistry()
  
{
    
if (resourceFactoryRegistry == null)
    
{//可以自行Set一个注册表实现,没有的话用系统缺省注册表
      resourceFactoryRegistry =
        
new ResourceFactoryRegistryImpl()
        
{
          
public Resource.Factory delegatedGetFactory(URI uri)
          
{
            
return Resource.Factory.Registry.INSTANCE.getFactory(uri);
          }

        }
//代理系统注册表,注意这个应该是正宗的。
    }

    
return resourceFactoryRegistry;
  }

所以自己new 出来的ResourceSet可以向注册表中任意添加工厂实现。
2. 调用注册表的getFactory(URI), 实现如下:
 public Resource.Factory getFactory(URI uri)
  
{
    String protocol 
= uri.scheme();
    Object resourceFactory 
=  protocolToFactoryMap.get(protocol); //先根据protocol查找
    if (resourceFactory == null)
    
{
      String extension 
= uri.fileExtension();
      resourceFactory 
= extensionToFactoryMap.get(extension); //找不到再根据扩展名查找
      if (resourceFactory == null)
      
{
        resourceFactory 
= extensionToFactoryMap.get("*"); //尝试查找缺省扩展
        if (resourceFactory == null)
        
{
          resourceFactory 
= delegatedGetFactory(uri); //自行实现可以扩展此方法解析。
        }

      }

    }


    
//Descriptor可以用于编程使用
    return 
      resourceFactory 
instanceof Resource.Factory.Descriptor ?
        ((Resource.Factory.Descriptor)resourceFactory).createFactory() :
        (Resource.Factory)resourceFactory;
  }

查找一个工厂居然这么复杂!正因为这么复杂,才能支持platform/file/fttp等众多千奇百怪的URI
不同类型的工厂加工出不同类型的Resource, 才会输出为XSD/XML/XMI/....

如果直接操作系统注册表要小心。EMF中定义了几个扩展点,可以实现类似目的。
已知的ResourceFactory实现有:XSD/ECore/EMOF/XML/XMI,XSD的输出方法的介绍可以参考Eclipse Development using the Graphical Editing Framework and the Eclipse Modeling Framework电子书。



posted @ 2006-05-26 00:02 steeven 阅读(1119) | 评论 (0)编辑 收藏
 
这个东西比较有趣,代码还要区分是否在Eclipse环境下运行。
先看看现象,以EMF例子Library.ecore为例, 测试代码如下:
public class Test {
    
public static void main(String[] args) throws IOException {
        ResourceSet rs 
= new ResourceSetImpl();
        rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
                Resource.Factory.Registry.DEFAULT_EXTENSION,
                
new XMIResourceFactoryImpl()); //outside eclipse
        Resource resource 
= rs.createResource(URI
                .createURI(EXTLibraryPackage.eNS_URI));
        
//step a
        Library library = EXTLibraryFactory.eINSTANCE.createLibrary();
        library.setName(
"some lib");
        resource.getContents().add(library);
        
//step b
//        Book book = EXTLibraryFactory.eINSTANCE.createBook();
//        book.setTitle("some book");
//        Employee employee = EXTLibraryFactory.eINSTANCE.createEmployee();
//        employee.setFirstName("some one");
        
//step c
//        library.getBooks().add(book);
//        library.getEmployees().add(employee);
        
//step d
//        resource.getContents().add(book);
    
//        System.out.println(EcoreUtil.getURI(employee));
//        System.out.println(EcoreUtil.getURI(book));
        resource.save(System.out, null);
    }

}


步骤 输出
a ----------------
<?xml version="1.0" encoding="ASCII"?>
<extlib:Library xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0" name="some lib"/>
#//
#//
<?xml version="1.0" encoding="ASCII"?>
<extlib:Library xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0" name="some lib"/>
c http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0#//@employees.0
#//
<?xml version="1.0" encoding="ASCII"?>
<extlib:Library xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0" name="some lib">
  <employees firstName="some one"/>
</extlib:Library>
d http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0#/0/@employees.0
http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0#/1
<?xml version="1.0" encoding="ASCII"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0">
  <extlib:Library name="some lib">
    <employees firstName="some one"/>
  </extlib:Library>
  <extlib:Book title="some book"/>
</xmi:XMI>

可以看到,没有加入lib的时候,employee/book实例的URI都是#//, employee加入以后有了#//@employees.0, book依旧。
在book加入resource以后有了#/1的URI, employee/book在containment定义分别是true,false,所以employee加入lib以后就随lib加入resource(实例容器)。book则要单独加入。

另外一个有趣的现象是Resource可以容纳多个实例,在step d可以看到输出的根节点由lib变成匿名容器。

如果lib不加入resource又如何呢?
步骤 输出
a ----------------
#//
#//
c #///@employees.0
#//
d ----------------
没加入resource之前,URI是未知的,知道的只是相对父节点的相对segment.

posted @ 2006-05-25 22:40 steeven 阅读(1186) | 评论 (1)编辑 收藏
 
Eclipse的Ecore编辑工具里面Annotation完全要手写,比如写ExtendedMetaData就很费劲。
手写指定Source,指定每个Key/Value很容易出错。
这个插件通过向导选择source, 通过PropertySheet编写Key/Value。并且根据Ecore的定义实现校验。

Step1:


Step 2:
AllDataTypes组合了该URL下面所有的EDataType


Step3: 编辑属性。注意source的变化:
如果选择的AllDataTypes,就是Ecore的URI
如果选择某个EClass, 后面会加上#EClassName


Step4: 如果选择AllDataTypes,自动选择所有EdataTypes。


Step5: 工作结果



请注意Source的生成规则!

适用版本:eclipse3.2rc3
下载地址: http://www.blogjava.net/Files/steeven/org.steeven.eclipse.emf.annotation.wizard.zip (含源码)
posted @ 2006-05-24 20:14 steeven 阅读(1219) | 评论 (3)编辑 收藏
 
EMF验证方面的文档很少, 日他娘的微软拼音,真讨厌啊。
因为比较少,所以这里总结一下。

验证的定义有两种方式:
1. 生成验证方法框架,代码自己实现。参见EMF Overview:
  添加Annotatio, Source=http://www.eclipse.org/emf/2002/Ecore, 然后添加DetailsEntry:key=constraints, Value=validateXxx
  EDataType,EClass支持,属性不支持。
2. 定义类似Schema的Facet,自动生成对应的验证代码,用于验证简单数据类型:
  添加Annotatio, Source=http:///org/eclipse/emf/ecore/util/ExtendedMetaData, 然后添加DetailsEntry:key=maxLength, Value=2
  支持的facet参见ExtendedMetaData。
  仅EDataType支持,属性不支持。

示例Ecore:

新生成SqlmodelValidator.java, 代码如下:

可见Table_ValidateC, MyLabel_ValidateA,MyLabel_validateB都自动生成,修改里面的if(false)为需要的业务判断逻辑。
validateMyLabel_MaxLength()方法是根据ExtendedMetaData自动生成的,无需修改。

总结:
1. EMF验证利用了Annotation扩展,这种机制很灵活,但是给用户带来不便。
2. Attribute属性不能生成验证规则(eclipse3.2rc3),可以定义为单独的EDataType,然后引用之。
3. Constraints+Facet+本身的结构验证可以构成很强的验证规则,并且属于Model层,数据本身即可验证自身。
4. EObjectValidator.DynamicEDataTypeValidator似乎可用于动态验证,有知道用法的朋友给讲解一下~

posted @ 2006-05-19 19:03 steeven 阅读(1131) | 评论 (0)编辑 收藏
 
SDO,简单理解就是EMF的脱机版。类似于resultSet和DataSet。可用于smartclient等脱机数据加工场合。
主要特点:(个人理解)
可验证
强类型
可取出完整数据和差异。

生成SDO代码和EMF大同小异,主要是在my.genmodel的第一个节点的右键菜单中选择:Set SDO defaults.

体验:
1. 生成Editor后,执行生成的Editor Plugin
2. 新建Example EMF Model Creation Wizards->Data Graph Model
3. 在Changes节点上Start Loggin, 然后编辑数据即可看到自动生成的差异。

网上手工操作SDO的示例代码比较少,这里简单demo如下:
import java.util.Iterator;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.sdo.EDataGraph;
import org.eclipse.emf.ecore.sdo.SDOFactory;
import org.steeven.family.FamilyFactory;
import org.steeven.family.个人;
import org.steeven.family.家庭;

import commonj.sdo.ChangeSummary;
import commonj.sdo.DataGraph;
import commonj.sdo.DataObject;

public class Server {

    
public static void main(String[] args) {
        
// client side
        EDataGraph graph = loadGraph();
        graph.getChangeSummary().beginLogging(); // important!
        家庭 family 
= (家庭) graph.getRootObject();
        family.setTitle(
"my family");
        个人 baby 
= FamilyFactory.INSTANCE.create个人();
        baby.set姓名(
"sophie");
        family.get兔崽子().add(baby);
        graph.getChangeSummary().endLogging();
        saveGraph(graph);
        update(graph);
    }


    
//server side
    public static EDataGraph loadGraph() {
        家庭 family 
= FamilyFactory.INSTANCE.create家庭(); // or load from
        
// database
        EDataGraph graph = SDOFactory.eINSTANCE.createEDataGraph();
        graph.setERootObject((EObject) family);
        
return graph;
    }


    
//server side full save
    public static void saveGraph(EDataGraph graph) {
        System.out.println(graph.getRootObject());
    }


    
//server side update changed objects
    public static void update(DataGraph dataGraph) {
        ChangeSummary changeSummary 
= dataGraph.getChangeSummary();
        
for (Iterator it = changeSummary.getChangedDataObjects().iterator(); it
                .hasNext();) 
{
            DataObject changedObject 
= (DataObject) it.next();
            System.out.println(
"Update for " + changedObject);
            
for (Iterator settingIt = changeSummary.getOldValues(changedObject)
                    .iterator(); settingIt.hasNext();) 
{
                ChangeSummary.Setting changeSetting 
= (ChangeSummary.Setting) settingIt
                        .next();
                System.out.println(
" (changed "
                        
+ changeSetting.getProperty().getName() + " from \""
                        + changeSetting.getValue() + "\" to \""
                        
+ changedObject.get(changeSetting.getProperty())
                        
+ "\")");
            }

        }

    }

}

输出:
org.steeven.family.impl.家庭Impl@9664a1 (title: my family)
Update for org.steeven.family.impl.个人Impl@1729854 (姓名: sophie, 性别: 男)
Update for org.steeven.family.impl.家庭Impl@9664a1 (title: my family)
 (changed title from "null" to "my family")
 (changed 兔崽子 from "[]" to "[org.steeven.family.impl.个人Impl@1729854 (姓名: sophie, 性别: 男)]")

SDO生成的代码似乎更加纯净一点,没有很多的eXxxx()方法(有需要的也可以取到)。
据说log的开销比较大,不建议对大量数据使用。
posted @ 2006-05-15 19:00 steeven 阅读(1800) | 评论 (5)编辑 收藏
 

看到eclipse3.2里面的GMF, 觉得比较有趣,底层还是用到了EMF. 花了两天时间仔细研究了以下EMF,的确是个好东西.

EMF根据ecore建模(可以和schema的xsd相互转换)生成强类型的EMF代码. 这个强类型更强的地方是可以取得meta信息,从而可以用于校验和界面辅助信息的生成.类似于动态bean,属性也可以根据名称动态取得.

以前考虑过用xsd描述界面, 但是数据载体只能是xml, 即使利用apache的schema编译工具生成强类型的类,后台代码也是xml. 不利于持久化. emf在代码生成引擎比较智能,可以标记出用户代码和自动生成代码.不会有生成覆盖问题.

这里做个简单示例:
1. Ecore:
可以新建Ecore, 建立好以后用GMF可视化编辑(Eclipse3.2RC2)

2. 生成Model:
点击my.ecore文件,菜单:File->New->Other->Eclipse Modeling Framework->EMF Model
3. 打开生成的my.genmodel, 选择树顶点的:Generate Model Code
生成的代码里面会有一个编译错误. 是中文编程的问题, 中文没有大小写(先天不足啊),结果性别这个成员变量和性别类名混淆,出错.在错误代码前面加上包全名即可.
4. 利用生成的代码构建一个家庭,输出xml并且校验之:

import  java.io.IOException;
import  java.util.Iterator;

import  org.eclipse.emf.common.util.Diagnostic;
import  org.eclipse.emf.common.util.URI;
import  org.eclipse.emf.ecore.EObject;
import  org.eclipse.emf.ecore.resource.Resource;
import  org.eclipse.emf.ecore.util.Diagnostician;
import  org.eclipse.emf.ecore.xmi.XMLResource;
import  org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import  org.steeven.family.FamilyFactory;
import  org.steeven.family.人物;
import  org.steeven.family.家庭;
import  org.steeven.family.性别;

public   class  TestMy  {

    
public   static   void  main(String[] args)  throws  IOException  {
        testFamily();
    }


    
private   static   void  testFamily()  throws  IOException  {
        家庭 family 
=  FamilyFactory.eINSTANCE.create家庭();
        family.setTitle(
" steeven家 " );
        family.set老公(FamilyFactory.eINSTANCE.create人物());
        family.get老公().set姓名(
" steeven " );
        family.set老婆(FamilyFactory.eINSTANCE.create人物());
        family.get老婆().set姓名(
" stella " );
        family.get老婆().set性别(性别.女_LITERAL);
        人物 sophie 
=  FamilyFactory.eINSTANCE.create人物();
        sophie.set姓名(
" sophie " );
        sophie.set性别(性别.女_LITERAL);
        family.get兔崽子().add(sophie);
        dump(family);
        validate(family);
    }


    
private   static   void  validate(EObject family)  {
        Diagnostic diagnostic 
=  Diagnostician.INSTANCE.validate(family);
        System.out.println(diagnostic);
        
for  (Iterator it  =  diagnostic.getChildren().iterator(); it.hasNext();)  {
            Diagnostic diag 
=  (Diagnostic) it.next();
            System.out.println(diag.getMessage());
        }

    }


    
private   static  Resource dump(EObject objs)  throws  IOException  {
        
//  ResourceSet rs = new ResourceSetImpl();
        
//  rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
        
//  Resource.Factory.Registry.DEFAULT_EXTENSION,
        
//  new XMIResourceFactoryImpl());
        
//  Resource resource = rs.createResource(URI
        
//  .createFileURI("c:\\temp\\test.xml"));
        XMLResource resource  =   new  XMLResourceImpl(URI
                .createFileURI(
" c:\\temp\\test.xml " ));
        resource.setEncoding(
" GBK " );
        
for  (EObject obj : objs)
            resource.getContents().add(obj); 
//  目前版本不加入resource验证会报singling异常
        resource.save(System.out,  null );
        
return  resource;
    }

}

运行结果如下:

<? xml version="1.0" encoding="GBK" ?>
< family: 家庭 xmlns:family ="http://org.steeven/family"  title ="steeven家"  老公 ="/"  老婆 ="/"  兔崽子 ="/" />
Diagnostic ERROR 
The feature '老公' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@6eb38a{#//}'
The feature '老婆' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@1cd2e5f{#//}'
The feature '兔崽子' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@19f953d{#//}'

可见输出的xml中没有包含人物的具体信息. 修改my.ecore中老公/老婆/兔崽子属性的containment属性为true,重新生成代码后运行结果如下:
<?xml version="1.0" encoding="GBK"?>
<family:家庭 xmlns:family="http://org.steeven/family" title="steeven家">
  
<老公 姓名="steeven"/>
  
<老婆 性别="女" 姓名="stella"/>
  
<兔崽子 性别="女" 姓名="sophie"/>
</family:家庭>
Diagnostic OK


====================
EMF单独运行成功~

这里ECORE似乎不支持嵌套定义,不像schema那样一个complexType声明里面可以定义的很复杂, 也不像Java的内部类. 似乎被作了简化, 更像关系数据库表之间的关系.

待求证问题:
1. EMF的校验信息是否支持国际化.
2. EMF数据的能否更方便的保存到数据.

EMF的灵活和强大已经验证过, 用于C/S还是B/S应该都不是问题.
posted @ 2006-05-14 21:27 steeven 阅读(2037) | 评论 (3)编辑 收藏
 
最近照葫芦画瓢,写了一个manifest的可视化编辑和自动更新工具。

主要想法是运行程序一句话搞定: java -jar xxx.jar。所有class path在jar里面的manfiest.mf中设定。
当需要引用的jar很多的时候,windows2000有命令行的长度限制,会报错。

主要功能:
1. new wizard
2. gui editor
3. switch auto-update in project menu

Class-Path in auto-updated manifest.mf file will be auto updated
while increase & full building.

下载:http://www.blogjava.net/Files/steeven/org.steeven.eclipse.manifest_1.0.zip

安装:eclipse菜单[help]-> Software Updates-> Find and Install ->    Search for new features to install ->   new archieved site
posted @ 2006-04-07 16:24 steeven 阅读(957) | 评论 (2)编辑 收藏
 

最近碰到几个怪问题:
1. 在新装的XP上Swing界面文字不显示,加上远程调试参数就能出来。安装最新的jre/jdk也没用。启动时加上远程调试参数OK,但不能这样交付啊。后来给显卡升级了一下驱动,搞定!真是奇怪
2. xp上跑的很好的批处理在win2k下失败,%~dps0失败,这是用来取批处理的短格式当前路径。google后知道这个参数在xpsp2以前都返回错误路径,我倒。。。 %~dps1, %~dp0都能正常工作,于是乎,写了两个批处理,把%dp0(长路径)传给另外一个,在那里面用%~dps1取得后设定环境变量,成功~
3. Java程序安装成服务以后不能接受其他电脑的访问,独立运行的时候没问题。用超级用户权限也没戏。后来拍拍脑袋发现是防火墙的问题,手动启动服务的时候windows防火墙不提示是否允许访问网络,所以缺省就被禁止鸟~。在防火墙中添加例外程序以后OK。所以安装程序需要聪明一些,自己在注册表中增加相关设定。

posted @ 2006-04-07 16:15 steeven 阅读(660) | 评论 (0)编辑 收藏
 
最近碰到一个问题:一个Java应用中(非web)众多的jar在windows2000下面下载启动失败。仔细查看了一下,批处理bat自动把所有的jar都加入到环境变量中,由于jar太多,导致命令行过长,系统不错,“不能加入”。 查文档得知jar/META-INF下面的mainifet.mf可以指令jar需要引用的包,比如: Class-Path: a.jar b/c.jar 实测发现加上两三个可以正常工作,多了以后就实效。换行,前面加一个空格还是不行。试验N久,放弃。 Class-Path: a.jar b.jar c.jar 多亏了偶一个同事契而不舍,终于发现java在解析的时候仅仅把上行末尾的回车和下行开头的空格去掉。所以,上面的格式中如果a.jar和b.jar后面直接跟回车,系统会认为是j.jar.b.jar.c.jar。 解决方法就是在每行后面加个空格。够弱智吧? 这个文件有每行76字符限制,不能超长。这些规定真是奇怪,居然能遗传到java5里面,希望野马能改正。
posted @ 2006-03-09 18:43 steeven 阅读(964) | 评论 (0)编辑 收藏
CALENDER
<2006年3月>
2627281234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(10)

随笔分类

随笔档案

文章档案

相册

我的链接

搜索

  •  

最新评论


Powered By: 博客园
模板提供沪江博客