Путаница по поводу разрешения классов в хранимых процедурах Oracle Java

Я пытаюсь использовать стороннюю библиотеку Java в Oracle. Библиотека кажется совместимой с той же версией jvm 1.4, что и наш сервер Oracle 10g, поскольку она отлично работает вне Oracle, поэтому я чувствую, что у меня должна получиться заставить ее работать. Эта библиотека в конечном итоге выполняет HTTP-запросы на основе SOAP, и при запуске в Oracle я получаю ошибки разрешения классов.

Вот строка, показывающая разницу:

Class msgfact = Class.forName("com.sun.xml.messaging.saaj.soap.MessageFactoryImpl");

Я попытался зарегистрировать эти библиотеки в Oracle с помощью утилиты loadjava и получил то, что считал успешным:

C:\>loadjava -verbose -schema MYUSER -user MYUSER/MYPWD@dbinstance -force saaj-impl.jar

Похоже, что все загружается, и я вижу этот класс MessageFactoryImpl в этом списке. Но затем я пытаюсь запустить эту строку кода из Oracle SQL (внутри другого класса, который я написал и загрузил с помощью loadjava), эта строка выдает исключение ClassNotFoundException (java.lang.ClassNotFoundException: com / sun / xml / messaging / saaj / soap / MessageFactoryImpl ).

Затем я вернулся и попытался добавить переключатель «-resolve» в командную строку loadjava. Это действует так, как будто эти классы saaj регистрируются, но они не разрешаются должным образом.

Как я могу успешно загрузить эти классы saaj в Oracle, или, если по какой-то причине Oracle уже загрузил их, как я могу убедить мой собственный код успешно использовать существующий класс?

FWIW, я уже предпринял шаги, чтобы убедиться, что предоставлены соответствующие разрешения для сокетов, и мой код может успешно выполнить общий HTTP-запрос на целевой URL-адрес. У него просто проблемы с использованием стека SOAP библиотеки, чтобы это произошло.

РЕДАКТИРОВАТЬ: Вот образец моего результата loadjava. Кажется, это показывает, что именно не удается, но я не понимаю, почему эти конкретные классы не разрешаются, когда кажется, что они обрабатываются должным образом на этапах предварительного разрешения. Я удалил здесь около 80% файла, но есть и другие классы, которые показывают те же проблемы с разрешением классов.

arguments: '-verbose' '-schema' 'MYSCHEMA' '-user' 'MYSCHEMA/MYSCHEMA@actest' '-resolve' '-force' 'saaj-impl.jar' 
[snip]
creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory
loading  : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory
creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler
loading  : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler
creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler
loading  : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler
creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
loading  : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl
loading  : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl
[snip]
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/AttachmentPartImpl
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/Envelope
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory
errors   : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory
    ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/SOAPPartImpl could not be resolved
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler
resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
errors   : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
    ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl could not be resolved
errors   : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl
    ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/impl/EnvelopeImpl could not be resolved
errors   : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl$1
    ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl could not be resolved
skipping : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl$2
[snip]
The following operations failed
    class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory: resolution
    class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl: resolution
    class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl: resolution
    class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl$1: resolution
[snip]
exiting  : Failures occurred during processing

person Chris Farmer    schedule 27.02.2009    source источник


Ответы (6)


Прежде всего, убедитесь вне Oracle, что искомый класс действительно находится в этом jar-файле. Думаю, да, но проверить не помешает.

Затем я проверял, какие классы были загружены и есть ли у них допустимые статусы.

SELECT object_name, dbms_java.longname(object_name), status
  FROM user_objects
  WHERE object_type='JAVA CLASS'
  ORDER BY 1

Возможно, вы захотите несколько ограничить это, если классов много, например:

WHERE dbms_java.longname(object_name) LIKE '%MessageFactoryImpl'

Если класса нет или он указан с неправильным именем пакета, проблема связана с командой loadjava.

Если класс существует, но его статус - НЕДЕЙСТВИТЕЛЬНЫЙ, проверьте USER_ERRORS, чтобы узнать, в чем заключаются ошибки. Я не помню, выполнял ли я динамическую загрузку классов в Oracle, но я помню, что статическая компоновка вызвала бы ошибки, которые подразумевали, что класс не существует, когда он действительно существовал, но имел ошибки.

