Содержание


Интегрирование COM и Java-компонентов

Достижение возможности взаимодействия при помощи Development Tool for Java-COM Bridge

Серия контента:

Этот контент является частью # из серии # статей: Интегрирование COM и Java-компонентов

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Интегрирование COM и Java-компонентов

Следите за выходом новых статей этой серии.

По мере роста требований и сложности процессов в организации может наступить необходимость комбинирования приложений и компонентов, реализованных на различных базовых технологиях, в одно единое интегрированное решение. Технологии Java и COM играли главенствующие роли в разработке крупномасштабных приложений и компонентов для платформы Windows, в то время как до сих пор взаимодействие между этими двумя технологиями (т.н. "бриджинг") оставалось, в основном, не решаемым вопросом в мире интеграции. В последние годы появилось несколько инструментальных средств, позволяющих поверхностные "облегченные" (lightweight) взаимодействия между Java-компонентами и COM-компонентами. Однако некоторые из этих средств имеют очень ограниченную применимость, например такие, которые поддерживают перенос только из Java-компонент в COM (т.е. вызывающих методы COM-сервера из Java-кода). В универсальных же средствах переноса проявляется большая потеря производительности при интенсивных вычислениях.

Эта статья знакомит с технологией переноса, балансирующей между производительностью и применимостью. IBM Rational Java-COM Bridge (RJCB) не только поддерживает перенос данных из Java-компонент в COM, но и из COM в Java-компоненты посредством "мостов". Программа для построения RJCB-"мостов" (the Development Tool for Java-COM Bridge (DTJCB)) интегрируется с IDE Eclipse, распространяемой с открытыми исходными кодами (см. вставку DTJCB как расширение Eclipse), облегчая создание и использование "мостов" в Java-среде. Вы можете также использовать средства Microsoft для переноса данных из COM-компонентов в Java-компоненты при помощи созданных в DTJCB-"мостов".

DTJCB предоставляет также пошаговую методику переноса широкомасштабных COM-приложений на платформу Java. Вместо полной модернизации приложения за одну ночь он позволяет вам выполнять перенос компонент за компонентом, оставляя приложение доступным для использования, и поддерживать эту доступность с минимальными потерями.

Понимание технологии RJCB

Технология RJCB использует среду Java Native Interface (JNI) для взаимодействия Java-кода и COM-кода. JNI позволяет вам вызывать “родной” код в языке Java и наоборот. Вы можете объявить метод в языке Java и определить тело метода в C или C++. И наоборот, вы можете вызвать методы Java из C или C++ кода.

Рисунок 1 демонстрирует структуру “моста” RJCB.

Рисунок 1. Структура "моста" RJCB
Структура "моста" RJCB
Структура

Зеленые прямоугольники на рисунке 1 представляют файлы RJCBRT.jar и RJCBRT.dll, находящиеся в установочном пакете RJCB. Они предоставляют поддерживающие классы и службы, используемые сгенерированным кодом “моста” (и, с ограничениями, вашим Java-кодом). Красные прямоугольники представляют код, созданный генератором “моста” RJCB и являются специфичными для конкретного COM API.

Каждый COM API описывается специальным файлом, называемым библиотекой типов (type library). Автономная библиотека типов обычно имеет расширение .tlb. Библиотеки типов могут быть также встроены внутри исполняемого файла (.exe, .dll, и .ocx). Генератор “моста” RJCB читает библиотеку типов и генерирует код “моста” на Java и С++, основываясь на API, описанном в этой библиотеке.

COM-интерфейсы обычно предоставляют два различных механизма вызова методов: позднее связывание и раннее связывание. Использование позднего связывания требует разрешения названий методов на этапе выполнения и пакетирования (депакетирования) всех параметров методов в(из) специальный массив значений, имеющих тип variant. Раннее связывание обладает тем преимуществом, что точно известно, какой метод вызывается и какой тип имеют его параметры. Для внутрипроцессного (in-process) COM-сервера (при работе в пространстве имен COM-сервера) механизм раннего связывания эквивалентен вызову vtable в C++ (стандартному механизму вызова виртуального метода C++).

Механизм позднего связывания обеспечивается реализацией специального супер-интерфейса с названием IDispatch. Интерфейс IDispatch предоставляет метод для поиска методов COM-интерфейса (или свойств) по названию, который возвращает идентификатор dispid найденного метода. Интерфейс IDispatch предоставляет также еще один метод для вызова COM-метода по его dispid и массиву значений variant, содержащему параметры вызова. Вызов COM-методов посредством интерфейса IDispatch очень неэффективен по сравнению с простым вызовом C++ vtable (даже если вы избегаете применения позднего связывания IDispatch и пользуетесь только вызовом методов с указанием их идентификаторов dispid).

Главной мотивацией разработки технологии RJCB являлась реализация быстрого (насколько это возможно), переноса данных между Java и COM. Мы использовали некоторые API для переноса большого объема данных между Java и COM, и нашей задачей была наивысшая производительность нашей технологии. По этой причине в RJCB поддерживается только COM API с интерфейсами vtable раннего связывания. Сгенерированный RJCB-код использует прямые интерфейсно зависимые вызовы vtable. Суперинтерфейс IDispatch не используется.

В RJCB генератор кода производит прокси-процедуры Java для каждого интерфейсаvtable и coclass, определенного в библиотеке типов COM. Он также генерирует Java-модули, содержащие константы и литералы enum, определенные в библиотеке типов.

Изучение примера кода переноса данных

