精彩的人生

好好工作,好好生活

BlogJava 首页 新随笔 联系 聚合 管理
  147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

#

突然发现我认识的今年毕业的人工作都找的很好(除了我们学校的),一个去了上海思科,一个是本科生,也去了上海,一个去了甲骨文。

不知道我毕业的时候会咋样,每念及此,倍感忧心。
posted @ 2006-04-19 10:19 hopeshared 阅读(253) | 评论 (0)编辑 收藏

译者:gracepig

E-mail & MSN : zhangchi_nwpu@hotmail.com


版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
英文原文地址:
http://www.javaworld.com/javaworld/jw-07-2005/jw-0704-jena.html

中文地址
http://www.matrix.org.cn/resource/article/43/43598_RDF_JAVA.html

关键词:Resource Description Framework models RDF XML Jena Protégé

摘要
资源描述框架(Resource Description Framework RDF)是一种以XML格式描述元数据的标准格式。Jena是一种用于将关系数据库或是文本文件中所表示的数据建立为元数据模型的框架方法。Protégé 用用来创建RDF元数据文档的编辑工具。 建立这种数据库和文件的元数据模型需要由用户自己定义脚本。本文介绍介绍了SemantiRDFUtils这种脚本,它拥有多个功能块可以用于维护Jena RDF 元数据模型.(2200词,2005-7-4) By Venkata N.VAsam

与XML成为不同软件厂商之间数据交互的标准过程相似,资源描述框架(RDF)也沿着这条道路前进,希望能够成为描述与交互元数据的标准。XML 使用文件类型定义(DTD)和XML格式定义(XSD)来描述数据。RDF使用XML语法和RDF Schema(RFDS)来将元数据描述成为数据模型。

本文介绍了一种使用Jena RDF API 编写的用户自定义工具,使用这种工具来管理存储在关系数据库或是文本文件的数据模型。这种工具是由HP实验室开发的,Jena框架是一个RDF,RDFS以及OWL(Web Ontology Language)的开源实现, 它包含着一个基于规则的推论引擎。它提供了建立和操纵RDF模型的Java API。本文介绍的SemanticRDFUtils.bat是一种使用Jena开发的脚本。使用这种脚本,我们可以维护存储在关系数据库和文本文件中的元数据模型。本文还介绍了怎样使用Protégé来将建RDF的语意描述文件(.rdfs)和数据文件(.rdf)。

软件安装
在使用SemanticRDFUtils.bat之前必须先安装以下的软件。关于以下工具的链接请参看文中所附的资源。
        J2SE 1.3 或更高的版本
        Jena 2.0
        Oracle 9.2.0.1.0
        Apache Ant 1.5.4 或更新的版本
        Protégé 2.1


RDF和RDFS 文件简要介绍
下面的XML格式的RDF和RDFS文件用于显示一个字母顺序的交叉引用模型。它们是使用Protégé 2.1 的图形界面工具创建的。当执行脚本和RDF查询工具的时候我们可以动态的引入RDF文件。RDFS文件则在我们使用Protégé 给RDF文件中加入更多数据时使用。


列表1. RDFTest1.rdf

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE rdf:RDF [
   <!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
   <!ENTITY rdfs 'http://www.w3.org/TR/1999/PR-rdf-schema-19990303#'>
   <!ENTITY Maana 'http://www.vvasam.com/Maana#'>
]>
<rdf:RDF xmlns:rdf="&rdf;"
   xmlns:Maana="&Maana;"
   xmlns:rdfs="&rdfs;">
<Maana:ASCII rdf:about="&Maana;RDFTest_Instance_0"
   Maana:Name="A"
   Maana:value="65"
   rdfs:label="A:65">
   <Maana:system rdf:resource="&Maana;RDFTest_Instance_2"/>
</Maana:ASCII>
<Maana:System rdf:about="&Maana;RDFTest_Instance_1"
   Maana:Name="lowercase"
   rdfs:label="lowercase"/>
<Maana:ASCII rdf:about="&Maana;RDFTest_Instance_10000"
   Maana:Name="b"
   Maana:value="98"
   rdfs:label="b:98">
   <Maana:system rdf:resource="&Maana;RDFTest_Instance_1"/>
</Maana:ASCII>
<Maana:ASCII rdf:about="&Maana;RDFTest_Instance_10001"
   Maana:Name="B"
   Maana:value="66"
   rdfs:label="B:66">
   <Maana:system rdf:resource="&Maana;RDFTest_Instance_2"/>
</Maana:ASCII>
<Maana:AscXRef rdf:about="&Maana;RDFTest_Instance_10002"
   rdfs:label="b:98:B:66">
   <Maana:keyName rdf:resource="&Maana;RDFTest_Instance_10000"/>
   <Maana:keyValue rdf:resource="&Maana;RDFTest_Instance_10001"/>
</Maana:AscXRef>
<Maana:AscXRef rdf:about="&Maana;RDFTest_Instance_10005"
   rdfs:label="a:97:A:65">
   <Maana:keyValue rdf:resource="&Maana;RDFTest_Instance_0"/>
   <Maana:keyName rdf:resource="&Maana;RDFTest_Instance_8"/>
</Maana:AscXRef>
<Maana:System rdf:about="&Maana;RDFTest_Instance_2"
   Maana:Name="uppercase"
   rdfs:label="uppercase"/>
<Maana:ASCII rdf:about="&Maana;RDFTest_Instance_8"
   Maana:Name="a"
   Maana:value="97"
   rdfs:label="a:97">
   <Maana:system rdf:resource="&Maana;RDFTest_Instance_1"/>