Новая информация после публикации вывода loadjava

Вывод loadjava кажется несовместимым с вашей попыткой найти класс в базе данных. Если он загружается, но не решается, он все равно должен быть в списке, но со статусом НЕДЕЙСТВИТЕЛЬНЫЙ.

Я получил JAR и сам попробовал в пустой схеме. Класс загружается, но недействителен, как ожидалось:

dev> select object_name, dbms_java.longname(object_name),status
  2  from user_objects
  3  where object_name like '%MessageFactoryImpl';

OBJECT_NAME
--------------------------------------------------------------------------------
DBMS_JAVA.LONGNAME(OBJECT_NAME)
--------------------------------------------------------------------------------
STATUS
-------
/3e484eb0_MessageFactoryImpl
com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
INVALID

Затем я проверил, в чем была ошибка в классе:

dev> alter java class "com/sun/xml/messaging/saaj/soap/MessageFactoryImpl" resolve;
dev> /

Warning: Java altered with compilation errors.

dev> show error
Errors for JAVA CLASS "/3e484eb0_MessageFactoryImpl":

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      ORA-29521: referenced name javax/xml/soap/MessageFactory could
         not be found

0/0      ORA-29521: referenced name javax/xml/soap/SOAPMessage could not
         be found

0/0      ORA-29521: referenced name javax/xml/soap/MimeHeaders could not
         be found

0/0      ORA-29521: referenced name javax/xml/soap/SOAPException could not
         be found

(Эти ошибки также будут перечислены в USER_ERRORS, при условии, что разрешение было предпринято хотя бы один раз.)

Итак, ясно, что этот класс ссылается на классы из базовой библиотеки SOAP. Вам тоже придется загрузить это - вы это сделали?

К вашему сведению, когда я пишу код для вызова Class.forName (), я получаю ClassNotFoundException. Что может показаться нелогичным, поскольку объект класса действительно существует в схеме. Однако недопустимый класс на самом деле «не существует» с точки зрения загрузчика классов в Oracle; и для того, чтобы класс был допустимым, Oracle должен иметь возможность разрешать все свои ссылки на другие классы.

person Dave Costa    schedule 02.03.2009
comment
Файл saaj-impl.jar действительно содержит класс com.sun.xml.messaging.saaj.soap.MessageFactoryImpl. Спасибо за использование функции длинного имени. Я не мог понять, как вернуть эти полные имена! В моем экземпляре Oracle нет классов longname, которые похожи на "% MessageFactory%". - person Chris Farmer; 03.03.2009
comment
Итак, кажется довольно очевидным, что loadjava не делает то, что я хочу. У вас есть идеи, как я могу отладить это использование? - person Chris Farmer; 03.03.2009
comment
Я ожидал, что подробный вывод loadjava будет содержать хоть какое-то указание. Можете ли вы опубликовать репрезентативный образец продукции? - person Dave Costa; 03.03.2009
comment
Отредактированный ответ. На данный момент я предполагаю, что вы не загрузили другие jar-файлы, содержащие классы, на которые ссылаются классы SAAJ. - person Dave Costa; 03.03.2009

Вы впервые запускаете Java в базе данных? Вот реализация hello world, чтобы убедиться, что ваша Oracle JVM работает правильно и у вас есть необходимые разрешения. Вы сказали: «Моя схема базы данных, поэтому я могу делать все, что захочу» - это не значит, что у вас есть надлежащие гранты.

SQL> create or replace and compile java source named "Hello" as 
   public class Hello{ 
      public static String world() { 
         return "Hello World "; 
      } 
   }; 
/ 

Java created. 

Теперь функция-оболочка

SQL> create or replace function Hello RETURN VARCHAR2 
     as LANGUAGE JAVA NAME 'Hello.world() return String'; 
     / 

Function created.

Теперь проверьте это

SQL> select Hello from dual; 

