如何从 Wildfly 8 获取初始上下文

How to get an Initial Contex from Wildfly 8

已添加 7 月 23 日。

许多观点:甚至 "that's dumb" 问题都没有回应。谁能至少告诉我为什么这样一个令人尴尬的琐碎问题似乎在任何地方都没有答案。

问:

--- 在本地机器 localhost:9990 上安装 Wildfly 8 运行ning。 --- 有一个需要 Wildfly 的 IntialContext 的 Java 程序。 --- 每个参考资料都说使用:"Context ctx = new InitialContext(env);" --- 然而,一周的搜索没有找到 returns 一个属性集。 并且没有一个 java 程序的例子。

从来没有人这样做过吗?真的需要帮助

原消息如下

我知道很多人问过如何从 Wildfly 8 获取初始上下文。但是我还没有找到一个简单的答案和一个简单的例子。

因此,我希望有人能告诉我为什么这不起作用。 我用 standalone-full.xml

启动 Wildfly

下面三个部分有

A - 我测试的代码摘要 Class 其唯一目的是保护初始上下文。 (我只删除了很多产生下一节的打印代码。]

B - Eclipse 控制台输出 失败。

C - 剪切并粘贴代码。以防万一有人可以帮助我让它工作。我想留下一些下一个 WF 新用户可以剪切和过去的东西 运行。与上面的 1 唯一的区别是这个版本有我用来格式化输出的所有静态方法。注意:我知道我插入的关于小于号的评论听起来很愚蠢。但是……他们是真的。

代码摘要