</Maana:ASCII>
</rdf:RDF>


列表 2. RDFTest1.rdfs

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE rdf:RDF [
   <!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
   <!ENTITY system 'http://protege.stanford.edu/system#'>
   <!ENTITY Maana 'http://www.vvasam.com/Maana#'>
   <!ENTITY rdfs 'http://www.w3.org/TR/1999/PR-rdf-schema-19990303#'>
]>
<rdf:RDF xmlns:rdf="&rdf;"
   xmlns:system="&system;"
   xmlns:rdfs="&rdfs;"
   xmlns:Maana="&Maana;">
<rdf:Property rdf:about="&system;maxCardinality"
   rdfs:label="system:maxCardinality"/>
<rdf:Property rdf:about="&system;minCardinality"
   rdfs:label="system:minCardinality"/>
<rdf:Property rdf:about="&system;range"
   rdfs:label="system:range"/>
<rdfs:Class rdf:about="&Maana;ASCII"
   rdfs:label="ASCII">
   <rdfs:subClassOf rdf:resource="&rdfs;Resource"/>
</rdfs:Class>
<rdfs:Class rdf:about="&Maana;AscXRef"
   rdfs:label="AscXRef">
   <rdfs:subClassOf rdf:resource="&rdfs;Resource"/>
</rdfs:Class>
<rdf:Property rdf:about="&Maana;Name"
   rdfs:label="Name">
   <rdfs:domain rdf:resource="&Maana;ASCII"/>
   <rdfs:domain rdf:resource="&Maana;System"/>
   <rdfs:range rdf:resource="&rdfs;Literal"/>
</rdf:Property>
<rdf:Property rdf:about="&Maana;RDFTest_Slot_10003"
   rdfs:label="RDFTest_Slot_10003">
   <rdfs:range rdf:resource="&rdfs;Literal"/>
</rdf:Property>
<rdfs:Class rdf:about="&Maana;System"
   rdfs:label="System">
   <rdfs:subClassOf rdf:resource="&rdfs;Resource"/>
</rdfs:Class>
<rdf:Property rdf:about="&Maana;keyName"
   rdfs:label="keyName">
   <rdfs:range rdf:resource="&Maana;ASCII"/>
   <rdfs:domain rdf:resource="&Maana;AscXRef"/>
</rdf:Property>
<rdf:Property rdf:about="&Maana;keyValue"
   rdfs:label="keyValue">
   <rdfs:range rdf:resource="&Maana;ASCII"/>
   <rdfs:domain rdf:resource="&Maana;AscXRef"/>
</rdf:Property>
<rdf:Property rdf:about="&Maana;system"
   rdfs:label="system">
   <rdfs:domain rdf:resource="&Maana;ASCII"/>
   <rdfs:range rdf:resource="&Maana;System"/>

</rdf:Property>
<rdf:Property rdf:about="&Maana;value"
   rdfs:label="value">
   <rdfs:domain rdf:resource="&Maana;ASCII"/>
   <rdfs:range rdf:resource="&rdfs;Literal"/>
</rdf:Property>
</rdf:RDF>


Jena和Protégé概述
本节在宏观层面上介绍Jena和Protégé。用户可以在附加资源中得到关于这两个产品更多的信息。本文的目的是使您对Jena和Protégé有一个比较清晰的理解。

Jena RDF 和RDQL

RDF数据模型是一个声明(statement)的集合,每一个声明都包括三个部分:资源,属性和值。 资源(resource)可以是任何使用URI标示的内容,它可以包含其它属性。每一个属性有一个值。
Jena可以将RDF模型保存在关系数据库或是文件当中。RDQL是用来查询RDF模型的语言。RDF提供一种节点可以为资源或是文本的有向图(有向图的概念请参看《离散数学》)。RDQL则提供一种方式,由用户定义一种图模式,使用这种模式对目标图集合进行匹配,获得所有符合定义模式的结果。图1 使用RDF图来表示列表1和列表2中文件

resized image

图1:范例RDF文件的RDF 图表示


