一步一步教你用JCA(下)

本文特邀lgao撰写

在本系列文章的上篇中:

http://bluedash.iteye.com/blog/1566189

阿男为大家讲解了JCA的概念。本文将由我用一个例子来描述怎么进行ResourceAdapter的开发。

在本文中我们要用到的EIS是一个Servlet的服务,运行在一个JBoss AS服务器上(实际上运行在哪里无所谓,是什么也不重要。因为JCA标准中,并没有对EIS的形式或内容做要求。可以是文件,数据库,FTP服务,或像本文要用到的这个HTTP Servlet服务)。

这个项目的功能是列出自己电脑上的目录。我们将这个项目命名为:

* services-1.0.0.war

然后我们要使用另一台JBoss AS服务器做为Application Server,在这上面开发一个ResourceAdapter,用RAR的形式部署,将EIS接进来。将这个项目命名为:

* listfiles-0.1.rar

最后,我们要在Application Server上面开发一个Web应用,使用这个ResourceAdapter为我们接入的EIS资源,提供给最终用户进行使用。这个项目名为:

* listfiles-0.1.war

示例的整体架构图如下:

一步一步教你用JCA(下)_第1张图片

接下来是实施过程:

制作EIS

在一般的JCA开发过程中,应该是没有这步的,因为我们是要将已有的EIS通过ResourceAdpator接进Application Server。但是因为这个例子要为大家展示完整的过程,因此我们要首先动手制作一个EIS。

首先使用maven[1]创建一个webapp:

$ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=webapp-javaee6 -DgroupId=org.jboss.jca.sample.eis -DartifactId=services -Dversion=1.0.0 -B


我们要做一个Servlet,这个Servlet的功能很简单:用户给出一个dir目录,Servlet列出这个目录中的文件,就相当于ls命令:

package org.jboss.jca.sample.eis;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = {"/listfiles"})
public class ListFilesServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String dir = request.getParameter("dir");
        StringBuilder sb = new StringBuilder();
        if (dir != null && !dir.isEmpty()) {
            File file = new File(dir);
            if (file.exists() && file.canRead() && file.isDirectory()) {
                for (File f : file.listFiles()) {
                    if (f.isDirectory()) {
                        sb.append("drwx------\t" + f.getName() + "<br />\n");
                    } else if (f.isFile()) {
                        sb.append("-rwx------\t" + f.getName() + "<br />\n");
                    }
                }
            }
        } else {
            sb.append("Unkown Directory: " + dir);
        }
        request.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.println(sb.toString());
        out.flush();
    }

}


这就是这个EIS的全部功能了,接下来将项目打包:

mvn package


生成services-1.0.0.war,然后我们将它部署到JBoss AS服务器上,这个项目就算弄完了。

制作ResourceAdapter

接下来我们要制作核心部分ResourceAdapter。在这里,我们要用到JBoss社区的JCA标准实现框架IronJacamar[2]。

IronJacamar下载完成后,切换到:

ironjacamar-1.0.10.Final/doc/codegenerator/


运行:

./codegenerator.sh


按照提示输入:

一步一步教你用JCA(下)_第2张图片

在上述提示中, 红色下划线标记的为输入,其他因为采用提示给的默认值,因此直接回车就可以。其中:

Value: http://192.168.1.103:8080/services/listfiles  


这个配置指向你的EIS所在机器的IP地址。此外注意到我们设置中的Transaction Support和Re-authenticatiion都是No。也就是说,我们不准备在这个ResourceAdapter中实现事务管理contract和认证contract。是一个相当简单的ResourceAdapter。

完成后,会在当前目录下产生一个叫做out的目录,并生成了一系列的Java代码,下面是out目录结构:

一步一步教你用JCA(下)_第3张图片

我们看一下相应的类图:

一步一步教你用JCA(下)_第4张图片

* 在JCA规范中,暴露给用户的连接管理接口是ConnectionFactory。在本例当中我们的ConnectionFactory为ListFilesConnectionFactory。
* 通过ListFilesConnectionFactory.getConnection()获取到ListFilesConnection实例。
* ListFilesConnection 实例通过 ListFilesManagedConnection与相应的EIS 交互。
* ListFilesMangedConnection代表和EIS的物理连接;ListFilesConnection是这个物理连接的Handler。

首先我们实现ListFilesConnection接口,定义一个方法:

/** 
* Call the EIS ListFilesServlet and get response
*/
public String listFiles(String dir);



然后在ListFilesConnectionImpl中实现它:

...
private ListFilesManagedConnection mc;
...
public String listFiles(String dir)
{   
    return mc.listFiles(dir);
}


注意到ListFilesManagedConnection是实际要实现这个方法的地方,因此,接下来我们要在ListFilesManagedConnection中实现与EIS实际交互的逻辑。因为我们的EIS是一个Servlet的Web服务,因此通过网络调用它,并获取返回值,实现EIS的接入:

