Bon Long Ray - Documents for our current project.

Eclipse 3.2 RCP 连接到 JBoss 4.04 GA

1. ClassLoader

因为ClassLoader的关系, RCP 不能如普通 Java App 般直接连接到 JBoss 服务器,比如,使用如下常见代码:
List 1.1:
    java.util.Hashtable env = new java.util.Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
    env.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces");
    env.put(Context.PROVIDER_URL, "localhost:1099");
    try {
        Context ctx = new InitialContext(env);
          ...

在 InitialContext 时就会报错:
List 1.2:
Exception:Cannot instantiate class:
org.jnp.interfaces.NamingContextFactoryjavax.naming.NoInitialContextException:
Cannot instantiate class:
org.jnp.interfaces.NamingContextFactory
[Root exception is java.lang.ClassNotFoundException:
org.jnp.interfaces.NamingContextFactory]

针对这种报错网上查到的资料往往是说缺包,需要把
  • jboss/client/jbossall-client.jar
  • jboss/client/jnp-client.jar
  • jboss/client/log4j.jar
这几个主要的 jboss 关于 jnp 的 jar 都加入 classpath。对 RCP 而言,有了这些包也一样会报错,关键还是在于 classloader。

比较简单的解决办法是使用 rcp-trainingJNDIBrowser (RCP) 中 JNDIBrowser.lib 这样一个 plugin。这是一个扫描本地JBoss服务器可用 JNDI Name 并通过 TreeView 显示的小程序。它把 jbossall-client.jar 做了一个 plugin ,可以方便的解决缺包问题和 ClassLoader 问题,需要的话,也可以自己做一个――事实上,它所带的这个 jar 也最好替换成当前使用的 JBoss 下的 jbossall-client.jar。

至于具体操作,可以参考 com.rcptraining.jndibrowser.view 中的
  • JNDIView.java
  • InitialContextLoader.java
这两个文件。

在 JNDIView 中,通过 lib plugin 获得一个 ClassLoader:
List 1.3:
m_LibraryClassLoader = JNDIBrowserLibPlugin.class.getClassLoader();

而后,基于这个ClassLoader 通过方法 getInitialContext() 获取有效的 Context:
List 1.4:
    private Context getInitialContext() throws NamingException
    {
        // we use our special loader to obtain the inital context
        InitialContextLoader loader = new InitialContextLoader(m_LibraryClassLoader);
        
        // start the thread
        loader.start();
        
        try
        {
            // wait for the thread to terminate. we don't need any 
            // kind of asynch behaviour
            loader.join();
        } 
        catch (InterruptedException aEx)
        {
            throw new RuntimeException(aEx);
        }
        
        return loader.getContext();
    }

获得有效的 Context 是通过 InitialContextLoader (extends Thread):

List 1.5:
class InitialContextLoader extends Thread
{
    private Context m_Context;
    private NamingException m_Exception;
    
    InitialContextLoader(ClassLoader aLoader)
    {
        // set context class loader to the loader we received
        setContextClassLoader(aLoader);
    }
    
    public void run()
    {
        // create initial context in a usual way       
        Properties env = new Properties();
        
        env.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099");
        env.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        // we can't throw anything exception from Thread.run();
        try
        {
            m_Context = new InitialContext(env);
        } 
        catch (NamingException aEx) 
        {
            // so we remember the exception
            m_Exception = aEx;
        }
    }
    public Context getContext() throws NamingException
    {
        // if exception was generated during run() -  
        if(m_Exception != null)
            throw m_Exception; // throw it
        return m_Context;
    }
}
如此,可以获得一个有效的 context ,并可以 lookup 到 JBoss 的 default JNDI names 了。

2. Security Manager

接下来的工作对象是 security manager。比如 《Pro Eclipse JST Plugins for J2EE Development》这本书中的 TroubleTicket 这个例子,如果使用 Eclipse 内部的 Application Client Project (其他的 common java application 也一样),可以访问 TroubleTicket的 Static Session Bean:
List 2.1:
getClassName()  getName()  obj.toString()
$Proxy64  TicketService  TicketServiceHome

但 RCP 却无法访问,试图 ctx.lookup("TicketService") 时,会报错:
List 2.2:
javax.naming.CommunicationException
[Root exception is java.lang.ClassNotFoundException:
service.TicketServiceHome (loader disabled)]
________
(未完)

没有评论: