JDBC Lotus-Oracle错误:Java.lang.ArrayIndexOutOfBoundsException:数组索引超出范围:-1

时间:2011-08-24 16:04:06

标签: java oracle jdbc lotus-notes

我正在使用jdbc连接到Oracle 10g数据库。在Eclipse / Java中构建连接可以正常工作。但是,当我将代码移动到Lotus 8.5.2代理程序时,我最终得到以下错误:

Java.lang.ArrayIndexOutOfBoundsException: Array index out of range: -1
 at oracle.jdbc.driver.T4CTTIoauthenticate.setSessionFields(T4CTTIoauthenticate.java:1019)
 at oracle.jdbc.driver.T4CTTIoauthenticate.<init>(T4CTTIoauthenticate.java:186)
 at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:354)
 at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:454)
 at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
 at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
 at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:802)
 at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:298)
 at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:222)
 at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:166)
 at JavaAgent.NotesMain(Unknown Source)
 at lotus.domino.AgentBase.runNotes(Unknown Source)
 at lotus.domino.NotesThread.run(Unknown Source)

这是用于连接的代码:

Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection(
 "jdbc:oracle:thin:@:xx.xx.xx.xx:1521:xx", "xx", "xx");

我试图以不同的方式解决这个问题: - 在eclipse中使用Lotus JVM - 在eclipse中使用不同的jdbc jar - 使用不同的方法在Lotus中构建连接 - 在莲花中使用不同的jdbc jars罐子

最后我移动了ojdbc14.jar文件Lotus \ Notes \ _jvm \ lib \ ext目录,现在工作正常。 这个解决方案可行,但显然我更喜欢将这个jar与nsf一起分发。有没有办法让这种情况发生?

正如leyrer所建议的那样。我尝试将以下行添加到“/jvm/lib/security/java.policy”文件中

permission java.security.AllPermission;

这会导致相同的错误消息。 现在我将坚持将ojdbc5.jar放在/ ext目录中。

3 个答案:

答案 0 :(得分:2)

如果您正在使用解压缩的ojdbc jar,请确保不排除oracle / sql / converter_xcharset / * .glb文件。当我的可执行jar使用Maven构建时,我得到了同样的错误,但是没有包含这些文件。下面的块明确包含它们。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>unpack-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <configuration>
        <excludeTypes>pom</excludeTypes>
        <includes>**/*.class,**/*.glb</includes>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <overWriteReleases>false</overWriteReleases>
        <overWriteSnapshots>true</overWriteSnapshots>
      </configuration>
    </execution>
  </executions>
</plugin>

答案 1 :(得分:1)

我猜,JVM的安全管理器不允许访问网络,因为安全策略未指定允许此操作。 有关详细信息,请参阅Flying Saucer in Lotus Notes

答案 2 :(得分:0)

很久以前这个问题出现了......但是这个月我必须为客户发现它。在任何地方我都找不到解决办法,但却有一些错误的借口和不完整的分析。因此,对于所有人来说,我将分享我的发现,问题的根本原因以及解决问题的机会。我用驱动程序的版本11.2.0.4(ojdbc6.jar)测试了它。此外,如果您的数据库使用UTF-8编码,它似乎只适用于java.policy调整。就我而言,它是一个使用Windows 1252编码的数据库。

首先,oracle jdbc驱动程序需要进行一些安全性调整......最好是明确设置它们而不是permission java.security.AllPermission;。使用此权限,取自ocacle jdbc驱动程序下载页面(ojdbc.policy文件):

permission java.util.PropertyPermission "user.name", "read";
permission java.util.PropertyPermission "oracle.jdbc.*", "read";
permission java.util.PropertyPermission "oracle.net.wallet_location", "read";
permission java.util.PropertyPermission "oracle.net.tns_admin", "read";
permission javax.management.MBeanServerPermission "createMBeanServer";
permission javax.management.MBeanPermission "oracle.jdbc.driver.OracleDiagnosabilityMBean#[com.oracle.jdbc:type=diagnosability,*]", "registerMBean";
permission javax.management.MBeanTrustPermission "register";

完成此设置后,您将遇到Java.lang.ArrayIndexOutOfBoundsException: Array index out of range: -1问题。其根本原因是,java代理的类加载器(lotus.domino.AgentLoader)没有实现getResource(String name),这导致始终将null返回给调用方法。由于orcale jdbc驱动程序需要jar中oracle.sql.converter_xcharset文件夹中的glb文件才能正常工作并且它们是由上面提到的getRousource方法加载的,所以这不起作用!结果是ArrayIndexOutOfBoundsException。

因此,唯一的解决方案是使用文件系统中的驱动程序(并使用jvm默认类加载器),或者更改类加载过程,如下所示:

  1. 创建自定义类加载器: 公共类CustomLoader扩展了ClassLoader {

    private final AgentLoader loader;
    
    public CustomLoader(AgentLoader agentLoader, ClassLoader parent) {
        super(parent);
        loader = agentLoader;
    }
    
    @Override
    public URL getResource(String name) {
    
        InputStream is = loader.getResourceAsStream(name);
        if (is == null) {
            return super.getResource(name);
        }
    
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    
        try {
            URL url = new URL("dominoinmemory", "", -1, name, new DominoInMemoryStreamHandler(name));
            System.out.println(url);
            return url;
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    
    }
    
    private class DominoInMemoryStreamHandler extends URLStreamHandler {
    
        private String resName;
        byte[] content = null;
    
        public DominoInMemoryStreamHandler(String resName) {
            this.resName = resName;
        }
    
        @Override
        protected URLConnection openConnection(final URL u) throws IOException {
            if (!u.getProtocol().equals("dominoinmemory"))
                throw new IOException("Cannot handle protocol: " + u.getProtocol());
            InputStream is = loader.getResourceAsStream(resName);
            content = toByteArray(is);
    
            return new URLConnection(u) {
    
                @Override
                public int getContentLength() {
                    if (content != null) {
                        return content.length;
                    } else {
                        return super.getContentLength();
                    }
                }
    
                @Override
                public void connect() throws IOException {
                    if (content != null) {
                        connected = true;
                    } else {
                        throw new IOException("The resource '" + resName + "' was not found");
                    }
    
                }
    
                @Override
                public InputStream getInputStream() throws IOException {
                    return new ByteArrayInputStream(content);
                }
    
            };
        }
    
    }
    
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return output.toByteArray();
    }
    
  2. 在domino代理中,在发生任何其他操作之前,使用反射更改AgentLoader的父类加载器

    public void NotesMain() {
    
        try {
            AgentLoader agentLoader = (AgentLoader) getClass().getClassLoader();
            Field f1 = agentLoader.getClass().getSuperclass().getDeclaredField("parent");
            f1.setAccessible(true);
            ClassLoader parent = (ClassLoader) f1.get(agentLoader);
            f1.set(agentLoader, new CustomLoader(agentLoader, parent));
            ...
    
  3. 注意:

    • 使用此风险需要您自担风险!
    • 此代码在策略文件中需要两个附加条目:
      • permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
      • permission java.net.NetPermission "specifyStreamHandler";