【问题标题】:Oracle: Java stored procedure sending JMS MessageOracle:Java 存储过程发送 JMS 消息
【发布时间】:2011-10-23 10:07:03
【问题描述】:

我正在尝试将点对点 JMS 消息从 oracle 数据库存储过程发送到 java 应用程序。这两个“点”位于不同的机器上,我已经确认它们可以通过 ping 相互通信。

我创建了一个 java 应用程序,它能够成功地从应用程序服务器中的队列中取出消息。该应用程序在 JBoss v4.2.3 服务器中运行。我已经能够从远程 Java 应用程序成功发送 JMS 消息,所以我确信在服务器中运行的代码是可以的。

我已经从正在运行的远程 java 应用程序中获取代码,并将其成功加载到一个 oracle 存储过程中。我还设法(我相信!)使用 loadjava 实用程序将所需的 jar 文件加载到 oracle 中。我加载的三个jar文件是:

   * jms-1.1 
   * jbossmq-3.2.3
   * jboss-client-4.0.2

这三个 jars 在工作的远程 java 应用程序中使用,似乎就是所有需要的。加载到存储过程中的代码如下:

    package com.base.jms.client;

    import java.util.Hashtable;

    import javax.jms.JMSException;
    import javax.jms.Queue;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueSender;
    import javax.jms.QueueSession;
    import javax.jms.TextMessage;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class StandAloneClient {

        public static String send() throws Exception {

            String result = "Starting -> ";

            try {

                Hashtable env = new Hashtable();
                env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
                env.put(Context.PROVIDER_URL, "192.168.111.242:1099");
                env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

                result = result + "Environment -> ";

                // set up stuff
                Context ic = new InitialContext(env);
                result = result + "Context -> ";

                QueueConnectionFactory connectionFactory = (QueueConnectionFactory) ic.lookup("ConnectionFactory");
                result = result + "Factory -> ";

                Queue queue = (Queue) ic.lookup("queue/A");
                result = result + "Queue -> ";

                QueueConnection connection = connectionFactory.createQueueConnection();
                result = result + "Connection -> ";

                QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
                result = result + "Session -> ";

                QueueSender sender = session.createSender(queue);
                connection.start();

                result = result + "Sender -> ";

                TextMessage myMessage = session.createTextMessage();
                myMessage.setText(result);
                sender.send(myMessage);

                result = result + "Sending Message -> ";

                sender.close();
                session.close();
                connection.close();

                result = result + "Close";

            } catch (JMSException e) {
                result = result + "JMS Exception";

                /*
                if(e.getMessage() != null) {
                    result = result + ":" + e.getMessage();
                }*/

            } catch (Exception e) {
                result = result + "Exception";

                /*
                if(e.getMessage() != null) {
                    result = result + ":" + e.getMessage();
                }*/

            }

            return result;
        }

    }

我已经添加了结果字符串,因此我可以尝试确定它在代码中的哪个位置发生了故障。为了创建和测试这个过程,我在 sqlplus 中执行了以下命令:

create or replace function send_jms return VARCHAR2 as language java name 'com.base.jms.client.StandAloneClient.send() return java.lang.String';

variable myString varchar2(20);
call send_jms() into :myString;
Call completed.
print myString;

一切似乎都已正确加载和编译,但是没有发送消息。返回的结果字符串暗示它在尝试从 InitialContext 检索 QueueConnectionFactory 类时发生故障。返回的结果字符串为:

Starting -> Environment -> Context -> Exception

我不知道为什么这不起作用,并且无法从抛出的异常中收集更多信息。谁能确认我这样做是正确的,如果是,看看我做错了什么?

为这篇长文道歉,但提前感谢您查看它!

【问题讨论】:

  • 附带说明:Oracle 附带了一个建立在高级队列之上的 JMS 实现。有没有人使用内置的 JMS 成功地与 JBoss 或其他应用程序服务器进行互操作,甚至可能不使用 Java,而只使用 PL/SQL 包?
  • 我使用了 JBoss 提供的 Advance Queues。 Oracle 流也可用于 JMS。我认为采用我所做的方法会更容易。我开始不这么想了:)

标签: java oracle jboss jms


【解决方案1】:

我发现即使我试图以 SYS 的身份授予权限,并且该策略属于 SYS,但 SYS 没有授予该策略的权限。 所以这对我有用:

exec dbms_java.grant_policy_permission('SYS','SYS','java.net.SocketPermission','*');
exec dbms_java.grant_permission( 'MY_SCHEMA',  'SYS:java.net.SocketPermission', '*', 'connect,resolve' );

【讨论】:

    【解决方案2】:

    我终于完成了这一切,这在很大程度上要感谢 Cody 提供的帮助。我只是提出这个答案,以防其他人遇到同样的问题并想知道我是如何解决的。

    我为向 oracle 授予必要权限而运行的语句是:

    GRANT JAVASYSPRIV to NTIS
    EXEC dbms_java.grant_permission ('JAVASYSPRIV', 'SYS:java.net.SocketPermission', '*', 'accept,connect,listen,resolve');
    EXEC DBMS_JAVA.GRANT_PERMISSION('YOUR SCHEMA', 'SYS:java.net.SocketPermission', '*', 'connect,accept,resolve');
    

    执行这些命令时,您必须以“SYSTEM”用户身份登录。

    我在存储过程中遇到了一些进一步的问题,这些问题归结为我加载到 oracle 中的库的问题。我使用的罐子是:

     jms
     jbossmq-client 
     jboss-client 
    

    jbossmq-client 和 jboss-client jar 必须与应用服务器本身使用的版本相同。我使用的是 JBoss 4.2.3,所以我从 JBoss 目录中的“客户端”文件夹中复制了这些 jar。

    我还必须将 java 类/存储过程中引用的 ipaddress 放在 hosts 文件中,因为 oracle 似乎对 ipaddress 进行了反向查找。如果你不这样做,你会得到一个未知的主机异常。在 hosts 文件中,只需输入您的计算机名称和 IP 地址。

    完成这一切之后,它现在对我来说可以正常工作了!希望这对遇到同样问题的人有所帮助。

    【讨论】:

      【解决方案3】:

      我并不完全是在 Oracle 数据库中运行 Java 和 JMS 的专家(尽管我分别了解这三个组件中的每一个)。但从您的描述看来,您似乎没有考虑 Java 的 Oracle 安全模型。

      Oracle 不会让任何组件访问网络(或文件系统等),而无需明确被授予访问权限。因此,开始阅读Oracle JVM security,了解您可能需要如何配置 Oracle 以让您连接到远程计算机。

      授予权限可能涉及以下语句:

      EXEC DBMS_JAVA.GRANT_PERMISSION('YOUR_SCHEMA', 'SYS:java.net.SocketPermission', '192.168.111.242', 'connect,accept,resolve');
      

      【讨论】:

      • 嗨科迪,感谢您的回复。对于我正在处理的架构,我已经运行了您提供的授予权限以及 JAVASYSPRIV 的几个授予权限。它似乎已经把问题转移了。以前,我得到的 AccessControlException 与您所说的一致。但是,现在我在尝试检索 QueueConnectionFactory 时遇到了 javax.naming.CommunicationException。我将调查这个新异常的原因。您可以提供任何进一步的想法将不胜感激!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-11
      • 2018-07-30
      • 2012-01-07
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多