HELLO 
----------------------------------- 
Hello World 
person Brian    schedule 07.03.2009
comment
О, я могу использовать и другие методы. Я попытался сказать это в своем сообщении, когда сказал, что могу получить доступ к целевому URL-адресу через http. Это в моем классе Java, работающем в Oracle. Это мой привет, мир. - person Chris Farmer; 07.03.2009

Сделай это:

try
{
    System.out.println("Class.forName returned: " + 
        Class.forName("com.sun.xml.messaging.saaj.soap.MessageFactoryImpl"));
}
catch(final Throwable ex)
{
    ex.printStackTrace();
    System.exit(1);
}

Просто чтобы быть на 100 и 10% уверенным, что он не генерирует исключение, которое каким-то образом скрывается, и что оно действительно возвращает null. Если это все еще так, дайте мне знать (интересная проблема, если приведенный выше код работает, но возвращает null).

person TofuBeer    schedule 28.02.2009
comment
Блин. Моя ошибка. Строка Class.forName (com.sun.yada.yada ..) выдает исключение: java.lang.ClassNotFoundException: com / sun / xml / messaging / saaj / soap / MessageFactoryImpl - person Chris Farmer; 02.03.2009

Попробуйте №3 :-) (я не использую Oracle ... но это отличная проблема для отладки ...)

Помогает ли информация о Class.forName в Oracle?

http://download.oracle.com/docs/cd/B14117_01/java.101/b12021/appover.htm#i1006547

Это представляет собой проблему ClassLoader, поэтому, надеюсь, решение будет таким же, как и в «реальном, не-Oracle» мире :-)

Изменить ... еще одна попытка ...

Хорошо, посмотрим на это еще ... каков результат следующего:

System.out.println("vm vendor:     " + System.getProperty("java.vendor"));
System.out.println("vm version:    " + System.getProperty("java.version"));
System.out.println("class version: " + System.getProperty("java.class.version"));

Мне интересно, есть ли проблема с версией файла класса - есть ли у файлов классов версия, которая не может быть запущена на виртуальной машине Oracle?

person TofuBeer    schedule 02.03.2009
comment
Да, это моя схема базы данных, поэтому я могу делать все, что хочу. Проблема в том, что я не обязательно знаю, что делаю! - person Chris Farmer; 03.03.2009

Разрешение и загрузка классов - это сложные операции, выполняемые виртуальной машиной. Алгоритм, который будет использоваться этими двумя операциями, как описано в спецификации, оставлен открытым для разработчиков VM. Я чувствую, что в вашем случае разрешение работает, поскольку операция проверяет только доступность самого класса, в то время как позже она терпит неудачу при попытке эффективно загрузить класс (скорее всего, из-за отсутствия зависимостей: при загрузке класса виртуальной машине требуется разрешить хотя бы все прямые ссылки на другие классы). Вам нужно будет убедиться, что все классы доступны для Oracle, и выполнение быстрого поиска в Google для ORA-29534 показывает, что эта проблема возникает у множества людей (и я почти уверен, что кто-то ее понял).

./Алекс

person alexpopescu    schedule 08.03.2009

Saaj-impl.jar является частью компонента SAAJ пакета разработчика веб-служб. У него есть зависимости от других JAR, которые поставляются с SAAJ, например, он определенно зависит от saaj-api.jar и Activation.jar, насколько мне известно. Конечно, saaj-api.jar обязательно зависит и от множества других JAR.

Что касается JWSDP 1.5, вы можете найти информацию в Примечания к выпуску JWSDP 1.5 быть полезным. JWSDP 1.6 имеет разные JAR-файлы в SAAJ. Я не нашел, что примечания к выпуску JWSDP 2.0 особенно полезны в этом отношении. Кстати, JWSDP 2.0 будет иметь разные JAR, которые нужно разместить в пути к классам; поэтому масштаб вашей проблемы в конечном итоге зависит от версии saaj-impl.jar, которую вы используете.

На случай, если вам это может понадобиться, на следующих страницах уже доступна некоторая документация о том, как загрузить клиентские JAR-файлы SOAP в базу данных Oracle и использовать их. Я полагаю, что они отличаются от файлов SAAJ JAR, которые поставляются с вашей библиотекой.

person Vineet Reynolds    schedule 08.03.2009