В целях демонстрации рассмотрим код переноса данных, сгенерированный для простого примера COM API. В этом примере объявлен один модуль с несколькими константами, один тип enum с несколькими литералами enum, один интерфейс с единственным свойством Name и один класс coclass, реализующий один интерфейс. (Реальные COM API содержат намного большее число интерфейсов, каждый из которых имеет много методов и свойств.)

В листинге 1 приведена простая спецификация COM API Interface Definition Language (IDL):

Листинг 1. IDL-спецификация для SimpleTestModule
module SimpleTestModule
{
    static const int SIMPLETEST_INT_CONST = 99;
    static const LPCOLESTR SIMPLETEST_STRING_CONST = L"This is a test.";
};


typedef [public] enum SimpleTestEnum {
    STE_VALUE1 =  0,
    STE_VALUE2 =  1,
    STE_VALUE3 =  2
} SimpleTestEnum;


[
    object,
    uuid(1C551D4C-B3D8-4BCA-BDC0-6D870D84CA7F),
    helpstring("ISimpleTest Interface"),
    dual,
    pointer_default(unique)
]
interface ISimpleTest : IDispatch
{
    [propget, helpstring("property Name"), id(1)]
    HRESULT Name([out, retval] BSTR* theName);

    [propput, helpstring("property Name"), id(1)]
    HRESULT Name([in] BSTR theName);
};


[
    uuid(14CED841-ED27-4450-9255-FE384C6C3B0D),
    helpstring("SimpleTest Class")
]
coclass SimpleTest
{
    [default] interface ISimpleTest;
};

Соответствующие файлы с исходным кодом Java, производимые генератором кода RJCB, приведены в листингах 2 и 3:

Листинг 2. SimpleTestModule.java
package com.ibm.simpletest;

public interface SimpleTestModule {

    public static final int SIMPLETEST_INT_CONST = 99;
    public static final String SIMPLETEST_STRING_CONST = "This is a test.";

}
Листинг 3. SimpleTestEnum.java
package com.ibm.simpletest;

public interface SimpleTestEnum {

    public static final int STE_VALUE1 = 0;
    public static final int STE_VALUE2 = 1;
    public static final int STE_VALUE3 = 2;

}

Для интерфейсов генерируется три различных Java-файла. Один файл содержит Java-эквивалент интерфейса и приведен в листинге 4:

Лиситнг 4. ISimpleTest.java
package com.ibm.simpletest;

public interface ISimpleTest {


    public static final String IID = "1C551D4C-B3D8-4BCA-BDC0-6D870D84CA7F";
    public static final Class BRIDGECLASS = SimpleTestBridgeObjectProxy.class;
    public static final String CLSID = "7B422507-1B5B-49F7-BCEF-0FDE519C621A";

    /** 
     * getName. property Name
     */
    public String getName() throws java.io.IOException;

    /** 
     * setName. property Name
     */
    public void setName(String theName) throws java.io.IOException;

}

Второй файл содержит JNI-объявления для каждого метода в интерфейсе. Его содержимое показано в листинге 5:

Листинг 5. ISimpleTestJNI.java
packagecom.ibm.simpletest;

public class ISimpleTestJNI {

    public static native String getName(long native_this) throws java.io.IOException;

    public static native void setName(long native_this, String theName)
     throws java.io.IOException;

}

Третий файл содержит прокси-класс Java, реализующий интерфейс путем вызова JNI-методов. Прокси-класс содержит также ссылку на представляемый им реальный COM-объект в переменной класса native_object (определенной во вспомогательном классе superclass, который расширяют все прокси-классы). В листинге 6 приведен файл прокси-класса Java:

Листинг 6. ISimpleTestProxy.java
packagecom.ibm.simpletest;

public class ISimpleTestProxy extends SimpleTestBridgeObjectProxy
 implements ISimpleTest {

    protected ISimpleTestProxy(String clsid, String iid)
     throws java.io.IOException
    {
        super(clsid, iid);
    }

    public ISimpleTestProxy(String clsid, String dumb1, Object dumb2)
     throws java.io.IOException
    {
        super(clsid, ISimpleTest.IID);
    }

    public ISimpleTestProxy(long native_object)
    {
        super(native_object);
    }

    public ISimpleTestProxy(Object com_proxy_object)
     throws java.io.IOException
    {
        super(com_proxy_object, ISimpleTest.IID);
    }

    protected ISimpleTestProxy(Object com_proxy_object, String iid)
     throws java.io.IOException
    {
        super(com_proxy_object, iid);
    }

    // Методы ISimpleTest 

    public String getName() throws java.io.IOException
    {
        String theName = ISimpleTestJNI.getName(native_object);
        return theName;
    }

    public void setName(String theName) throws java.io.IOException
    {
        ISimpleTestJNI.setName(native_object, theName);
    }

}

Для класса coclass генерируется один прокси-класс Java с названием SimpleTest. В листинге 7 показан файл SimpleTest.java:

Листинг 7. SimpleTest.java
packagecom.ibm.simpletest;

public class SimpleTest extends ISimpleTestProxy {

    public static final String CLSID = 
    "14CED841-ED27-4450-9255-FE384C6C3B0D";

    public SimpleTest(long native_object)
    {
        super(native_object);
    }

    public SimpleTest(Object com_proxy_object)
     throws java.io.IOException
    {
        super(com_proxy_object, ISimpleTest.IID);
    }

    public SimpleTest() throws java.io.IOException
    {
        super(CLSID, ISimpleTest.IID);
    }

}

Прокси-класс Java coclass расширяет прокси-класс своего интерфейса по умолчанию. Если он реализует также дополнительные интерфейсы, то он содержит реализации этих дополнительных интерфейсов (аналогично прокси-интерфейсу).

Прокси-класс coclass содержит также конструктор по умолчанию, не имеющий параметров для создания экземпляра COM-объекта, который он представляет. Конструктор создает экземпляр COM-объекта при помощи CLSID, указанного в объявлении coclass в библиотеке типов.

Тело "родных" (native) методов, объявленных в ISimpleTestJNI.java, находится в ISimpleTestJNI.cpp, что показано в листинге 8:

Листинг 8. ISimpleTestJNI.cpp
JNIEXPORT jstring JNICALL 
Java_com_ibm_simpletest_ISimpleTestJNI_getName(
    JNIEnv* env, jclass,
    jlong native_this)
{
    SimpleTestLib::ISimpleTest* this_intf = 
    (SimpleTestLib::ISimpleTest*)native_this;
    CComBSTR nativeTheName;
    CHRT(this_intf->get_Name(&nativeTheName));
    return JSTRING_FROM_CCOMBSTR
    (env, nativeTheName);
}

JNIEXPORT void JNICALL 
Java_com_ibm_simpletest_ISimpleTestJNI_setName(
    JNIEnv* env, jclass,
    jlong native_this, jstring theName)
{
    SimpleTestLib::ISimpleTest* 
    this_intf = (SimpleTestLib::ISimpleTest*)native_this;
    BSTR_FROM_JSTRING nativeTheName(env, theName);
    CHRTV(this_intf->put_Name(nativeTheName));
}

Как видно из листинга 8, методы просто вызывают соответствующий COM-метод через указатель COM-интерфейса, производя все необходимые преобразования параметров (такие как преобразование между строковыми представлениями в Java и COM). Код также заботится о трансляции возвращаемых кодов ошибок COM в исключительные ситуации языка Java (посредством макросов CHRT*).

Для двунаправленных "мостов", в которых вы указали генератору переноса данных RJCB, что определенные интерфейсы в COM API реализуются на языке Java, генерируются два дополнительных файла на языке С++, предоставляющие COM-прокси для этих Java-реализаций COM-интерфейсов. COM-прокси в основном аналогичен Java-прокси, только действует наоборот. Он содержит ссылку на представляемый им Java-объект в переменной экземпляра класса.

В нашем простом примере файлы COM-прокси для интерфейса ISimpleTest называются ISimpleTestProxy.h и ISimpleTestProxy.cpp. Эти файлы читать немного тяжелее из-за сложностей программирования COM в C++. В листинге 9 приведен фрагмент файла ISimpleTestProxy.cpp:

Листинг 9. Фрагмент кода в ISimpleTestProxy.cpp
STDMETHODIMP ISimpleTestProxy::get_Name(BSTR* theName)
{
    JNIEnv* env = 0;
    jobject java_object;

    CHRR(_RJCBService->GetJavaObject
    (this, &env, &java_object));
    JNILocalFrame _JNILocalFrame(env);
    if (theName == 0) {
        return E_INVALIDARG;
    }
    jstring jniTheName = 
    (jstring)env->CallObjectMethod(java_object, _ISimpleTestProxyInfo->
      m_getName_method_id);
    *theName = BSTR_FROM_JSTRING(env, jniTheName).Detach();
    return _RJCBService->CatchException(env);
}

STDMETHODIMP ISimpleTestProxy::put_Name(BSTR theName)
{
    JNIEnv* env = 0;
    jobject java_object;
    CHRR(_RJCBService->GetJavaObject
    (this, &env, &java_object));
    JNILocalFrame _JNILocalFrame(env);
    env->CallVoidMethod(java_object, _ISimpleTestProxyInfo->
      m_setName_method_id, JSTRING_FROM_BSTR(env, theName));
    return _RJCBService->CatchException(env);
}

Обратите внимание, что методы в листинге 9 просто вызывают соответствующий Java-метод через представленный в прокси Java-объект, производя все необходимые преобразования параметров (такие как преобразование между строковыми представлениями в Java и COM). Код также заботится о трансляции исключительных ситуаций языка Java в коды ошибок, возвращаемых в COM.

Использование DTJCB: Обзор

Для использования технологии RJCB с DTJCB нужно создать и скомпоновать "мост" для компонента "сервер" и добавить код в компонент "клиент", обращающийся к "серверу" при помощи "моста". DTJCB дает возможность выполнить этот процесс внутри одной среды.

Вы начинаете с серверного компонента, созданного в COM или Java, затем создаете "мост" в проекте RJCB, используя среду Eclipse. Конечный проект дополняется прокси-кодом "моста", сгенерированным на Java и Visual C++, и используемой этим прокси-кодом библиотекой времени исполнения. Затем вы используете в Eclipse стандартную команду Build для компоновки всех кусочков нашего "моста".

При обращении к COM-серверу из Java-клиента можно продолжать работу в Eclipse для создания Java-проекта. Вы добавляете Java-код клиентской программы, взаимодействующей с прокси "моста", который в свою очередь обращается к COM-серверу через библиотеку времени исполнения, реализующую "мост". Использование DTJCB в Eclipse позволяет работать с начала до конца, от создания "моста" до фактического вызова его методов.

При обращении к Java-серверу из COM-клиента вы сначала регистрируете Java-сервер в системе Microsoft Windows, чтобы он был представлен COM-среде. Затем вы можете использовать поддерживающее технологию COM средство разработки, например Visual C++ или Visual Basic из Microsoft Visual Studio, для написания клиентского кода, обращающегося к Java-серверу через "мост". Мы проиллюстрируем этот процесс некоторыми примерами в следующих разделах.

Разработка COM-клиента на Java при помощи DTJCB

Рассмотрим процесс создания "моста" для COM-сервера в DLL-файле, служащего для экспонирования его интерфейса для Java-технологии и для вызова этого интерфейса из Java-клиента. Возьмем для примера магазин офисной фурнитуры, в котором применяется COM-сервер для отслеживания товаров. Этот COM-интерфейс отображается из файла OfficeFurniture.dll. Нам хотелось бы передать информацию о товарах из COM-сервера в клиентское Java-приложение.

Создание проекта "моста" RJCB

Для начала процесса создания "моста" выберите пункт Java-COM Bridge Project в мастере Eclipse New Project, как показано на рисунке 2.

Рисунок 2. Мастер New Project
Мастер New Project
Мастер New Project

Нажатие на кнопку Next вызовет появление страницы New Java-COM Bridge Project, где указываются название и месторасположение проекта (см. рисунок 3).

Рисунок 3. Страница New Java-COM Bridge Project
Страница New Java-COM Bridge Project
Страница New Java-COM Bridge Project

На следующей странице показываются "мосты", находящиеся в данный момент времени в проекте (если они есть). Для нашего нового проекта эта страница пуста (см. рисунок 4).

Рисунок 4.Страница содержимого Java-COM Bridge Project
Страница содержимого Java-COM Bridge Project
Страница содержимого Java-COM Bridge Project

Нажмите кнопку Add... для вызова страницы Java-COM Bridge Settings, на которой вы предоставляете информацию о COM-сервере и создаваемом "мосте". Вы придумываете название "моста", в качестве исходной библиотеки типов указываете COM-сервер и вводите название Java-пакета для доступа из Java-кода. (Дополнительные настройки и информацию вы можете найти в средстве разработки самостоятельно.)

Рисунок 5. Станица Java-COM Bridge Settings
Станица Java-COM Bridge Settings
Станица Java-COM Bridge Settings

Если вы удовлетворены настройками создаваемого "моста", нажмите кнопку OK. Название "моста" появится на странице содержания проекта, как показано на рисунке 6.

Рисунок 6. Страница содержания Java-COM Bridge Project
Страница содержания Java-COM Bridge Project
Страница содержания Java-COM Bridge Project

После нажатия кнопки Finish мастера вы можете заметить, что вид Package Explorer в перспективе Eclipse Java Perspective расширен прокси-кодом "моста", написанном на языках Java и Visual C++, как показано на рисунке 7.

Рисунок 7. Сгенерированные файлы в Package Explorer
Сгенерированные файлы в Package Explorer
Сгенерированные файлы в Package Explorer

Компоновка проекта "моста" RJCB

После генерирования прокси-кода "моста" можно приступить к его компоновке при помощи стандартного меню build в Eclipse. Обратите внимание, что код "моста" зависит от JDK (не только JRE) и Microsoft Visual C++ 6.0 (Service Pack 5), так что убедитесь в их присутствии в системе.

Eclipse поддерживает как автоматический, так и ручной режим компоновки, оба из которых могут скомпоновать необходимые бинарные файлы для "моста". В нашем примере компоновщик генерирует файлы OfficeFurnitureBridge.dll и OfficeFurnitureBridge.jar.

"Мост" готов к использованию. Можно открыть Java-файл прокси для того, чтобы увидеть, какой интерфейс можно использовать. Например, на рисунке 8 изображены методы интерфейса OfficeFurniture.dll, которые вы можете использовать в языке программирования Java.

Рисунок 8. Методы интерфейса для работы с "мостом"
Методы интерфейса для работы с "мостом"
Методы интерфейса для работы с

Создание Java-проекта в виде COM-клиента

Следуя обычному процессу разработки Java-кода в Eclipse, вы можете легко создать Java-проект и написать некоторый код для доступа к интерфейсу. Начните с использования мастера New Project, как показано на рисунке 9.

Рисунок 9. Мастер New Project
Мастер New Project
Мастер New Project

На следующей странице укажите название Java-проекта (рисунок 10).

Рисунок 10. Страница New Java Project
Страница New Java Project
Страница New Java Project

Затем, на следующей странице Java Settings нужно указать зависимости проектов и библиотек на соответствующих закладках страницы, как показано на рисунках 11 и 12.

Рисунок 11. Настройка Project dependency
Настройка Project dependency
Настройка Project dependency
Рисунок 12. Настройка Library dependency
Настройка Library dependency
Настройка Library dependency

После нажатия кнопки Finish Eclipse создаст новый Java-проект. Теперь вы можете увидеть оба проекта («мост» и Java) в Package Explorer, как показано на рисунке 13.

Рисунок 13. Проект "моста" и Java-проект в Package Explorer
Проект "моста" и Java-проект в Package Explorer
Проект

Использование проекта "моста" RJCB из клиентской программы

Самое время добавить Java-код для вызова интерфейса COM-сервера. При помощи стандартной команды New Java class в Eclipse сначала добавьте новый класс в только что созданный Java-проект, как показано на рисунке 14.

Рисунок 14. Добавление нового Java-класса
Добавление нового Java-класса
Добавление нового Java-класса

Добавьте Java-код для обращения к интерфейсу COM-сервера, экспонируемому через "мост". Прежде всего, добавьте фрагмент кода в листинге 10 в тело метода main() класса Test:

Листинг 10. Новый код для метода main()
int count = 0;
try {
// Загрузка библиотеки RJCB Runtime 
com.ibm.rjcb.RJCBUtilities.loadRJCB
  ("C:\\eclipse\\plugins\\
  com.ibm.rjcb.dtk.common_1.0.0\\RJCBRT.dll");
// Загрузка Bridge dll
string dll_location = "C:\\eclipse\\workspace\\"
+ "SampleBridgeProject\\MyJ2CBridge\\"
+ "c++\\OfficeFurnitureBridge\\
Release\\OfficeFurnitureBridge.dll";
System.load(dll_location);
// Доступ к COM-объекту при помощи "моста"
IOfficeCatalog catalog = new OfficeCatalog();
count = catalog.Count();
System.out.println("count = " + count);
for (int index = 0; index < count; index++) {
System.out.println("item=" + index
+ " ID=" + catalog.GetID(index)
+ " Name=" + catalog.GetName(index));
}
} catch (java.io.IOException e) {
e.printStackTrace();
}

В листинге 10 catalog - это прокси-объект реального COM-сервера. Вы можете вызывать его методы. Вы можете затем использовать контекстное меню класса Organize Imports. Eclipse автоматически добавляет операторы импорта в класс, как показано в листинге 11:

Листинг Listing 11. Автоматическое добавление imports в Eclipse
import com.officefurniture.IOfficeCatalog;
import com.officefurniture.OfficeCatalog;

Опять используйте команду Build для компоновки Java-проекта и установите настройку Run так, как показано на рисунке 11.

Рисунок 15. Диалог конфигурирования Run
Диалог конфигурирования Run
Диалог конфигурирования Run

Результат работы программы Java-клиента отображается в окне Output, как показано на рисунке 16.

Рисунок 16. Результаты работы в окне Output
Результаты работы в окне Output
Результаты работы в окне Output

Здорово, не так ли? Вы создали Java-код, взаимодействующий с COM-сервером.

Разработка Java COM server

А сейчас рассмотрим, как определить интерфейс для реализации на стороне Java, который экспонируется через "мост" в COM, и как вызвать этот интерфейс из COM-клиента. Мы будем использовать интерфейс ICookie для иллюстрации необходимых действий. В листинге 12 показана IDL-спецификация этого интерфейса:

Листинг 12. IDL-спецификация для ICookie
import"oaidl.idl";
import "ocidl.idl";

[
object,
uuid(364DC55D-9C03-4dc6-AD82-5CAC8F1077FF),
dual,
helpstring("ICookie Interface"),
pointer_default(unique)
]
interface ICookie : IDispatch
{
[id(1), helpstring("method GetModel")] 
HRESULT GetName([retval, out] BSTR *name);

[id(2), helpstring("method GetModel")] 
HRESULT GetKind([retval, out] BSTR *name);
};

[
uuid(658EEF6A-D9C9-4a06-870D-2FA8A31A3026),
version(1.0),
helpstring("COM to Java test 1.0 Type Library")
]
library CookieLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");

[
uuid(F0E00502-16E2-43e2-B12C-02EE037C402B),
helpstring("Cookie Class")
]
coclass Cookie
{
[default] interface ICookie;
};
};

Создание проекта "моста" RJCB

DTJCB поддерживает создание "моста" из библиотеки типов. Трюк заключается в предварительном использовании компилятора Microsoft MIDL с IDL-спецификацией, приведенной в листинге 12, для создания библиотеки типов, которую мы назовем cookie.tlb.

Этапы создания проекта "моста" RJCB из библиотеки типов аналогичны этапам, описанным в предыдущем разделе "Разработка COM-клиента на Java при помощи DTJCB", за исключением спецификации настроек "моста". Назовем этот проект "моста" SampleBridgeProject2. Установите настройки "моста" так, как показано на рисунке 17.

Рисунок 17. Настройки "моста" для MyC2JBridge
Настройки "моста" для MyC2JBridge
Настройки

Обратите внимание на отличия настроек на рисунках 17 и 5. Исходной библиотекой является файл с расширением .tlb, а не .dll. Это служит указанием для TJCB о том, что "мост" создается для Java-компонента, а не для COM-сервера. ICookie также отмечен флажком возле поля "Java implemented interfaces".

Дальнейшие действия практически такие же, как и в предыдущем случае. В конце процесса создания "моста" вы можете увидеть проект "моста" и Java-прокси для интерфейса (Icookie.java), как показано на рисунке 18.

Рисунок 18. Проект "моста" для SampleBridgeProject2
Проект "моста" для SampleBridgeProject2
Проект

Теперь можно написать Java-класс, реализующий интерфейс ICookie, для вызова кода сервера. Для упрощения примера мы просто добавим новый класс, методы которого возвращают простые данные. Используйте стандартный механизм Eclipse для добавления класса при помощи мастера нового класса, как показано на рисунке 19.

Рисунок 19. Новый класс MyCookie
Новый класс MyCookie
Новый класс MyCookie

Простые реализации двух методов приведены в листинге 13:

Листинг 13. Реализации для GetName и GetKind
public class MyCookie implements ICookie {

/* (non-Javadoc)
* @see com.Cookie.ICookie#GetName()
*/
public String GetName() throws IOException {
return "Butter-n-Sweet";
}

/* (non-Javadoc)
* @see com.Cookie.ICookie#GetKind()
*/
public String GetKind() throws IOException {
return "Buttermilk";
}
}

Компоновка проекта "моста" RJCB