上图中,椭圆代表资源,长方形代表描述。资源通过箭头连接到其它的资源或是描述值(一个对象或是一个值)上,这样一组关系形成一个三元组,成为一个声明(statement)。
下面给我一个RDQL查询的例子。三元组(?x <http://www.vvasam.com/Maana#value> "97")是一个声明。X是一个绑定的变量用来代表一个资源;http://www.vvasam.com/Maana#value是一个叫做“value”的属性;97是这个属性的值。

SELECT ?x WHERE (?x <http://www.vvasam.com/Maana#value> "97")

Jena的toolkit提供了一个在命令行方式执行的Java类(jjena.rdfquery)来进行RDQL查询。下面的例子演示了如果使用这个命令进行查询并将查询结果存入test1.rdql当中。
java jena.rdfquery --data RDFTest1.rdf --query test1.rdql
x
================================================
http://www.vvasam.com/Maana#RDFTest_Instance_8

注意:通过文后的资源链接来获得关于RDF和RDQL更多的信息。


RDF 中使用Protégé

Protégé 是一个用来建立和编辑ontologies和知识库的GUI工具。Protégé可以在RDF格式下创建和保存数据。在使用Protégé建立RDF模型时,需要在新建一个工程的时候选取RDF Schema,如图2所示。


图2. RDF Schema工程


在Protégé's工程菜单选择新建工程时,选择格式(Select Format)对话框会弹出。点击OK按钮,图3的窗口会出现。


图3. 缺省Protégé工程视图


正如您在图3中所看到的那样,Protégé有一些标签。本文主要介绍其中的Classes,Instances和Algernon标签。
图4显示了Protégé的保存对话框。在其中用户可以填入工程,类文件,实例文件,和命名空间的名字。如图4所示,类文件名中包括RDF Schema的信息,实例文件名中包括RDF的数据。命名空间中以唯一URI的方式标示出RDF模型。


图4: Protégé's保存对话框


图5和图6显示的是Protégé's类标签和实例标签,分别表示了列表1和列表2中的.rdf和.rdfs文件。这些文件使用Protégé's schema 格式创建。


图5: Protégé的类标签



图6: Protégé的实例标签


Protégé中的Algeronon 查询
Protégé's的Algernon query标签为进行Algernon查讯提供了一个图形界面,用户可以在这个UI当中进行查询,并查看结果。Algernon是一种基于三元组的查询语言,如图7所示Algernon将资源以遍历(traversal)路径的方式返回给用户。缺省的Algernon并不会如下图那样显示。要看到这个标签,用户必须从工程菜单的设置子菜单中选择。



图7. Algernon 标签


Jena和Protégé之间的命名(terminology)映射
由于Jena和Protégé是两个不同的开源技术,所以他们的RDF 命名(terminology)存在差别。下表中列出了这些命名规则,用户可以更具这些命名规则来创建和处理RDF文件。


表1. Jena 和 Protégé 命名比较



Jena 的语义RDF工具

一节讲解了一些用于维护Jena数据库和文件模型的有用的工具/脚本。这些脚本文件包含在SemanticRDFUtils-scripts-files.zip文件当中,您可以在资源当中找到。下面的列表中描述了这些脚本文件可以执行的任务。当用户以没有任务ID号作为参数的命令行方式执行SemanticRDFUtils批处理文件时,下面的内容将会出现在你的控制台当中

C:\RDF\SemanticRDFUtils
Usage: SemanticRDFUtils taskid
   Where taskid should be any one of the following:
    1 --> To create and initialize the Jena system tables with a system model name as JenaRDFSystem
    2 --> To create a database model
    3 --> To remove a database model.
    4 --> To list the contents of a given model.
    5 --> To import RDF/XML file to a database.
    6 --> To list existing database model names
    7 --> To export a database model to a RDF/XML file
    8 --> To delete all the contents of a database model
    9 --> To create a union(RDF/XML file) of RDF/XML file models
    10 --> To create an intersection(RDF/XML file) of RDF/XML file models
    11 --> To create a difference(RDF/XML file) of RDF/XML file models
    12 --> To get the size of the given model
    13 --> Export the RDF query results as RDF/XML file.
    14 --> Delete the resource(s) from a model based on RDF query



以上各任务ID的意思分别为:
1:建立并初始化一个Jena系统表,系统模型名为JenaRDFSystem
2:建立数据库模型
3:删除一个数据库模型
4:列出所给出模型当中的内容
5:将RDF/XML文件导入数据库
6:列出存在数据库模型的名字
7:将数据库模型导出到RDF/XML文件中
8:删除一个数据库模型当中的所有内容
9: 为不同RDF/XML文件模型建立一个合并的RDF/XML文件
10:建立不同RDF/XML文件直接的交集文件。
11: 建立不同RDF/XML文件直接的差集文件。
12:得到给定模型的大小
13:将RDF查询结果保存在RDF/XML文件当中
14:从RDF查询结果模型当中删除资源

SemanticRDFUtils脚本使用SemanticRDFUtils.properties文件储存配置信息。下表给出了配置信息中的所有属性:

表 2. 属性设置


resized image


任务
第一个任务是在数据库中建立一个Jena 系统表并要求下列属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url

第二个任务是在数据库建立一个新的RDF模型并要求下列属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性为空,那么脚本会提示用户从键盘输入值)

第三个任务是从数据库中删除RDF模型并要求以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性为空,那么脚本会提示用户从键盘输入值)

第四个任务是列出RDF数据库中的内容并要求以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性为空,那么脚本会提示用户从键盘输入值)

第五个任务是将RDF导入到数据库模型当中,并要求以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性为空,那么脚本会提示用户从键盘输入值)
        import_rdffile_abs_name
属性import_rdffile_abs_name值将被置为.rdf文件的绝对路径(如下的例子所示)。如果这个值为空那么脚本会提示用户从键盘输入值。
import_rdffile_abs_name=C:\temp\RDFTest1.rdf

第六个任务是列出一个数据库模型中所有的模型,需要以下的属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url

第七个任务是将指定数据库模型的内容导出到一个RDF文件当中,需要以下的属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性值为空,脚本将提示用户从键盘输入)
        import_rdffile_abs_name
属性export_rdffile_abs_name值将被置为.rdf文件的绝对路径(如下的例子所示)。如果这个值为空那么脚本会提示用户从键盘输入值。
export_rdffile_abs_name=C:/temp/export.rdf

第八个任务是从数据模型中删除内容,需要以下正确的属性值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
The ninth task performs a union operation on two file models and requires appropriate values for the following properties:

第九个任务是对两个文档模型进行并集操作,需要以下正确的属性值:
        isRDFInDB
        url
               file_rdfmodel1_abs_name
        file_rdfmodel2_abs_name
        result_rdfmodel_abs_name
下面是一个范例的属性值:
file_rdfmodel1_abs_name=C:/temp/RDFTest1.rdf

file_rdfmodel2_abs_name=C:/temp/RDFTest2.rdf

result_rdfmodel_abs_name=C:/temp/RDFTestUnion.rdf