import java.util.Properties;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JmsTestGetJNDIContext {

  //members
  final private Properties env = new Properties() {
    private static final long serialVersionUID = 1L;
    {
      /* These are Properties used by a standalone JavaClient to secure a WIldFly InitialContext()*/             
      put(Context.INITIAL_CONTEXT_FACTORY,   "org.jboss.naming.remote.client.InitialContextFactory");  
      put(Context.PROVIDER_URL,"http-remoting://localhost:9990");
      put(Context.SECURITY_PRINCIPAL,"userGLB");  
      put(Context.SECURITY_CREDENTIALS,"Open");
      put("jboss.naming.client.ejb.context", true);  

      /*The above URL, ID and PW successfully open Wildfly's Admin Console*/
    }
  };

  //constructor
  private JmsTestGetJNDIContext (){
    /*print "beg"*/
    /*print "env"*/
    try { 
      /*print "Requesting InitialContext"*/
      Context ctx = new InitialContext(this.env); 
      /*print "JNDI Context: " + ctx)*/
      /*print "end");
    } catch (CommunicationException e) {
      /* print "You forgot to start WildFly dummy!"*/       
    } catch (Exception e) {
      /* print"caught:  " + e.getClass().getName()*/
      /*print e.getMessage()*/
      /* "end")*/
    }
    static public void main (String[] args) {
     /*print "beg"*/
     JmsTestGetJNDIContext client = new JmsTestGetJNDIContext ();
     /*print "end"*/
    }
  }

B - 控制台输出

JmsTestGetJNDIContext.main ()   beg
  JmsTestGetJNDIContext.<init> ()       beg
    JmsTestGetJNDIContext.<init> ()       These are Properties used to obtain IntialContext
           Key: java.naming.provider.url
                Value: http-remoting://localhost:9990
           Key: java.naming.factory.initial
                Value: org.jboss.naming.remote.client.InitialContextFactory
           Key: jboss.naming.client.ejb.context
                Value: true
           Key: java.naming.security.principal
                Value: userGLB
           Key: java.naming.security.credentials
                Value: Open
    JmsTestGetJNDIContext.<init> ()       Requesting InitialContext
    JmsTestGetJNDIContext.<init> ()       caught: javax.naming.NamingException
    JmsTestGetJNDIContext.<init> ()       Failed to create remoting connection
  JmsTestGetJNDIContext.<init> ()       end
JmsTestGetJNDIContext.main ()   end

剪切并粘贴代码

package org.america3.gotest.xtra;
import java.util.Properties;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JmsTestGetJNDIContext {
//members
final private Properties env = new Properties() {
  /**
   * Properties used by a standalone JavaClient to secure
   * a WIldFly InitialContext()*/
  private static final long serialVersionUID = 1L;
    {
put(Context.INITIAL_CONTEXT_FACTORY,"org.jboss.naming.remote.client.InitialContextFactory");  
      put(Context.PROVIDER_URL, "http-remoting://localhost:9990");
      put(Context.SECURITY_PRINCIPAL, "userGLB");  
      put(Context.SECURITY_CREDENTIALS, "Open");
      // The above URL, ID and PW successfully open Wildfly's Admin Console
      put("jboss.naming.client.ejb.context", true);  
    }
  };
  //constructor
  private JmsTestGetJNDIContext (){/*ignore*/String iAm = JmsTestGetJNDIContext.getIAm("  ", Thread.currentThread().getStackTrace()); 
  P (iAm, "beg");
  pProps(iAm, env);
  try { 
    P (sp + iAm, "Requesting InitialContext");
    Context ctx = new InitialContext(this.env); 
    P (sp + iAm, "JNDI Context: " + ctx);
     P (sp + iAm, "end");
  } catch (CommunicationException e) {
    P (sp +  iAm, "You forgot to start WildFly dummy!");       
  } catch (Exception e) {
    P (sp + iAm, "caught:  " + e.getClass().getName());
    P (sp + iAm, e.getMessage());
    P (iAm, "end");
  }
}
static public void main (String[] args) {/*ignore*/String iAm =  JmsTestGetJNDIContext.getIAm("",Thread.currentThread().getStackTrace());
  P (iAm, "beg");
  JmsTestGetJNDIContext client = new JmsTestGetJNDIContext ();
  P (iAm , "end");
}

/*The remaining static methods are just to facilitate printing.
 * They are normally in a Untility package I add to my projects.
 * I put them here so this code would run for anyone.*/

  static private void pProps (String leader, Properties p) {
    StringBuffer sb = new StringBuffer ();
    String s = JmsTestGetJNDIContext.padRight(leader, 45, ' ');
    s = "  " + s + "These are Properties used to obtain IntialContext"+"\n";
    sb.append(s);
    String skip = "";
    for (Object key: p.keySet()) {
      sb.append(skip + "       " + JmsTestGetJNDIContext.padRight("\"" 
                   + (String)key + "\"", 40, ' ') 
                   + "     \"" + p.get(key) + "\"");
      skip = "\n";
    }
    System.out.println(sb);
  }

  static private void P (String s, String s2) {
    System.out.println(s + s2);
  }

  static public String getClassMethodName (StackTraceElement[] elements) {
    String className = null;
    for (int i = 0; i * elements.length; i++]i ) {
      /* You need to type in a less than sign for the '*' 
       * because when I do, the editor will not show any code 
       * that comes after it.
       * I have no idea why, but I've spent over an hour trying,
       * and every time I type a less than sign all the following 
       * code dissappears!*/
      className = elements[i].getClassName ();
      if (className.startsWith ("org.america3")) {
        int end = className.lastIndexOf ('.');
        return className.substring (end + 1) + "." + elements[i].getMethodName ();
      } else {
        continue;
      }
    }
    return "no project method found in elements beginning with org.america3" ;
  }

  static private String getIAm (String indent, StackTraceElement[] elements) {
    StringBuffer sb = new StringBuffer ();
    sb.append(JmsTestGetJNDIContext.getClassMethodName(elements));
    sb.append(" ()");
    return indent + JmsTestGetJNDIContext.padRight (sb.toString(), 45, ' ') ;
  }

  static public String padRight(String s, int width, char c){
    if (s == null) return "Null String";
    if(s.length() ** width){
    /* You need to type in a greater than or equal sign for 
     * the '**'see above.*/
     return s;
    } else {
      StringBuffer sb = new StringBuffer();
      sb.append (s);
      for(int i = 0; i *** (width - s.length()); i++){
        /*You need to type in a less than sign the '***'. Again see above*/
        sb.append(c);
      }
      return sb.toString();
    }
  }

  static public String sp = "  ";
}

不久前,我还在 CLI 应用程序中使用远程 EJB。我挖掘了一个我当时写的小示例项目。它得到一个 InitialContext 并调用一个名为 AddBrackets:

的远程 EJB
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import de.dnb.test.ejb.AddBrackets;

public final class Application {

  public static void main(String[] args) throws NamingException {
    final Properties jndiProperties = initJndiProperties();
    final AddBrackets addBrackets = getEjb(jndiProperties);

    System.out.println(addBrackets.processText("Hello World"));
  }

  private static Properties initJndiProperties() {
    final Properties jndiProperties = new Properties();
    jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
        "org.jboss.naming.remote.client.InitialContextFactory");
    jndiProperties.put("jboss.naming.client.ejb.context", true);
    jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080/");
    //jndiProperties.put(Context.SECURITY_PRINCIPAL, "test");
    //jndiProperties.put(Context.SECURITY_CREDENTIALS, "test");
    return jndiProperties;
  }

  private static AddBrackets getEjb(Properties jndiProps)
      throws NamingException {
    final Context jndiContext = new InitialContext(jndiProps);
    final String interfaceName = AddBrackets.class.getName();
    return (AddBrackets) jndiContext.lookup(
        "ejbtest-app-1.0-SNAPSHOT/ejbtest-ejb-1.0-SNAPSHOT/AddBracketsBean!"
            + interfaceName);
  }
}

我将此程序构建为依赖于

的 Maven 项目
<dependency>
    <groupId>org.wildfly</groupId>
    <artifactId>wildfly-ejb-client-bom</artifactId>
    <version>8.2.1.Final</version>
    <type>pom</type>
</dependency>

此依赖项引入 Wildfly 的远程客户端 EJB 实现并将以下 jar 添加到 class 路径(链接到 Maven Central):

我在 Wildfly 上没有对 运行 这个例子进行特殊配置。我只是下载了一个 vanilla Wildfly 8.2.1,将其解压缩,使用 add-user.sh 脚本设置一个管理员用户并将我的 EJB 部署到一个 EAR 中。如您所见,无需用户名和密码即可授予访问权限。

您可以在我的 bitbucket account.

上找到包含 AddBrackets EJB 的完整项目

当我尝试使用 Wildfly 了解远程 EJB 时,我发现文章 JBoss EAP / Wildfly – Three ways to invoke remote EJBs 非常有用。它清楚地描述了在 Wildfly 上访问远程 EJB 的三种不同方法。

我确定问题不在于编码或 JNDI InititialContext 属性。

我的意思是致命错误是 NoSuchMethodError。因此,正如我在 WildFly 服务器日志中确认的那样,我的主要方法甚至从未尝试连接。

以下是我认为可以解释真正问题的内容。

而且我认为这解释了为什么会有如此多的求助电话来解决这个错误:

java.lang.NoSuchMethodError:
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]

还有为什么 none 的求助电话得到了最终的答复。只是人们建议不同的罐子。

由于所有这些答案都固定在罐子上,这就是我测试我使用的构建路径的方式:

首先,我从构建路径中删除了所有 jar。然后我 运行 我的一行主程序直到所有 ClassNotFoundException 都消失了。

第一个错误

java.lang.ClassNotFoundException:
org.jboss.naming.remote.client.InitialContextFactory]

将 jboss-remote-naming-1.0.7.final.jar 添加到 class 路径

下一个错误

java.lang.NoClassDefFoundError:
org/jboss/logging/Logger