Проект готов для компоновки. Опять же, поскольку DTJCB интегрирован с Eclipse, вы можете использовать стандартную команду Eclipse Build.

Регистрация Java COM-сервера

Технология COM тесно связана с системным реестром Windows. Поэтому необходимо убедиться, что соответствующие компоненты зарегистрированы корректно, включая:

  • DLL-файл "моста", сгенерированный DTJCB
  • JVM, на которой будет выполняться "мост", вместе с корректным classpath
  • Java-класс, реализующий интерфейс и ID программы
  • DLL-файл библиотеки времени исполнения для RJCB

Все эти компоненты можно зарегистрировать при помощи команды Windows regsvr32.exe и команд registerJavaVM.exe и registerJavaClass.exe, поддерживаемых в DTJCB. После регистрации всех компонентов их можно использовать для работы с COM-клиентом.

Использование RJCB в проекте COM-клиента

Клиентскую COM-программу можно создать различными способами. Для нашего упражнения рассмотрим использование Visual Basic 6.0 в Microsoft Visual Studio. Сначала создайте новый стандартный EXE-проект и добавьте ссылку на файл cookie.tlb, используя команду Project/References. На рисунке 20 изображено диалоговое окно References, которое появляется после выполнения этой команды, а также показано, как можно добавить ссылку.

Рисунок 20. Добавление ссылки в проект
Добавление ссылки в проект
Добавление ссылки в проект

Добавьте кнопку Command в форму, как показано на рисунке 21.

Рисунок 21. Кнопка Command в форме
Кнопка Command в форме
Кнопка Command в форме

Затем добавьте код вызова для извлечения информации из Java-класса. На рисунке 22 показан код, выполняющийся при нажатии пользователем кнопки Command1.

Рисунок 22. Код, выполняющийся при нажатии кнопки Command
Код, выполняющийся при нажатии кнопки Command
Код, выполняющийся при нажатии кнопки Command

Обратите внимание, что код создает экземпляр объекта Cookie и вызывает его методы через "мост" явным способом. В результате выполнения этой программы, после нажатия пользователем кнопки Command1, появляется информационное окно с информацией, полученной из Java-класса. См. рисунок 23.

Рисунок 23. Результат работы программы - информационное окно
Результат работы программы - информационное окно

Использование автономного RJCB

Применение Eclipse для создания RJCB-"мостов" не является обязательным. RJCB поставляется со своими собственными автономными инструментами, которые можно использовать для генерации приложений "мостов". Для их работы можно использовать любую Java-среду разработки.

Полный набор двоичных файлов RJCB располагается в каталоге com.ibm.rjcb.dtk.ui_1.0.0\generator установленного DTJCB.

Для создания RJCB-"моста" не в Eclipse запустите программу bin\generateBridge.exe tool в графическом (Graphical User Interface) режиме (т.е., без аргументов командной строки). Появится окно, такое же как и при работе в DTJCB, в котором можно указать исходную библиотеку типов, целевую папку, название Java-пакета и т.п. Затем вы можете нажать кнопку Generate или Build для генерирования или генерирования/компоновки "моста".

Программу generateBridge можно запустить также и в пакетном режиме, используя аргументы командной строки. (Именно так эта программа вызывается в интегрированной среде DTJCB Eclipse). Для получения справки по использованию аргументов командной строки выполните программу с аргументом /?. Наилучшим способом определить, с какими аргументами нужно генерировать приложение в пакетном режиме, является запуск программы generateBridge сначала в GUI-режиме. При этом создастся файл с названием generatebridgename.bat, в котором содержится вызов generateBridge для пакетного использования со всеми необходимыми аргументами, соответствующими значениям, указанным вами в полях и настройках в графическом режиме. Этот файл создается каждый раз при нажатии кнопки Generate или Build.

Принимая во внимание, что Eclipse является передовой средой разработки Java-приложений, доступной бесплатно (см. раздел "Ресурсы"), мы настоятельно рекомендуем ее использование совместно с DTJCB для разработки ваших приложений "мостов" (см. вкладыш "DTJCB как расширение Eclipse"). Такая интеграция с Eclipse предоставляет наилучшее решение по типу "все в одном".

Развертывание RJCB-”моста”

RJCB-”мост” можно развернуть несколькими способами в зависимости от природы программы-клиента, которая будет использовать “мост”. Клиентское приложение может быть автономным приложением, подключаемым модулем Eclipse, или COM-клиентом. Мы рассмотрим эти ситуации и поговорим о том, что необходимо для развертывания в каждой из них. Мы также коснемся темы разработки и совместного использования развернутых программ при работе в группе разработчиков.

Развертывание приложения в клиентской среде

Для конечного пользователя нежелательно, чтобы приложение работало внутри Eclipse или поддерживающей COM-технологию среде разработки. “Мост” необходимо установить на компьютере пользователя в виде набора файлов, включая подготовленные к развертыванию бинарные файлы RJCB-”моста”, а также исполняемые файлы.

В некоторых других ситуациях “мост” используется совместно во время разработки приложения. При этом вы размещаете “мост” в форме подключаемого модуля Eclipse, вместе с подключаемым модулем Common, который содержит файлы RJCB времени исполнения. Это облегчает разработку кода в Eclipse.

Каковы тонкости развертывания?