当使用SemanticRDFUtils执行任务9的时候,两个.rdf文件会被合并。如果要在一个合并的.rdf文件上建立一个Protégé工程,.rdfs文件必须被手工生成。

第10个任务是执行两个文件模型的交集操作,需要以下属性的正确值:
        isRDFInDB
        url
        file_rdfmodel1_abs_name
        file_rdfmodel2_abs_name
        result_rdfmodel_abs_name
下面是一个范例的属性值:
file_rdfmodel1_abs_name=C:/temp/RDFTest1.rdf
file_rdfmodel2_abs_name=C:/temp/RDFTest2.rdf
result_rdfmodel_abs_name=C:/temp/RDFTestInterSection.rdf


第11个任务是执行两个文件模型的差集操作,需要以下属性的正确值:
        isRDFInDB
        url
        file_rdfmodel1_abs_name
        file_rdfmodel2_abs_name
        result_rdfmodel_abs_name
下面是一个范例的属性值:
file_rdfmodel1_abs_name=C:/temp/RDFTest1.rdf
file_rdfmodel2_abs_name=C:/temp/RDFTest2.rdf
result_rdfmodel_abs_name=C:/temp/ RDFTestDifference.rdf


第12个任务是列出指定数据库模型的大小,需要以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个值为空那么脚本会提示用户从键盘输入值)

第13个任务将对数据库模型的一个RDF查询结果导出到一个RDF文件中,需要以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性值为空,脚本会要求用户从键盘输入值)
        rdf_query
        bind_var_name
        export_rdffile_abs_name
下面是一个范例的属性值:
rdf_query=SELECT ?x WHERE (?x    "65")
bind_var_name=x
export_rdffile_abs_name=C:/temp/exportquery.rdf


第14个任务是将一个将数据库模型的RDF查询结果删除,需要以下属性的正确值:
        rdf_sytem_model_name
        db_user
        db_password
        isRDFInDB
        url
        modelName (如果这个属性值为空,脚本会要求用户从键盘输入值)
        rdf_query
        bind_var_name
下面是一个范例的属性值:
rdf_query=SELECT ?x WHERE (?x    "65")
bind_var_name=x


结论
这篇文章介绍了怎么样使用Jena和Protégé来创建RDF源数据模型。并描述了怎样使用SemanticRDFUtils在命令行脚本方式下维护RDF模型。在这篇文章的资源中的SemanticRDFUtils-source-files.zip文件包含了能够用来创建基于Web接口或是Protégé的插件的源文件,使用它们可以管理RDF模型。针对每一个RDF模型所加载的脚文会有所不同,所以需要区别对待,每一种情况都要独立处理。

关于作者:
Venkata N. Vasam 主要工作领域是J2EE/Web services/EAI 架构。目前他使用SeeBeyond集成工具包(eGate和ICAN)为A2A和B2B集成需求提供Web服务/J2EE/EAI 架构。他获得了J.N.T University,Hyderabad, India的计算机科学与工程学位。业余时间Vasam喜欢打网球看喜剧和运动电影。

gracepig是(Matrix.org.cn)的会员,可以通过zhangchi_nwpu@hotmail.com和他联系。


资源
文中的源码下载地址
http://www.javaworld.com/javaworld/jw-07-2005/jena/jw-0704-jena.zip
"What is RDF?" 作者 Tim Bray (XML.com, 一月 2001): http://www.xml.com/pub/a/2001/01/24/rdf.html
        RDF 规范
http://www.w3.org/RDF/
        Jena下载地址
http://jena.sourceforge.net/downloads.html
        RDF和Jena RDF API简介
http://jena.sourceforge.net/tutorial/RDF_API/index.html
        Jena2: 一种语意Web框架
http://www.hpl.hp.com/semweb/jena2.htm
        RDQL:
http://jena.sourceforge.net/tutorial/RDQL/index.html
        RDF 入门
http://www710.univ-lyon1.fr/~champin/rdf-tutorial/
        Protégé 入门
http://protege.stanford.edu/doc/tutorial/get_started/index.html
        Protégé 下载
http://protege.stanford.edu/download/download.html
        Algernon标签
http://algernon-j.sourceforge.net/doc/algernon-protege.html
        ava 下载地址
http://java.sun.com/
        Oracle下载地址
http://www.oracle.com/technology/software/index.html
                Matrix java门户
http://www.matrix.org.cn
posted @ 2006-04-17 13:06 hopeshared 阅读(2498) | 评论 (0)编辑 收藏

进公司已经5个月了,这五个月过的还真是不轻松。

在以前的公司,就算刚进去的时候什么都不会,2个月下来也会变成一个熟手,任务分配下来剩下的问题只是时间问题

但是现在,经常会觉得无从下手,经常会觉得很无助,经常会觉得自卑:怎么自己什么都不会呢?为什么自己的知识面那么窄呢?怎么看了那么多资料什么都记不住呢?

于是,就会想到放弃,就会很想休息。

然后再网上四处闲逛,然后发现没有什么值得去的网站。于是反思自己的工作,于是告诉自己:加油!不会就学习吧。

于是开始放下急功近利的心,于是放下带着目标的眼镜,拿出最原始的、最基本的文档,仔细地研读。现在,我是学生,我在学习,我不是工人。

posted @ 2006-04-12 13:28 hopeshared 阅读(297) | 评论 (0)编辑 收藏

老板让我分析wildfire的结构,这个软件是开源的,能拿到代码,但是文档太少了。我需要掌握它的体系结构,但是我已经看了n天的资料+文档了,还是没有理清,有没有很好的办法能快速掌握一个软件的结构呢?偶比较笨,学习起来比较慢。。。
posted @ 2006-04-11 13:05 hopeshared 阅读(909) | 评论 (4)编辑 收藏

版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:cleverpig(作者的Blog:http://blog.matrix.org.cn/page/cleverpig)
原文:http://www.matrix.org.cn/resource/article/44/44062_Java+Annotation+Apt.html
关键字:java,annotation,apt

前言:
前不久在matrix上先后发表了《java annotation 入门》《java annotation 手册》两篇文章,比较全面的对java annotation的语法、原理、使用三方面进行了阐述。由于《入门》中的简单例程虽然简单明了的说明了annotation用法,但给大家的感觉可能是意犹未见,所以在此行文《java annotation高级应用》,具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。

一、摘要:
《java annotation高级应用》具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。本文列举了用于演示annotation的BRFW演示框架、演示APT的apt代码实例,并对其进行较为深度的分析,希望大家多多提意见。

二、annotation实例分析
1.BRFW(Beaninfo Runtime FrameWork)定义:
本人编写的一个annotation功能演示框架。顾名思义,BRFW就是在运行时取得bean信息的框架。

2.BRFW的功能:
A.源代码级annotation:在bean的源代码中使用annotation定义bean的信息;
B.运行时获取bean数据:在运行时分析bean class中的annotation,并将当前bean class中field信息取出,功能类似xdoclet;
C.运行时bean数据的xml绑定:将获得的bean数据构造为xml文件格式展现。熟悉j2ee的朋友知道,这个功能类似jaxb。

3.BRFW框架:
BRFW主要包含以下几个类:
A.Persistent类:定义了用于修饰类的固有类型成员变量的annotation。
B.Exportable类:定义了用于修饰Class的类型的annotation。
C.ExportToXml类:核心类,用于完成BRFW的主要功能:将具有Exportable Annotation的bean对象转换为xml格式文本。
D.AddressForTest类:被A和B修饰过的用于测试目的的地址bean类。其中包含了地址定义所必需的信息:国家、省级、城市、街道、门牌等。
E.AddressListForTest类:被A和B修饰过的友人通讯录bean类。其中包含了通讯录所必备的信息:友人姓名、年龄、电话、住址(成员为AddressForTest类型的ArrayList)、备注。需要说明的是电话这个bean成员变量是由字符串类型组成的ArrayList类型。由于朋友的住址可能不唯一,故这里的住址为由AddressForTest类型组成的ArrayList。
从上面的列表中,可以发现A、B用于修饰bean类和其类成员;C主要用于取出bean类的数据并将其作xml绑定,代码中使用了E作为测试类;E中可能包含着多个D。
在了解了这个简单框架后,我们来看一下BRFW的代码吧!

4.BRFW源代码分析:
A.Persistent类:
清单1:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.annotation.*;

/**
* 用于修饰类的固有类型成员变量的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Persistent {
        String value() default "";
}


B.Exportable类:
清单2:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.annotation.*;

/**
* 用于修饰类的类型的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Exportable {
        //名称
        String name() default "";
        //描述
        String description() default "";
        //省略name和description后,用来保存name值
        String value() default "";
        
}


C.AddressForTest类:
清单3:

package com.bjinfotech.practice.annotation.runtimeframework;

/**
* 用于测试的地址类
* @author cleverpig
*
*/
@Exportable("address")
public class AddressForTest {
        //国家
        @Persistent
        private String country=null;
        
        //省级
        @Persistent
        private String province=null;
        
        //城市
        @Persistent
        private String city=null;
        
        //街道
        @Persistent
        private String street=null;

        //门牌
        @Persistent
        private String doorplate=null;
        
        public AddressForTest(String country,String province,
                        String city,String street,String doorplate){
                this.country=country;
                this.province=province;
                this.city=city;
                this.street=street;
                this.doorplate=doorplate;
        }
        
}


D.AddressListForTest类:
清单4:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.util.*;

/**
* 友人通讯录
* 包含:姓名、年龄、电话、住址(多个)、备注
* @author cleverpig
*
*/
@Exportable(name="addresslist",description="address list")
public class AddressListForTest {
        //友人姓名
        @Persistent
        private String friendName=null;
        
        //友人年龄
        @Persistent
        private int age=0;
        
        //友人电话
        @Persistent
        private ArrayList<String> telephone=null;
        
        //友人住址:家庭、单位
        @Persistent
        private ArrayList<AddressForTest> AddressForText=null;
        
        //备注
        @Persistent
        private String note=null;
        
        public AddressListForTest(String name,int age,
                        ArrayList<String> telephoneList,
                        ArrayList<AddressForTest> addressList,
                        String note){
                this.friendName=name;
                this.age=age;
                this.telephone=new ArrayList<String>(telephoneList);
                this.AddressForText=new ArrayList<AddressForTest>(addressList);
                this.note=note;
                
        }
}


E.ExportToXml类:
清单5:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.ArrayList;

/**
* 将具有Exportable Annotation的对象转换为xml格式文本
* @author cleverpig
*
*/
public class ExportToXml {
        /**
         * 返回对象的成员变量的值(字符串类型)
         * @param field 对象的成员变量
         * @param fieldTypeClass 对象的类型
         * @param obj 对象
         * @return 对象的成员变量的值(字符串类型)
         */
        private String getFieldValue(Field field,Class fieldTypeClass,Object obj){
                String value=null;
                
                try{
                        if (fieldTypeClass==String.class){
                                value=(String)field.get(obj);
                        }
                        else if (fieldTypeClass==int.class){
                                value=Integer.toString(field.getInt(obj));
                        }
                        else if (fieldTypeClass==long.class){
                                value=Long.toString(field.getLong(obj));
                        }
                        else if (fieldTypeClass==short.class){
                                value=Short.toString(field.getShort(obj));
                        }
                        else if (fieldTypeClass==float.class){
                                value=Float.toString(field.getFloat(obj));
                        }
                        else if (fieldTypeClass==double.class){
                                value=Double.toString(field.getDouble(obj));
                        }
                        else if (fieldTypeClass==byte.class){
                                value=Byte.toString(field.getByte(obj));
                        }
                        else if (fieldTypeClass==char.class){
                                value=Character.toString(field.getChar(obj));
                        }
                        else if (fieldTypeClass==boolean.class){
                                value=Boolean.toString(field.getBoolean(obj));
                        }
                }
                catch(Exception ex){
                        ex.printStackTrace();
                        value=null;
                }
                return value;
        }
        
        /**
         * 输出对象的字段,当对象的字段为Collection或者Map类型时,要调用exportObject方法继续处理
         * @param obj 被处理的对象
         * @throws Exception
         */
        public void exportFields(Object obj) throws Exception{
                Exportable exportable=obj.getClass().getAnnotation(Exportable.class);        
                if (exportable!=null){
                        if (exportable.value().length()>0){
//                                System.out.println("Class annotation Name:"+exportable.value());
                        }
                        else{
//                                System.out.println("Class annotation Name:"+exportable.name());
                        }
                }
                else{
//                        System.out.println(obj.getClass()+"类不是使用Exportable标注过的");
                }
                
                //取出对象的成员变量
                Field[] fields=obj.getClass().getDeclaredFields();
                
                for(Field field:fields){
                        //获得成员变量的标注
                        Persistent fieldAnnotation=field.getAnnotation(Persistent.class);
                        if (fieldAnnotation==null){
                                continue;
                        }
                        //重要:避免java虚拟机检查对私有成员的访问权限
                        field.setAccessible(true);
                        Class typeClass=field.getType();
                        String name=field.getName();
                        String value=getFieldValue(field,typeClass,obj);
                        
                        //如果获得成员变量的值,则输出
                        if (value!=null){
                                System.out.println(getIndent()+"<"+name+">\n"
                                                +getIndent()+"\t"+value+"\n"+getIndent()+"</"+name+">");
                        }
                        //处理成员变量中类型为Collection或Map
                        else if ((field.get(obj) instanceof Collection)||
                                        (field.get(obj) instanceof Map)){
                                exportObject(field.get(obj));
                        }
                        else{
                                exportObject(field.get(obj));
                        }
                        
                }
        }
        
        //缩进深度
        int levelDepth=0;
        //防止循环引用的检查者,循环引用现象如:a包含b,而b又包含a
        Collection<Object> cyclicChecker=new ArrayList<Object>();
        
        /**
         * 返回缩进字符串
         * @return
         */
        private String getIndent(){
                String s="";
                for(int i=0;i<levelDepth;i++){
                        s+="\t";
                }
                return s;
        }
        /**
         * 输出对象,如果对象类型为Collection和Map类型,则需要递归调用exportObject进行处理
         * @param obj
         * @throws Exception
         */
        public void exportObject(Object obj) throws Exception{
                Exportable exportable=null;
                String elementName=null;
                
                //循环引用现象处理
                if (cyclicChecker.contains(obj)){
                        return;
                }
                
                cyclicChecker.add(obj);
                
                //首先处理Collection和Map类型
                if (obj instanceof Collection){
                        for(Iterator i=((Collection)obj).iterator();i.hasNext();){
                                exportObject(i.next());
                        }
                }
                else if (obj instanceof Map){
                        for(Iterator i=((Map)obj).keySet().iterator();i.hasNext();){
                                exportObject(i.next());
                        }
                }
                else{

                        exportable=obj.getClass().getAnnotation(Exportable.class);
                        //如果obj已经被Exportable Annotation修饰过了(注意annotation是具有继承性的),
                        //则使用其name作为输出xml的元素name
                        if (exportable!=null){
                                if (exportable.value().length()>0){
                                        elementName=exportable.value();
                                }
                                else{
                                        elementName=exportable.name();
                                }
                        }
                        //未被修饰或者Exportable Annotation的值为空字符串,
                        //则使用类名作为输出xml的元素name
                        if (exportable==null||elementName.length()==0){
                                elementName=obj.getClass().getSimpleName();
                        }
                        //输出xml元素头
                        System.out.println(getIndent()+"<"+elementName+">");
                        levelDepth++;
                        //如果没有被修饰,则直接输出其toString()作为元素值
                        if (exportable==null){
                                System.out.println(getIndent()+obj.toString());
                        }
                        //否则将对象的成员变量导出为xml
                        else{
                                exportFields(obj);
                        }
                        levelDepth--;
                        //输出xml元素结尾
                        System.out.println(getIndent()+"</"+elementName+">");
                        
                }
                cyclicChecker.remove(obj);
        }
        
        public static void main(String[] argv){
                try{
                        AddressForTest ad=new AddressForTest("China","Beijing",
                                        "Beijing","winnerStreet","10");
                        
                        ExportToXml test=new ExportToXml();
                        
                        ArrayList<String> telephoneList=new ArrayList<String>();
                        telephoneList.add("66608888");
                        telephoneList.add("66608889");
                        
                        ArrayList<AddressForTest> adList=new ArrayList<AddressForTest>();
                        adList.add(ad);
                        
                        AddressListForTest adl=new AddressListForTest("coolBoy",
                                        18,telephoneList,adList,"some words");
                        
                        test.exportObject(adl);
                }
                catch(Exception ex){
                        ex.printStackTrace();
                }
        }
}


在ExportToXml类之前的类比较简单,这里必须说明一下ExportToXml类:此类的核心函数是exportObject和exportFields方法,前者输出对象的xml信息,后者输出对象成员变量的信息。由于对象类型和成员类型的多样性,所以采取了以下的逻辑:

在exportObject方法中,当对象类型为Collection和Map类型时,则需要递归调用exportObject进行处理;
而如果对象类型不是Collection和Map类型的话,将判断对象类是否被Exportable annotation修饰过:
如果没有被修饰,则直接输出<对象类名>对象.toString()</对象类名>作为xml绑定结果的一部分;
如果被修饰过,则需要调用exportFields方法对对象的成员变量进行xml绑定。

在exportFields方法中,首先取出对象的所有成员,然后获得被Persisitent annotation修饰的成员。在其后的一句:field.setAccessible(true)是很重要的,因为bean类定义中的成员访问修饰都是private,所以为了避免java虚拟机检查对私有成员的访问权限,加上这一句是必需的。接着后面的语句便是输出<成员名>成员值</成员名>这样的xml结构。像在exportObject方法中一般,仍然需要判断成员类型是否为Collection和Map类型,如果为上述两种类型之一,则要在exportFields中再次调用exportObject来处理这个成员。

在main方法中,本人编写了一段演示代码:建立了一个由单个友人地址类(AddressForTest)组成的ArrayList作为通讯录类(AddressForTest)的成员的通讯录对象,并且输出这个对象的xml绑定,运行结果如下:

清单6:

<addresslist>
        <friendName>
                coolBoy
        </friendName>
        <age>
                18
        </age>
        <String>
                66608888
        </String>
        <String>
                66608889
        </String>
        <address>
                <country>
                        China
                </country>
                <province>
                        Beijing
                </province>
                <city>
                        Beijing
                </city>
                <street>
                        winnerStreet
                </street>
                <doorplate>
                        10
                </doorplate>
        </address>
        <note>
                some words
        </note>
</addresslist>


三、APT实例分析:
1.何谓APT?
根据sun官方的解释,APT(annotation processing tool)是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用annotation processors来处理annotation。而annotation processors使用了一套反射API并具备对JSR175规范的支持。
annotation processors处理annotation的基本过程如下:首先,APT运行annotation processors根据提供的源文件中的annotation生成源代码文件和其它的文件(文件具体内容由annotation processors的编写者决定),接着APT将生成的源代码文件和提供的源文件进行编译生成类文件。
简单的和前面所讲的annotation实例BRFW相比,APT就像一个在编译时处理annotation的javac。而且从sun开发者的blog中看到,java1.6 beta版中已将APT的功能写入到了javac中,这样只要执行带有特定参数的javac就能达到APT的功能。

2.为何使用APT?
使用APT主要目的是简化开发者的工作量,因为APT可以在编译程序源代码的同时,生成一些附属文件(比如源文件、类文件、程序发布描述文字等),这些附属文件的内容也都是与源代码相关的。换句话说,使用APT就是代替了传统的对代码信息和附属文件的维护工作。使用过hibernate或者beehive等软件的朋友可能深有体会。APT可以在编译生成代码类的同时将相关的文件写好,比如在使用beehive时,在代码中使用annotation声明了许多struct要用到的配置信息,而在编译后,这些信息会被APT以struct配置文件的方式存放。

3.如何定义processor?
A.APT工作过程:
从整个过程来讲,首先APT检测在源代码文件中哪些annotation存在。然后APT将查找我们编写的annotation processor factories类,并且要求factories类提供处理源文件中所涉及的annotation的annotation processor。接下来,一个合适的annotation processors将被执行,如果在processors生成源代码文件时,该文件中含有annotation,则APT将重复上面的过程直到没有新文件生成。

B.编写annotation processors:
编写一个annotation processors需要使用java1.5 lib目录中的tools.jar提供的以下4个包:
com.sun.mirror.apt: 和APT交互的接口;
com.sun.mirror.declaration: 用于模式化类成员、类方法、类声明的接口;
com.sun.mirror.type: 用于模式化源代码中类型的接口;
com.sun.mirror.util: 提供了用于处理类型和声明的一些工具。

每个processor实现了在com.sun.mirror.apt包中的AnnotationProcessor接口,这个接口有一个名为“process”的方法,该方法是在APT调用processor时将被用到的。一个processor可以处理一种或者多种annotation类型。
一个processor实例被其相应的工厂返回,此工厂为AnnotationProcessorFactory接口的实现。APT将调用工厂类的getProcessorFor方法来获得processor。在调用过程中,APT将提供给工厂类一个AnnotationProcessorEnvironment 类型的processor环境类对象,在这个环境对象中,processor将找到其执行所需要的每件东西,包括对所操作的程序结构的参考,与APT通讯并合作一同完成新文件的建立和警告/错误信息的传输。

提供工厂类有两个方式:通过APT的“-factory”命令行参数提供,或者让工厂类在APT的发现过程中被自动定位(关于发现过程详细介绍请看http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html)。前者对于一个已知的factory来讲是一种主动而又简单的方式;而后者则是需要在jar文件的META-INF/services目录中提供一个特定的发现路径:
在包含factory类的jar文件中作以下的操作:在META-INF/services目录中建立一个名为com.sun.mirror.apt.AnnotationProcessorFactory 的UTF-8编码文件,在文件中写入所有要使用到的factory类全名,每个类为一个单独行。

4.一个简单的APT实例分析:
A.实例构成:
Review类:定义Review Annotation;
ReviewProcessorFactory类:生成ReviewProcessor的工厂类;
ReviewProcessor类:定义处理Review annotation的Processor;
ReviewDeclarationVisitor类:定义Review annotation声明访问者,ReviewProcessor将要使用之对Class进行访问。
runapt.bat:定义了使用自定义的ReviewProcessor对Review类源代码文件进行处理的APT命令行。

B.Review类:
清单7:

package com.bjinfotech.practice.annotation.apt;

/**
* 定义Review Annotation
* @author cleverpig
*
*/
public @interface Review {
        public static enum TypeEnum{EXCELLENT,NICE,NORMAL,BAD};
        TypeEnum type();
        String name() default "Review";
}


C.ReviewProcessorFactory类:
清单8:

package com.bjinfotech.practice.annotation.apt;

import java.util.Collection;
import java.util.Set;
import java.util.Arrays;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
//请注意为了方便,使用了静态import
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.emptySet;

/**
* 生成ReviewProcessor的工厂类
* @author cleverpig
*
*/
public class ReviewProcessorFactory implements AnnotationProcessorFactory{
        /**
         * 获得针对某个(些)类型声明定义的Processor
         * @param atds 类型声明集合
         * @param env processor环境
         */
        public AnnotationProcessor getProcessorFor(
                        Set<AnnotationTypeDeclaration> atds,
                        AnnotationProcessorEnvironment env){
                return new ReviewProcessor(env);
        }
        /**
         * 定义processor所支持的annotation类型
         * @return processor所支持的annotation类型的集合
         */
        public Collection<String>         supportedAnnotationTypes(){
                //“*”表示支持所有的annotation类型
                //当然也可以修改为“foo.bar.*”、“foo.bar.Baz”,来对所支持的类型进行修饰
            return unmodifiableCollection(Arrays.asList("*"));
    }
        
        /**
         * 定义processor支持的选项
         * @return processor支持选项的集合
         */
        public Collection<String>         supportedOptions(){
                //返回空集合
            return emptySet();
    }
        
        public static void main(String[] argv){
                System.out.println("ok");
        }
}


D.ReviewProcessor类:
清单9:

package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.util.DeclarationVisitors;
import com.sun.mirror.util.DeclarationVisitor;

/**
* 定义Review annotation的Processor
* @author cleverpig
*
*/
public class ReviewProcessor implements AnnotationProcessor{
        //Processor所工作的环境
        AnnotationProcessorEnvironment env=null;
        
        /**
         * 构造方法
         * @param env 传入processor环境
         */
        public ReviewProcessor(AnnotationProcessorEnvironment env){
                this.env=env;
        }
        
        /**
         * 处理方法:查询processor环境中的类型声明,
         */
        public void process(){
                //查询processor环境中的类型声明
                for(TypeDeclaration type:env.getSpecifiedTypeDeclarations()){
                        //返回对类进行扫描、访问其声明时使用的DeclarationVisitor,
                        //传入参数:new ReviewDeclarationVisitor(),为扫描开始前进行的对类声明的处理
                        //        DeclarationVisitors.NO_OP,表示在扫描完成时进行的对类声明不做任何处理
                        DeclarationVisitor visitor=DeclarationVisitors.getDeclarationScanner(
                                        new ReviewDeclarationVisitor(),DeclarationVisitors.NO_OP);
                        //应用DeclarationVisitor到类型
                        type.accept(visitor);
                }
        }
}


E.ReviewDeclarationVisitor类:
清单10:

package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.util.*;
import com.sun.mirror.declaration.*;

/**
* 定义Review annotation声明访问者
* @author cleverpig
*
*/
public class ReviewDeclarationVisitor extends SimpleDeclarationVisitor{
        /**
         * 定义访问类声明的方法:打印类声明的全名
         * @param cd 类声明对象
         */
        public void visitClassDeclaration(ClassDeclaration cd){
                System.out.println("获取Class声明:"+cd.getQualifiedName());
        }
        
        public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration atd){
                System.out.println("获取Annotation类型声明:"+atd.getSimpleName());
        }
        
        public void visitAnnotationTypeElementDeclaration(AnnotationTypeElementDeclaration aed){
                System.out.println("获取Annotation类型元素声明:"+aed.getSimpleName());
        }
}


F.runapt.bat文件内容如下:
清单11:

E:
rem 项目根目录
set PROJECT_ROOT=E:\eclipse3.1RC3\workspace\tigerFeaturePractice
rem 包目录路径
set PACKAGEPATH=com\bjinfotech\practice\annotation\apt
rem 运行根路径
set RUN_ROOT=%PROJECT_ROOT%\build
rem 源文件所在目录路径
set SRC_ROOT=%PROJECT_ROOT%\test
rem 设置Classpath
set CLASSPATH=.;%JAVA_HOME%;%JAVA_HOME%/lib/tools.jar;%RUN_ROOT%

cd %SRC_ROOT%\%PACKAGEPATH%
apt -nocompile -factory com.bjinfotech.practice.annotation.apt.ReviewProcessorFactory  ./*.java


四、参考资源:
http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
作者的Blog:http://blog.matrix.org.cn/page/cleverpig


五、源代码下载:
[下载文件]
posted @ 2006-04-03 13:36 hopeshared 阅读(2235) | 评论 (0)编辑 收藏

仅列出标题
共30页: First 上一页 12 13 14 15 16 17 18 19 20 下一页 Last