| qishun's profile躺在角落的孤独者PhotosBlogLists | Help |
躺在角落的孤独者我不敢停留在任何街口,不安全的因素充斥着这里的每个角落 |
|||||
|
|
January 25 Java中的XML_RPC的应用转载: http://www.ibm.com/developerworks/cn/java/j-xmlrpc/index.html 2004 年 2 月 06 日 应用程序间通信对程序员来说可能是个不好对付的问题。而许多可用的选择(如 JNI)又难于掌握。XML-RPC 提供了一种非常简单的解决方案。该方法简洁、易于实现,且得到了大多数流行编程语言(例如 Java 语言和 C++)的开放源代码库的良好支持。例如,如果您有一个 Java 应用程序需要与另一个用 C++ 编写的应用程序进行对话,那么 XML-RPC 正好可能是最简单的方法。在本文中,软件开发人员兼培训师 Roy Miller 谈论了 XML-RPC 是什么以及如何有效地使用它。 我无数次从开发同伴那里听说最新的热门技术就是对软件开发世界中使人烦恼的问题的解决方法。XML 首次出现时,许多人就是这样说的。此时,我没有感到兴奋,而且从那时起,我的态度也没有太多改变。我一直认为 XML 是种极佳的方法,用以定义结构化数据,而无需笨拙地将之转化为关系型结构。但是,XML 不是一种编程语言 ―― XLST 在语法上较为复杂,且至少对于我来说有点奇怪。因此,我一直在等待出现需要进行结构化数据交换的问题,而这才是创造 XML 的真正目的。在最近的项目中就出现了这个特殊问题,XML(用作 XML-RPC)正是合适于该工作的工具。 我们的客户制造了一种硬件设备。我们加入该项目之前,用户配置每台设备的惟一方法就是用命令行接口。要不是每个客户在每个网络上可能有 20 台或更多(也许甚至成百或上千)这样的硬件设备,该方法也并非必定糟糕。迫使客户用命令行接口一个接一个地配置每台设备很可能会削减销售。当客户在订货到达后不得不对多台设备进行初始设置和配置的时候,该问题将会更为尖锐。每个设备的配置包含在一个 XML 文件中,而设备在启动时将读取该文件。 客户聘请我们创建一个配置应用程序,用以在一个或更多位置集中的管理机器上运行。该应用程序需要简化所有设备的初始设置,将之重新配置为要进行固件升级、纠正错误等等,以及监控现有设备。其中有点困难的问题就是设备上的软件是用 C 编写的,而我们的台式机应用程序却需要用 Java 编程语言进行编写。 我们首先考虑的是 JNI,但是觉得应该存在更简单的东西。那就是称作 XML-RPC 的有用的小东西。
XML-RPC 网站(请参阅 参考资料)是这样描述的: 它是允许运行在不同操作系统、不同环境中的软件进行基于 Internet 过程调用的规范和一组实现。这种远程过程调用使用 HTTP 作为传输协议,XML 作为编码格式。XML-RPC 的定义尽可能简单,但能够传送、处理和返回复杂的数据结构。 在阅读该描述时,我们就知道我们有了答案。每台设备的配置保存在一个文件之中(其内容也是 XML,但这对于该论述无关紧要)。这意味着我们已经拥有告诉每台设备如何配置自身的语义。如果我们给设备发送它所期待的配置文件,那就会很好了。但是将如何发送呢?我们可以仅仅发送字节,但那样会危及安全性,况且用字节操作来完成这一切也不是谁所真正需要的。我们意识到可以用定义良好的 XML-RPC 消息来发送字符串有效负荷,而 XML-RPC 消息将允许我们调用每台设备上严格限制的软件公共接口中的 C 函数。
概括地说,您可以将 XML-RPC 认为是简化的 SOAP。它可能是您曾需要的惟一的应用程序间的通信。XML-RPC 网站上有个极佳的“入门”文档,该网站还提供了一些发展历史以及各种语言的实例。但是,您可能只需要阅读其规范。在不到六页的内容上包括了一个简单的模型。本节中,我们将介绍一些重点,以便为如何在项目中使用 XML-RPC 做好准备。 一个 XML-RPC 消息就是一个请求体为 XML 的 HTTP-POST 请求。您需要一个 XML-RPC 客户程序来创建消息,以及一个 XML-RPC 服务程序来接收消息。服务程序一旦完成了请求,就同样以 XML 格式送回一个 XML-RPC 响应消息。请求可以包含参数(整数、字符串、日期以及其他类型,如果需要还可以包括数组和复杂记录)。每个请求的格式都极其简单,如清单 1 所示: POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181
<?xml version="1.0"?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>
您需要一个指定“处理程序”名(清单 1 中为 其响应也很简单,如清单 2 所示: HTTP/1.1 200 OK
Connection: close
Content-Length: 158
Content-Type: text/xml
Date: Fri, 17 Jul 1998 19:55:08 GMT
Server: UserLand Frontier/5.1.2-WinNT
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>South Dakota</string></value>
</param>
</params>
</methodResponse>
当您发出一个 XML-RPC 调用时,您将获得一个 XML 响应,其中包含一个 HTTP/1.1 200 OK
Connection: close
Content-Length: 426
Content-Type: text/xml
Date: Fri, 17 Jul 1998 19:55:02 GMT
Server: UserLand Frontier/5.1.2-WinNT
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>4</int></value>
</member>
<member>
<name>faultString</name>
<value><string>Too many parameters.</string>
</value>
</member>
</struct>
</value>
</fault>
</methodResponse>
这也涉及您需要用以理解 XML-RPC 相关处理的所有内容。实际上,您真的无需了解 XML 消息布局的细节。只要提供了有效输入,您所选择的 XML-RPC 实现库将为您完成所有工作。因此,您所缺乏的用以读取规范的惟一工具就是客户程序和服务程序实现。在这个应用程序中,我们需要 Java 实现的客户程序和 C 实现的服务程序。
XML-RPC 网站包含多种语言编写的规范的客户程序和服务程序实现的链接,这些语言包括 Java 编程语言、Ruby、Python、C/C++ 和 Perl。 有一个由 Apache 小组编写的实现,还有一些是由单个开发人员编写的。在查看其中一些的代码之后,我们选择了 Greger Ohlson 所编写的 Marquee XML-RPC 客户程序实现。Ohlson 也编写了一个服务程序实现,但是为我们将配置的硬件设备编写代码的同事选择了 Apache XML-RPC 服务程序。只要输入和输出是可预测的,这也的确不要紧。 所有的开发是在 Eclipse 中进行的,因此我们仅仅下载 Marquee 库,为它创建一个项目并加载到我们的工作区中。还将它置于应用程序的类路径中使我们可以访问 Marquee 接口。此时,我们就只需要使用它。为了简化该方法,我们为设备创建了一个包装器,使应用程序剩下部分只需处理一个域对象而无需担忧 XML-RPC 的细支末节,并且创建了一个 XML-RPC 对象来包装请求和解码响应。 当应用程序由于某种理由(例如检查其状态)需要与设备进行交互时,它仅需调用该设备的包装器上的方法,从而与 XML-RPC 对象交互以完成 XML-RPC 的神奇功能。清单 4 显示了说明包装器模样的简化实例。 public class Device {
protected DeviceConfiguration configuration;
protected Status status = Status.UNREACHABLE;
protected Device(DeviceConfiguration configuration) {
this.configuration = configuration;
}
public Status getStatus() {
return obtainRpcClient().getStatus();
}
public void setStatus(Status status) {
if (this.status != status) {
this.status = status;
}
}
public void reboot() {
Status status;
try {
status = obtainRpcClient().reboot();
} finally {
makeUnreachable();
}
setStatus(status);
}
public DeviceConfiguration getConfiguration() {
this.configuration =
DeviceConfigurationBuilder.toConfig(
obtainRpcClient().getDeviceConfiguration());
makeOk();
return this.configuration;
}
public Status putConfiguration() {
Status status =
obtainRpcClient().replaceDeviceConfiguration(
DeviceConfigurationBuilder.toData(this.configuration));
setStatus(status);
return status;
}
protected RpcClient obtainRpcClient() {
return new RpcClient(
this.configuration.getIpAddress(),
80,
this.configuration.getUserPassword(),
100);
}
public void makeOk() {
setStatus(Status.OK);
}
public void makeUnreachable() {
setStatus(Status.UNREACHABLE);
}
}
这三个类的详细说明超出了本文的范围,可是我将介绍由 该示例包括用以向设备询问其状态,告诉设备进行重新启动,以及 get 和 put 配置数据的方法。但是 import java.util.Hashtable;
import marquee.xmlrpc.XmlRpcClient;
import marquee.xmlrpc.XmlRpcException;
public class RpcClient {
protected static final Object[] EMPTY_ARRAY = new Object[0];
protected XmlRpcClient xmlRpcClient;
protected String ipAddress;
protected String password;
protected int port;
protected int timeout;
public RpcClient(
String ipAddress,
int port,
String password,
int timeout) {
super();
this.ipAddress = ipAddress;
this.port = port;
this.password = password;
this.timeout = timeout;
xmlRpcClient = new XmlRpcClient(ipAddress, port, "/RPC2");
}
protected Object invoke(final String rpcMethodName) {
return invoke(rpcMethodName, EMPTY_ARRAY);
}
protected Object invoke(final String rpcMethodName, Object[] parameters) {
try {
Object result = xmlRpcClient.invoke(rpcMethodName, parameters);
if (result instanceof Hashtable) {
Hashtable fault = (Hashtable) result;
int faultCode = ((Integer) fault.get("faultCode")).intValue();
throw new RuntimeException(
"Unable to connect to device via XML-RPC. \nFault Code: "
+ faultCode
+ "\nFault Message: "
+ (String) fault.get("faultString"));
}
if (result instanceof Integer) {
return Status.getStatus((Integer) result);
}
return result.toString();
} catch (XmlRpcException e) {
throw new RuntimeException(e);
}
}
public Status getStatus() {
return (Status) invoke("Device.getStatus");
}
public String getDeviceConfiguration() {
return (String) invoke("Device.getConfiguration");
}
public Status replaceDeviceConfiguration(String configurationData) {
return (Status) invoke(
"Device.replaceConfiguration",
new Object[] { configurationData });
}
public Status reboot() {
return (Status) invoke("Device.reboot");
}
}
请注意, 不带参数的版本用一个空的 本例中,如果得到一个错误返回,我们就发出带有从故障 既然您已经了解了所有事项,就让我们将之连接起来。比如说我们的应用程序告诉一个特殊的
向
向 请注意在该示例代码中,我们无需进行任何 XML 操纵。完全不是的。因为 Marquee 库为我们完成了这一切。现在,XML-RPC 规范相当简单,因此,您大概可以滚动自己的客户程序,却无需做什么 ―― Marquee 库非常好,并且还拥有本文中未曾探索的功能。文档是直观、完整的。在我看来,永远不必解析 XML 是让人高兴的。
直到此时,我都没有提及太多该等式的服务端的相关内容。那是因为是由小组中的其他人为该应用程序创建的 XML-RPC 服务端(使用 Apache 的 C 实现)。那是很棒的,但是如果也必须用 Java 语言开发 XML-RPC 服务该怎么办呢?实际上也很容易。在该项目中,我们可以使用同样用 Java 语言编写的 Marquee XML-RPC 服务程序实现(请参阅 Other uses for XML-RPC以了解实际该如何做,但那是出于另一目的)。 清单 6 显示了一个简单的处理先前讨论的 XML-RPC 客户端请求的 XML-RPC 服务程序。它仅仅用于示例,模拟了一台真实的物理设备。让我们剖析该代码以了解 XML-RPC 服务程序的详情。 import java.io.IOException;
import marquee.xmlrpc.XmlRpcServer;
import marquee.xmlrpc.handlers.ReflectiveInvocationHandler;
public class DeviceServer {
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
protected boolean isShuttingDown;
protected String configuration = "initial configuration";
protected String host;
protected String password = PASSWORD;
protected XmlRpcServer rpcServer;
protected Thread rpcThread;
protected int port;
protected Status status = Status.OK;
public DeviceServer(String theHost, int thePort) {
host = theHost;
port = thePort;
createRpcServer();
startRpcServer();
}
public void shutDown() {
isShuttingDown = true;
if (rpcServer != null)
rpcServer.shutDown();
}
public Object getStatus() {
return new Integer(status.getCode());
}
public Object getConfiguration() {
return "valid configuration data";
}
public Object replaceConfiguration(String xml) {
configuration = xml;
return new Integer(status.getCode());
}
public Object reboot() {
return new Integer(status.getCode());
}
public void setStatus(Status newStatus) {
status = newStatus;
}
protected void startRpcServer() {
rpcThread = new Thread(new Runnable() {
public void run() {
try {
rpcServer.runAsService(port);
} catch (IOException ioe) {
if (!isShuttingDown)
ioe.printStackTrace();
}
}
});
rpcThread.setName("DeviceServer[" + this.host + "] on " + this.port);
rpcThread.start();
}
protected void createRpcServer() {
rpcServer = new XmlRpcServer();
rpcServer.registerInvocationHandler(
"Device",
new ReflectiveInvocationHandler(this));
}
}
服务程序的构造函数给出了处理过程的概要内容。我们保存传入的主机和端口信息,然后调用 大多数请求是直接进行的,但是这个
要使用 Marquee XML-RPC 服务,运行的服务实例就必须知道如何译解方法字符串。它必须知道哪个对象与 rpcServer.registerInvocationHandler("Device", new
ReflectiveInvocationHandler(this));
现在,无论何时服务端获得一个请求,而其方法字符串如 处理程序概念对于 XML-RPC 规范不是必须的,但是 Marquee 是围绕其构建的并且运行良好。如果基本的
January 23 将CodeSmith的输出文件在VS2005中打开,发现中文变成了乱码,看了一下CodeSmith的帮助,将ReponseEncoding属性改成"UTF-8",再重新输出,用VS打开,还是乱码。没办法,在VS的选项里面看看吧,意外发现“文本编辑器”->“常规”中有一个自动检测不带签名的UTF-8编码,选上,中文乱码终于露出了原形。找了一些资料看看,总算知道了原因:Windows为了识别Unicode、Unicode big endian和UTF-8,在Unicode、Unicode big endian和 将CodeSmith的输出文件在VS2005中打开,发现中文变成了乱码,看了一下CodeSmith的帮助,将ReponseEncoding属性改成"UTF-8",再重新输出,用VS打开,还是乱码。没办法,在VS的选项里面看看吧,意外发现“文本编辑器”->“常规”中有一个自动检测不带签名的UTF-8编码,选上,中文乱码终于露出了原形。找了一些资料看看,总算知道了原因:Windows为了识别Unicode、Unicode big endian和UTF-8,在Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。而CodeSmith的输出UTF-8是标准的未加标识的。这样VS就不能识别出输出文件的编码了。 为此我们可以更改其CodeSmith的脚本的方法来处理: 首先增加2行 public System.Text.Encoding enc = System.Text.Encoding.GetEncoding("Unicode"); public System.IO.StreamWriter txt; 找到下面这句话 this.ClassTemplate.RenderToFile(classFileName, true); 上面这段话更改成下面的代码 txt = new System.IO.StreamWriter(classFileName,false,enc); txt.Write(ClassTemplate.RenderToString()); txt.Close(); 再找到下面这句话 this.MappingTemplate.RenderToFile(mappingFileName, true); 上面这段话更改成下面的代码 txt = new System.IO.StreamWriter(mappingFileName,false,enc); txt.Write(MappingTemplate.RenderToString()); txt.Close(); January 01 linux Sys文件系统转载:http://blog.chinaunix.net/u3/99507/showart_2059410.html sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与 proc 有些类似,但除了与 proc 相同的具有查看和设定内核参数功能之外,还有为 Linux 统一设备模型作为管理之用。相比于 proc 文件系统,使用 sysfs 导出内核数据的方式更为统一,并且组织的方式更好,它的设计从 proc 中吸取了很多教训。本文就 sysfs 的挂载点 /sys 目录结构、其与 Linux 统一设备模型的关系、常见属性文件的用法等方面对 sysfs 作入门介绍,并且就内核编程方面,以具体的例子来展示如何添加 sysfs 支持。 sysfs 的历史,其与 proc 的关系? sysfs 与 /sys sysfs 文件系统总是被挂载在 /sys 挂载点上。虽然在较早期的2.6内核系统上并没有规定 sysfs 的标准挂载位置,可以把 sysfs 挂载在任何位置,但较近的2.6内核修正了这一规则,要求 sysfs 总是挂载在 /sys 目录上;针对以前的 sysfs 挂载位置不固定或没有标准被挂载,有些程序从 /proc/mounts 中解析出 sysfs 是否被挂载以及具体的挂载点,这个步骤现在已经不需要了。请参考附录给出的 sysfs-rules.txt 文件链接。 sysfs 与 proc sysfs 与 proc 相比有很多优点,最重要的莫过于设计上的清晰。一个 proc 虚拟文件可能有内部格式,如 /proc/scsi/scsi ,它是可读可写的,(其文件权限被错误地标记为了 0444 !,这是内核的一个BUG),并且读写格式不一样,代表不同的操作,应用程序中读到了这个文件的内容一般还需要进行字符串解析,而在写入时需要先用字符串格式化按指定的格式写入字符串进行操作;相比而言, sysfs 的设计原则是一个属性文件只做一件事情, sysfs 属性文件一般只有一个值,直接读取或写入。整个 /proc/scsi 目录在2.6内核中已被标记为过时(LEGACY),它的功能已经被相应的 /sys 属性文件所完全取代。新设计的内核机制应该尽量使用 sysfs 机制,而将 proc 保留给纯净的“进程文件系统”。 初识 /sys 清单 1. 与 /sys 文件系统的一次交互(视内核版本号和外接设备的不同,在您的系统上执行这些命令的结果可能与此有所不同) ls -F /sys 这是在 Fedora 10 的 2.6.27.5-117.fc10.i686 的内核上,可以看到在 /sys 目录下有 block, bus, class, dev, devices, firmware, fs, kernel, module, power 这些子目录,本文将分别介绍这些目录存在的含义。 第二个 ls 命令展示了在一个 pci 设备目录下的文件, "ls" 命令的 "-F" 命令为所列出的每个文件使用后缀来显示文件的类型,后缀 "/" 表示列出的是目录,后缀 "@" 表示列出的是符号链接文件。可以看到第二个目录下包含有普通文件 (regular file) 和符号链接文件 (symbolic link file) ,本文也将以这个具体的设备为例说明其中每一个普通文件的用途。 /sys 文件系统下的目录结构 /sys 下的目录结构是经过精心设计的:在 /sys/devices 下是所有设备的真实对象,包括如视频卡和以太网卡等真实的设备,也包括 ACPI 等不那么显而易见的真实设备、还有 tty, bonding 等纯粹虚拟的设备;在其它目录如 class, bus 等中则在分类的目录中含有大量对 devices 中真实对象引用的符号链接文件; 清单1 中在 /sys 根目录下顶层目录的意义如下: 表 1. /sys 下的目录结构 /sys 下的子目录 /sys/devices /sys/dev /sys/bus /sys/class /sys/block /sys/firmware /sys/fs /sys/kernel /sys/module
编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的 /sys/module/<module_name>, 这些模块的可用参数会出现在 如 /sys/module/printk/parameters/time 这个可读写参数控制着内联模块 printk 在打印内核消息时是否加上时间前缀; 所有内联模块的参数也可以由 "<module_name>.<param_name>=<value>" 的形式写在内核启动参数上,如启动内核时加上参数 "printk.time=1" 与 向 "/sys/module/printk/parameters/time" 写入1的效果相同; 没有非0属性参数的内联模块不会出现于此。 /sys/power /sys/slab (对应 2.6.23 内核,在 2.6.24 以后移至 /sys/kernel/slab) 接下来对 /sys/devices/ 下的目录结构作进一步探讨: 清单 2. 查看 /sys/devices/ 的目录结构 $ ls -F /sys/devices/ isa/ LNXSYSTM:00/ pci0000:00/ platform/ pnp0/ pnp1/ 可以看到,在 /sys/devices/ 目录下是按照设备的基本总线类型分类的目录,再进入进去查看其中的 PCI 类型的设备: 清单 3. 查看 /sys/devices/pci0000:00/ 的目录结构 $ ls -F /sys/devices/ isa/ LNXSYSTM:00/ pci0000:00/ platform/ 在 /sys/devices/pci0000:00/ 目录下是按照 PCI 总线接入的设备号分类存放的目录,再查看其中一个, 清单 4. 查看 /sys/devices/pci0000:00/ 的目录结构 $ ls -F /sys/devices/pci0000:00/0000:00:01.0/ 0000:01:00.0/ device local_cpus power/ subsystem_vendor broken_parity_status enable modalias resource uevent class irq msi_bus subsystem@ vendor config local_cpulist pci_bus/ subsystem_device 可以看到,其中有一个目录 0000:01:00.0/, 其它都是属性文件和属性组,而如果对 0000:01:00.0/ 子目录中进行再列表查看则会得到 清单1 的目录结构。 继续以上过程可以了解整个目录树的结构,这里把它整理成 图 1. sysfs 目录层次图 图 1. sysfs 目录层次图
其中涉及到 ksets, kobjects, attrs 等很多术语,这就不得不提到 Linux 统一设备模型。 December 08 彻底清除oracle 的数据表Oracle 10g 中出现表名:BIN$2cMp4FjwQ2Cw3Lj+BxLYTw==$0 最近发现Oracle中出现了这些奇怪的表名,上网查找后发现是oracle10g的回收站功能,并没有彻底的删除表,而是把表放入回收站,最后就出现了这样一堆奇怪的表名。。。。 清除的方法如下: purge table origenal_tableName; purge index origenal_indexName; 查询垃圾信息,可以用如下SQL语句: SELECT t.object_name,t.type ,t.original_name FROM user_recyclebin t; 现在发现,原来还有这个命令: PURGE recyclebin; 根本用不了上面那么复杂。呵呵! 另:删除Table不进入Recycle的方法: drop table tableName purge; 不过,我想一般的人都不愿意用这个。 December 07 Oracle 10.2下的“System.Exception: System.Data.OracleClient requires Oracle client software version 8.1.7 or greater1。没有安装客户端runtime
2.安装客户段runtime以后,提示 ORA-12154: TNS: could not resolve the connect identifier specified这个错误,找了很多办法,都不怎么好用。最后只好这么程序了//OracleDataReader infocenter; 主要是连接字串的改变。 终于搞定了c# 连接oracle。 在Nhibernate里也这么修改了! |
||||
|
|