Исходя из рассмотренного нами выше примерного сценария, вы, возможно, имеете представление о том, какие файлы нужно развернуть для собственно “моста” и для библиотеки времени исполнения RJCB:

  • Исполняемые бинарные файлы “моста” находятся в двух файлах: JAR-файле и DLL-файле. Названия этих файлов состоят из имени файла исходной библиотеки типов и суффикса "Bridge". Например, “мост”, созданный для файла MSO.DLL, размещает свои исполняемые бинарные файлы в MSOBridge.DLL и MSOBridge.JAR.
  • При развертывании “моста” в виде подключаемого модуля Eclipse вы также должны развернуть его JAR и XML-файлы, для того чтобы Eclipse смог корректно идентифицировать и загрузить подключаемый модуль.
  • Исполняемые файлы RJCB являются также частью так называемого подключаемого модуля Common, который занимается загрузкой исполняемых DLL и экспортом файла во все подключаемые модули “моста” в Eclipse. При развертывании “моста” как подключаемого модуля Eclipse все, что вам необходимо - это развернуть также модуль Common. Для автономных Java-программ об этом должен заботиться клиент “моста”, копируя эти файлы в удобное место и, затем, либо загружать исполняемые DLL динамически перед первым использованием “моста”, либо настроить переменную PATH для указания на их месторасположение. Автономная клиентская Java-программа должна также добавить файл RJCBRT.jar библиотеки RJCB Java в свой classpath. Отметим, что предпочтительнее явно загружать исполняемые DLL с указанием их абсолютного месторасположения. Это дает гарантию загрузки нужной версии RJCB.DLL даже при наличии нескольких установленных в вашей системе версий.

Подробности сценариев развертывания

Следующие сценарии развертывания зависят от типа RJCB-”моста” (одно- или двунаправленный), типа программы-клиента (подключаемый модуль Eclipse или автономная Java-программа) и от того, требуется ли дополнительная регистрация COM-компонентов для развертываемого “моста” (в противоположность простому копированию файлов “моста”).

  • Для развертывания однонаправленного RJCB-”моста” в виде подключаемого модуля Eclipse (необходимость регистрации каких-либо DLL отсутствует):
    1. Скопируйте подключаемый модуль Common RJCB (com.ibm.xtools.rjcb.common) в папку подключаемых модулей платформы Eclipse, если его там еще нет. Этот подключаемый модуль содержит и загружает исполняемые файлы RJCB.
    2. Скопируйте подключаемый модуль (модули) RJCB-”моста” в папку подключаемых модулей платформы Eclipse. Каждый подключаемый модуль “моста” содержит в своей секции <requires> ссылку на модуль Common:
      <requires>
      <import plugin="com.ibm.xtools.rjcb.common" export="true"/>
      </requires>
    3. Добавьте ID подключаемого модуля “моста” (например, xxx.yyy.zzz) в секцию <requires> файла plugin.xml тех подключаемых модулей, из которых вы хотите обращаться к модулю “моста”:
      <requires>
      <import plugin="xxx.yyy.zzz"/>
      </requires>
  • Для развертывания “моста” как автономной Java-программы без регистрации каких-либо DLL:
    1. Поместите JAR-файл (файлы) “моста” в произвольное место на машине клиента.
    2. Поместите DLL-файл (файлы) “моста” в произвольное место на машине клиента.
    3. Поместите исполняемый файл RJCBRT.DLL и файл RJCBRT.jar в произвольное место.
    4. Загрузите RJCBRT.DLL по его абсолютному месторасположению перед первым обращением к “мосту”:
      RJCBUtilities.load(<абсолютный путь к RJCBRT.DLL>)
    5. Добавьте код в программу Java-клиента для загрузки DLL-файла (файлов) “моста” с использованием System.load перед первым обращением к “мосту”:
      System.load (<абсолютный путь к DLL «моста»>);
    6. Добавьте JAR-файл “моста” и файл времени исполнения RJCBRT.jar в classpath Java-программы.
  • Для развертывания подключаемого модуля “моста” в виде автономной Java-программы и регистрацией необходимых DLL:
    1. Поместите JAR-файл “моста” в произвольное место на машине клиента.
    2. Поместите DLL-файл “моста” в произвольное место на машине клиента.
    3. Зарегистрируйте DLL “моста”, используя программу regsvr32.
    4. Поместите файлы RJCBRT.DLL и RJCBRT.jar в произвольное место.
    5. Зарегистрируйте RJCBRT.DLL, используя программу regsvr32.
    6. Добавьте JAR-файл “моста” и RJCBRT.jar в classpath Java-программы.
  • Для развертывания “моста” (реализованного на языке Java COM-сервер) на COM-клиентах:
    1. Поместите JAR-файл (файлы) “моста” (“мостов”) в произвольное место.
    2. Поместите DLL-файл “моста” в произвольное место.
    3. Зарегистрируйте DLL “моста”, используя программу regsvr32.
    4. Зарегистрируйте JVM, используемую для создания экземпляра Java-сервера, при помощи программы RJCB registerJavaVM.exe.
    5. Зарегистрируйте класс (классы) Java-сервера при помощи программы RJCB registerJavaClass.exe.
    6. Зарегистрируйте файл RJCBRT.DLL, используя программу regsvr32.
  • Для развертывания подключаемого модуля “моста” методом экспортирования его из Eclipse в виде готового к развертыванию подключаемого модуля:
    1. Выберите проект “моста” в Package Explorer системы Eclipse.
    2. Вызовите диалоговое окно "Export".
    3. Выберите пункт "Deployable Plugins and Fragments".
    4. В появляющемся диалоговом окне выберите папку "eclipse" целевой установки Eclipse в качестве "Destination Directory" и подтвердите ваш выбор.
    5. Если “мост” не однонаправленный (только из Java в COM), вы должны зарегистрировать DLL “моста”, используя программу regsvr32.