/**
 * List Files of directory 'dir' in EIS machine.
 *
 * @return a String contains all files in the directory
 */
String listFiles(String dir) {
    ListFilesResourceAdapter ra = (ListFilesResourceAdapter) this.mcf.getResourceAdapter();
    String listFilesServiceURL = ra.getListFilesServiceURL();
    String listFilesServiceParam = ra.getListFilesServiceParam();
    StringBuilder sb = new StringBuilder();
    java.net.HttpURLConnection conn = null;
    try {
        String dirEncoded = java.net.URLEncoder.encode(dir, "UTF-8");
        String url = listFilesServiceURL + "?" + listFilesServiceParam + "=" + dirEncoded;
        conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
        conn.setDoOutput(true);
        conn.connect();

        java.io.InputStream in = conn.getInputStream();
        java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(in, "UTF-8"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }
    return sb.toString();
}



Java代码挺简单的,接下来我们要编辑IronJacamar的配置文件:

src/main/rar/META-INF/ironjacamar.xml


下面是配置的详细内容,很容易理解:

<ironjacamar xmlns="http://www.jboss.org/ironjacamar/schema"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema 
        http://www.jboss.org/ironjacamar/schema/ironjacamar_1_0.xsd">
    <!--这里修改 config property 的值-->
    <config-property name="listFilesServiceURL">
        http://192.168.1.103:8080/services/listfiles
    </config-property>
    <config-property name="listFilesServiceParam">dir</config-property>

    <transaction-support>NoTransaction</transaction-support>

    <connection-definitions>
        <connection-definition class-name="org.jboss.jca.sample.listfiles.ListFilesManagedConnectionFactory"
                               jndi-name="java:/eis/ListFilesConnectionFactory" pool-name="ListFilesConnectionFactory">
        </connection-definition>
    </connection-definitions>
</ironjacamar>


ResourceAdapter的全部代码工作至此完成了,接下来将项目打包:

mvn package


生成listfiles-0.1.rar,这个就是我们需要的RAR文件了。将这个文件部署到Application Server当中。

创建客户端

有了EIS,也有了ResourceAdapter来接入这个EIS,接下来我们要写一个客户端应用,来通过ResourceAdapter使用这个EIS。请注意这里面说的客户端并不是最终用户,而是通过ResouceAdapter来使用EIS的应用,我们称其为客户端。

还是使用mvn来创建一个Web项目:

$ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=webapp-javaee6 -DgroupId=org.jboss.jca.sample.listfiles -DartifactId=listfileweb -Dversion=1.0.0 -B


仅需要撰写一个jsp文件,打开:

src/main/webapp/index.jsp


内容如下:

<%@ page import="org.jboss.jca.sample.listfiles.*" %>
<html>
<body>
<h2>Hello JCA!</h2>
<form action="index.jsp">
Directory: <input type="text" name="dir" />&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" value="List Files"/>
</form>
<br />
<%
         String dir = request.getParameter("dir");
         String files = "";
         if (dir != null && dir.length() != 0){
             String jndiName = "java:/eis/ListFilesConnectionFactory";
             javax.naming.InitialContext ctx = null;
             try
             {
                ctx = new javax.naming.InitialContext();
                Object obj = ctx.lookup(jndiName);
                if(obj != null){
                    ListFilesConnectionFactory connFactory = (ListFilesConnectionFactory)obj;
                    ListFilesConnection conn = connFactory.getConnection();
                    files = conn.listFiles(dir);
                    conn.close();
                }
             }
             catch (Exception e)
             {
                e.printStackTrace();
             }
             finally
             {
                try
                {
                   ctx.close();
                }
                catch (Exception e)
                {
                   e.printStackTrace();
                }
             }

%>
<div>Files under directory <%= dir %> : <br /> <%= files %></div>
<%
         }
%>
</body>
</html>


功能很简单:给用户一个输入表单->输入需要显示的目录->将用户的请求提交给ResourceAdapter->ResourceAdapter去调用EIS并返回结果。

虽然功能不难,但是代码当中包含了很多ResourceAdapter的调用方法:

String jndiName = "java:/eis/ListFilesConnectionFactory";

javax.naming.InitialContext ctx = null;
ctx = new javax.naming.InitialContext();

Object obj = ctx.lookup(jndiName);

ListFilesConnectionFactory connFactory = (ListFilesConnectionFactory)obj;
ListFilesConnection conn = connFactory.getConnection();

files = conn.listFiles(dir);

conn.close();


接下来我们需要编辑一下:

MANIFEST.MF


这个文件,因为在JBoss AS 7中, 要求这个文件中包含项目所依赖的ResourceAdapter信息,格式如下:

Dependencies: deployment.<RAR Name>


因此我们在这个文件中添加内容如下:

Dependencies: deployment.listfiles-0.1.rar


指定这个客户端项目依赖于listfiles-0.1.rar。最后还是项目打包:

mvn package


生成listfileweb-1.0.0.war。

部署

至此为止,我们应该有了三样东西:

* services.war - EIS
* listfileweb-1.0.0.rar - RAR
* listfileweb-1.0.0.war - Client

我们要部署这些组件:

将listfileweb-1.0.0.rar和listfileweb-1.0.0.war部署在机器A的JBoss AS上面

假设 JBoss AS 7 的目录在 ~/softwares/jboss-as/jboss-as-7.1.1.Final/, 那么我们运行命令:

[lgao@lgao jca]$ cd ~/softwares/jboss-as/jboss-as-7.1.1.Final/
[lgao@lgao jboss-as-7.1.1.Final]$ bin/standalone.sh


运行完以上指令, JBoss AS 7 就会启动, 之后我们来部署 listfiles RAR 和 listfileweb WAR,打开另外一个控制台,然后输入:

[lgao@lgao jboss-as-7.1.1.Final]$ bin/jboss-cli.sh --connect
[standalone@localhost:9999 /] deploy ~/jca/listfiles-0.1.rar
[standalone@localhost:9999 /] deploy ~/jca/listfileweb-1.0.0.war


如果两条指令没有错误提示, 部署就成功了。 我们可以确认下:

[standalone@localhost:9999 /] deploy -l
NAME                  RUNTIME-NAME          ENABLED STATUS 
listfiles-0.1.rar     listfiles-0.1.rar     true    OK     
listfileweb-1.0.0.war listfileweb-1.0.0.war true    OK    


将services.war部署在机器B的JBoss AS上面

部署services.war的方法没什么不同,不再赘述。但是这台机器上面的JBoss AS7的配置要稍做改变,因为我们需要让机器A中的ResourceAdapter能访问到这台机器上面的EIS资源,而AS7默认只侦听localhost,所以要做出配置修改。打开:

jboss-as-7.1.1.Final\standalone\configuration\standalone.xml


修改:

<interface name="public">
    <inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>


为:

<interface name="public">
    <any-address />
</interface>


然后启动AS7服务器:

bin/standalone.sh


测试

万事俱备,接下来进行测试。在机器A上面访问Client:

http://127.0.0.1:8080/listfileweb-1.0.0/


效果如下:

一步一步教你用JCA(下)_第5张图片

在输入框里写上要查看的目录文件列表,此时RAR会调用EIS,返回EIS所在的机器B中的目录内容:

一步一步教你用JCA(下)_第6张图片

以上,我们就完成了这个例子全部内容的展示。

小结

本文通过一个例子向大家展示JCA中ResourceAdapter的开发过程,以及对它的使用方式。虽然这个例子非常简单,仅实现了JCA标准中提供的三个contracts中的最基本的Connection Management,但是它的流程是完整的,在此基础上,你可以继续深入阅读JCA的相关资料,进一步学习它,也可以为阅读现有EIS的ResouceAdapter的源代码打下良好基础。相信这会是一个好的起点。

代码

本文中用到的三个代码我放在了github上面,有兴趣可以迁出:

EIS

https://github.com/gaol/jca-eis-listfiles


RAR

https://github.com/gaol/jca-rar-listfiles


Client

https://github.com/gaol/jca-client-listfileweb


文中用到的工具

Maven

Maven 是项目管理的工具, 可以很方便的进行项目的编译,打包,测试。可以从以下网址找到下载连接。

http://maven.apache.org/  


笔者使用的 maven 版本是:

[lgao@lgao out]$ mvn -version
Apache Maven 3.0.2 (r1056850; 2011-01-09 08:58:10+0800)
Java version: 1.7.0, vendor: Oracle Corporation
Java home: /home/lgao/softwares/java/jdk1.7.0/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.3.5-2.fc16.i686.pae", arch: "i386", family: "unix"


IronJacamar

IronJacamar 是 JBoss 的 JCA 1.6 实现,它提供了生成 JCA 代码的工具和 standalone 的环境用来测试,从以下地址下载 IronJacamar:

http://www.jboss.org/ironjacamar/downloads


本文使用的IronJacamar版本为1.0.10.Final。

JBoss AS 7

我们在这个例子中使用JBoss AS 7做为应用服务器还有EIS的例子工具。下面是网址:

http://www.jboss.org/jbossas/downloads/


笔者使用的 JBoss AS 7 版本是: 7.1.1.Final。

参考资料

JSR 322: JavaTM EE Connector Architecture 1.6 - http://jcp.org/en/jsr/detail?id=322

IronJacamar 1.0 User's Guide - http://docs.jboss.org/ironjacamar/userguide/1.0/en-US/html_single/

IronJacamar 1.0 Developer's Guide - http://docs.jboss.org/ironjacamar/developerguide/1.0/en-US/html_single/

你可能感兴趣的:(java,JCA)