已添加 jboss-logging.jar

下一个错误

java.lang.NoClassDefFoundError: 
org/xnio/Options

添加了 xnio-api-3.0.7.ga.jar

下一个错误

java.lang.NoClassDefFoundError:
org/jboss/remoting3/spi/ConnectionProviderFactory

已添加 jboss-远程处理-3.jar

下一个错误

java.lang.NoClassDefFoundError:
org/jboss/ejb/client/EJBClientContextIdentifier

已添加 jboss-ejb-client-1.0.19.final.jar

FATAL ERROR(注:所有NoClassDefFoundError都已清除)

java.lang.NoSuchMethodError: 
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]

然后我用Eclipse的Project Explorer验证:

那个 jboss-remoting3.jar 有 org.jboss.remoting3.Remoting Class。确实如此。这就是为什么上面没有留下 NoClassDefFoundError 的原因。

并验证它有这个方法: public Endpoint createEndpoint (String, Executor, OptionMap) 注意:3个参数。

但是上面的错误表明有东西在调用: public端点createEndpoint(String, OptionMap) 注意:2个参数。

这就是程序抛出 NoSuchMethodError 的原因。它正在寻找 org.jboss.remoting3.Remoting.createEndpoint() 的 2 参数版本。我的 Remoting Class 只有 3 个参数版本。`

我知道这听起来不可能,但我唯一能想到的是 Java API???

中存在不一致

很明显有东西在调用 org.jboss.remoting3.Remoting.createEndpoint 带有 2 个参数。

但是我的 org.jboss.remoting3.Remoting Class 只有 3 个参数版本的 createEndpoint() 方法。

所以我要清理这一切并重新发布一个问题,询问如何解释 Class 调用 2 参数 org.jboss.remoting3.Remoting.createEndpoint 的存在当我有一个 org.jboss.remoting3.Remoting 仅提供 3 参数的罐子时的方法。

这是您的必填项 "that's a dumb question." wildfly remote quickstart github 存储库是否为您解答了问题?他们的代码,来自RemoteEJB.java

final Hashtable<String, String> jndiProperties = new Hashtable<>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
return (RemoteCalculator) context.lookup("ejb:/ejb-remote-server-side/CalculatorBean!" + RemoteCalculator.class.getName());

根据您自己的 以下 jar 在您的 class 路径中:

  • jboss-remote-naming-1.0.7.final.jar
  • jboss-logging.jar
  • xnio-api-3.0.7.ga.jar
  • jboss-远程处理-3.jar
  • jboss-ejb-client-1.0.19.final.jar

您写道应用程序抛出以下异常:

java.lang.NoSuchMethodError: 
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]

当作为 jboss-remote-naming jar 的一部分的 org.jboss.naming.remote.client.EndpointCache 试图调用包含在 jboss-remoting 中的 Remoting.createEndpoint() 时抛出此异常罐子。

正如您在回答中解释的那样,原因是 Remoting class 声明了 createEndpoint() 方法的 3 参数版本,而 EndpointCache class 尝试调用不存在的 2 参数版本。

我检查了 jboss-remote-naming and the jboss-remoting 项目的提交历史和声明的依赖关系,以找出那里出了什么问题。这是我发现的:

createEndpoint() 的 2 参数版本仅在 jboss-remoting 的 3.2 版本中添加。 jboss-remote-naming-1.0.7.final 的 pom.xml 表示它依赖于 jboss-remoting 3.2.7.GA。

由于您的 jboss-remoting-3.jar 上没有版本号,我猜它是旧版本。您应该能够通过在 jboss-remoting-3.jar 的 META-INF 文件夹中查找 pom.xml 来检查这一点。这应该包含版本号。

为了解决您的问题,我建议将您的 jboss-remoting-3.jar 替换为 jboss-remoting-3.2.7ga.jar 或使用我在 .

中列出的罐子