Развертывание при работе в группе

Обычно один из членов группы разработки создает “мост” и помещает его под управление программы контроля версий, так чтобы он мог совместно использоваться другими членами группы. Под управление программы контроля версий должны быть переданы следующие части проекта RJCB-”моста”:

  • Следующие файлы проекта “моста”:
    • .project
    • .classpath
    • plugin.xml
    • build.properties
    • src (подкаталог)
    Это даст возможность присоединяющимся к проекту разработчикам легко импортировать проект RJCB-”моста” в среду Eclipse при помощи мастера "Import", указав в нем месторасположение проекта и сгенерировав и скомпоновав проект в Eclipse.
  • Все файлы bridge.xml - (один файл на “мост”), расположенные в корневой папке своего “моста”.
  • Исходный файл библиотеки типов, используемый при генерации “моста”. DTJCB копирует этот файл из его первоначального месторасположения в место внутри каталога проекта RJCB-”моста”. Это делается для того, чтобы исходный файл библиотеки типов мог совместно использоваться членами группы. (Другие члены группы, возможно, не имеют ее или эта библиотека может быть расположена в другом месте.)
  • При необходимости могут быть скопированы для совместного использования исполняемые файлы “моста”, если не все члены группы имеют, например, установленную систему Microsoft Visual Studio и не могут самостоятельно компоновать “мосты”.

Совместное использование исполняемого RJCB

Клиенты RJCB-”моста” могут либо совместно использовать одну копию исполняемого RJCB, либо использовать свою, независимую его копию. Для совместного использования этот исполняемый файл должен быть сконфигурирован на машине разработчика следующим образом:

  • Каталог с RJCBRT.DLL должен быть прописан в переменной PATH.
  • RJCBRT.DLL должен быть зарегистрирован при помощи программы regsvr32.exe.
  • Соответствующий файл RJCBRT.JAR должен быть прописан в classpath.

Если вы имеете только однонаправленный Java-COM (в противоположность COM-Java) “мост”, вы должны использовать отдельную копию RJCB, который может иметь даже другую версию. Это становится возможным потому, что не требуется регистрация RJCB при помощи программы regsvr32 и помещение его в ваш PATH.

Миграция с COM к технологии Java

Если у вас хватило терпения добраться до этого места статьи, то вы, вероятно, имеете набор Java-приложений и приложений или компонентов, основанных на технологии COM, нуждающихся в использовании “моста”. И хотя RJCB-”мост” обеспечивает взаимодействие между этими двумя типами приложений, создание всех необходимых “мостов” для широкомасштабного корпоративного решения может быть не тривиальной задачей.

Лучшей стратегией для управления этими приложениями или компонентами была бы унификация реализации всех взаимодействующих приложений или компонентов в одну технологию. Это сохранило бы много сил, которые необходимо затратить на решение вопросов взаимодействия компонентов, и дало бы вам возможность направить время и средства на решение проблем реального бизнеса. Ставя себе это за цель, рассмотрим задачу переноса всех компонентов в технологию Java.

Стратегия: Революция против эволюции

Предположим, что на предприятии в существующих приложениях используется смесь Java и COM-компонентов, и мы хотим преобразовать все в Java-компоненты. Если предприятие обладает достаточным временем и ресурсами, можно было бы пересмотреть проект и реализовать приложение полностью на языке программирования Java. Эти усилия привели бы к ясной архитектуре, простоте разработке и снижению затрат на поддержку. С другой стороны, риск мог бы быть довольно большим и последствия от переключения с одного приложения на другое - не предсказуемыми. Этот подход работает хорошо с приложением небольшого масштаба.

В действительности, обычно ситуация более сложная. Предприятие может не иметь ни времени, ни ресурсов для таких широкомасштабных изменений, поэтому более реалистичным мог бы быть план поэтапной миграции. Хорошо было бы заменять COM-компоненты компонентами Java по одному и в конечном итоге перевести все компоненты приложения в Java-технологию. Сразу же возникает вопрос, как вы можете управлять этими маленькими этапами без причинения значительного ущерба работоспособности приложения.

Миграция с использованием RJCB

RJCB-”мост” может помочь использовать все компоненты совместно. Если вы решили преобразовать COM-компонент в Java-технологию, новая Java-реализация компонента может непосредственно взаимодействовать с необходимыми Java-компонентами. Для зависимых компонентов, которые все еще реализованы на технологии COM, вы можете создать RJCB-”мост” для их взаимодействия с новой Java-реализацией компонента. При этом подходе после завершения новой реализации компонента он будет готов взаимодействовать с остальными компонентами приложения.

Выполняя такие маленькие последовательные действия, вы можете поддерживать работоспособность приложения практически непрерывно и не заметить окончательного переключения на новое приложение при завершении процесса миграции. Это устраняет огромный риск, присущий революционному подходу, и дает плану миграции больше шансов на успех.

Итоговые замечания

Технологии Java и COM в настоящее время являются основными технологиями в мире компонентной архитектуры. Поскольку они продолжают оставаться главными игроками при взаимодействии компонентов, существует необходимость устранения разрыва между этими двумя технологиями. RJCB-”мост” является эффективным решением, а DTJCB предоставляет гибкие инструменты для его реализации.


Ресурсы для скачивания


Похожие темы

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=96446
ArticleTitle=Интегрирование COM и Java-компонентов: Достижение возможности взаимодействия при помощи Development Tool for Java-COM Bridge
publish-date=11162004