Передача объектов данных между Java-средами CICS: Часть 2: Методы передачи объектов данных Java

Java становится популярным языком программирования CICS-приложений. CICS предоставляет несколько Java-сред, каждая из которых имеет свои сильные стороны, поэтому передача объектов данных между различными Java-средами CICS ― важная задача. Этот цикл из трех статей посвящен данной теме. В Части 2 на примере класса Java показано, как передавать объекты данных Java между приложениями, запущенными в обобщенной среде JVM CICS, JVM на основе Axis2, среде CICS Dynamic Scripting и в JVM CICS на основе OSGi.

Деннис Уэйенд, технический специалист по работе с пользователями CICS, Web и Java, группа технического обеспечения продаж, IBM

Фото Денниса УэйендаДеннис Уэйенд (Dennis Weiand) работает техническим специалистом по CICS, Web и Java в группе технического обеспечения продаж IBM в Далласе (штат Техас, США). С ним можно связаться по адресу: dweiand@us.ibm.com.



20.08.2012

Введение

Часть 1 этого цикла из трех статей посвящена различным Java™-средам, которые предоставляет IBM® CICS®:

  • традиционная обобщенная среда JVM, в которой в каждый момент времени может выполняться только одна Java-транзакция на базе CICS;
  • среда JVM-сервера CICS, в которой несколько запросов Java-программ могут выполняться в одной и той же JVM одновременно. Следующие Java-среды, предоставляемые CICS, используют сервер JVM (но их нельзя смешивать в одном JVM-сервере):
    • среда на основе OSGi, которая обеспечивает систему динамических модулей OSGi с такими функциями, как динамическое добавление в JVM и удаление Java-классов, обеспечение реестра OSGi, предоставление Java-модулю только интерфейсов, а не классов модуля целиком, и определение зависимостей между модулями, что практически исключает типичные проблемы ClassNotFound;
    • механизм Web-сервисов с открытым исходным кодом Axis2, который позволяет быстро и легко представлять POJO с помощью аннотаций JAX-WS и писать обработчики в стиле Axis2;
    • CICS Dynamic Scripting ― быстрый способ разработки Web-приложений с использованием языков сценариев PHP и Groovy. Интерпретаторы PHP и Groovy реализованы на Java, так что это Java-мост, который позволяет создавать экземпляры объектов Java и вызывать CICS-программы;
  • CICS Transaction Gateway, который облегчает сообщение между Java-программой, работающей в не-CICS среде, и CICS TS-программой.

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

В Части 1 говорилось о CICS-версии вызова, команде EXEC CICS LINK, которая позволяет вызывать другие программы, написанные на том же или на другом языке программирования в среде CICS. В архитектуре CICS для передачи данных между программами CICS применяются COMMAREA и каналы/контейнеры. COMMAREA представляет собой блок ячеек памяти емкостью до 32 КБ, а контейнер ― это именованный блок ячеек памяти без ограничения размера. Контейнеры группируются в канал, который можно передавать из одной CICS-программы в другую. COMMAREA и каналы/контейнеры ― взаимоисключающие методы: программа может получить данные только одним из них. При вызове программы В из программы А программа А может передать COMMAREA или канал, но не то и другое вместе.

В Части 1 говорилось, что если CICS-приложение написано только на Java и нужно переходить из одной Java-среды CICS в другую, то проще оставаться в парадигме Java и передавать между Java-средами на базе CICS объекты данных Java. Для этого нужно выполнить сериализацию объекта данных Java в контейнер CICS, передать контейнер в другую Java-программу, работающую в другой Java-среде CICS, а затем выполнить десериализацию объекта в целевой Java-программе.

Иначе, можно преобразовать данные в поле-ориентированную структуру, последовательность байтов, но передача объектов данных Java между предоставляемыми CICS Java-средами позволяет использовать преимущества различных предоставляемых CICS Java-сред, а также избежать:

  • создания структуры тетради COBOL для данных, передаваемых между Java-программами;
  • запуска утилиты для создания объекта данных Java из тетради COBOL;
  • необходимости Java-программисту знать COBOL;
  • необходимости хранить требуемые тетради COBOL в своем хранилище исходного кода;
  • необходимости обеспечивать цикл обработки тетради COBOL;
  • необходимости обновлять тетрадь COBOL при изменении содержания передаваемых данных (с последующим обновлением хранилища и циклом обработки).

Использование объектно-ориентированной надстройки поверх CICS

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

String abc = "Some information to Pass";
Employee emp = new Employee("John Doe");
DDW_CicsObjectTransporter transporter = 
    new DDW_CicsObjectTransporter();
transporter.addObject("abc",abc)
    .addObject("emp",emp)
    .execute("TARGET");

// и после ответа программы

String errorString = (String)transporter.getObject("error");
If (errorString != null) {
    processError();
} else {
    Manager newManager = (Manager)transporter.getObject("mgr");
    // обработка/отображение возвращенного объекта Manager
}

Ниже приведен пример кода отвечающей Java-программы, которая возвращает данные с помощью надстройки:

DDW_CicsObjectTransporter transporter = new DDW_CicsObjectTransporter();
Employee emp = (Employee)transporter.getObject("emp");
// работа с объектом employee 
transporter.removeObject("abc");    // можно удалить объект в транспортере
Manger mgr = new Manger("Joe Bloggs");
transporter.addObject("mgr",mgr);  // добавление новых или измененных объектов 
return;

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

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

Сериализация объектов Java

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

Для сериализации объекта в байтовый массив используется метод writeObject() класса ObjectOuputStream. Чтобы десериализовать объект из байтового массива, потребуется метод readObject() класса ObjectInputStream.

Для сериализации объект должен реализовать интерфейс java.io.Serializable. Такие Java-объекты, как строки и массивы, реализуют этот интерфейс, но java.lang.Object (мать всех объектов) ― нет. Таким образом, в зависимости от структуры наследования объектов, которые нужно передать, может потребоваться реализация этими объектами интерфейса Serializable. Это не проблема, так как в одном Java-объекте можно реализовать несколько интерфейсов. Но даже если объект реализует интерфейс Serializable, это не означает, что все, на что ссылается этот объект, может быть сериализовано. Нужно гарантировать, что объект и все объекты, на которые он ссылается (и объекты, на которые ссылаются те объекты), реализуют Serializable.

Необходимо также, чтобы в вызывающей JVM-среде CICS и в целевой JVM-среде CICS присутствовала одна и та же версия класса. Реализация интерфейса Serializable включает поле, определяемое как private static final long, с именем serialVersionUID. При изменении объекта необходимо изменить serialVersionUID. Если serialVersionUID входит в объект, значение, связанное с этим полем, хранится в сериализованном объекте. При попытке десериализации объекта, если локальное определение класса не согласовано с serialVerisionUID из сериализуемого объекта, десериализация завершится неудачей со значимым сообщением об ошибке. Использование поля serialVersionUID позволит избежать потенциальных ситуаций рассогласования, которые могут привести к неожиданным результатам. При сериализации объектов настоятельно рекомендуется использовать serialVersionUID.

Классы передачи объектов данных Java, предлагаемые в этой статье, проверяют наличие в передаваемом объекте поля serialVersionUID, но не проверяют его наличие в объектах, на которые ссылается этот объект. Поэтому нужно убедиться, что ссылочные объекты содержат поле serialVersionUID. В предоставленном классе Java можно отключить проверку serialVersionUID с помощью метода setCheckForSerialVersionUIDBeforeSerialization(false).

Если объект имеет особенности с точки зрения сериализации, и обычный подход к сериализации Java с этим объектом не работает, можно указать, как сериализовать и десериализовать этот объект, реализовав методы writeObject() и readObject(). Эти два метода, если они присутствуют во время сериализации и десериализации объекта, будут вызываться при реализации интерфейса Serializable.

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

Запись сериализованных объектов Java в каналы и контейнеры CICS и их считывание в Java-среде CICS TS

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

  • обратиться к передаваемому (текущему) каналу со следующей командой:
    Channel myChannel = Task.getTask().getCurrentChannel();
  • создать канал, который затем можно передать в другую программу, с помощью следующей команды:
    Channel myChannel = Task.getTask().createChannel(THECHANNELNAME);
  • обратиться к текущему каналу или любому каналу, созданному с определенным именем, на текущем уровне соединения CICS:
    Channel myChannel = Task.getTask().getChannel(THECHANNELNAME).

Что касается методов getCurrentChannel() и getChannel(), то если переменная myChannel имеет значение null, указанный канал на этом уровне соединения CICS не существует, поэтому для передачи сериализованного объекта данных Java придется создать канал.

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

Получив ссылку на канал, для помещения данных в контейнер, извлечения данных из контейнера и удаления контейнера можно использовать следующий код. Существует два типа контейнеров CICS - CHAR и BIT, и в данном случае нужно использовать контейнеры BIT. Имена канала и контейнера могут содержать от 1 до 16 символов.

byte[] myByteArray = "some bytes".getBytes();   // для передачи
Container myContainer = myChannel.createContainer(containerName);
myContainer.put(myByteArray);                   // это контейнер типа BIT

Container myContainer = myChannel.getContainer(containerName);
byte[] myByteArray = myContainer.get();   // извлечение байтового массива из контейнера

myChannel.deleteContainer(containerName);       // удаление контейнера

При работе с каналами и контейнерами в Java-программе на базе CICS могут выдаваться различные исключения, поэтому поместите приведенные выше фрагменты кода в блоки try/catch.

Вызов из Java-программы на базе CICS другой CICS-программы

Java-программы на базе CICS, использующие другие Java-программы в той же Java-среде, предоставленной CICS, должны применять обычные процедуры Java — создание экземпляра объекта соответствующего типа и вызов нужных методов на этих объектов.

Для вызова другой Java-программы на базе CICS, которая работает в предоставленной CICS Java-среде, отличной от текущей предоставленной CICS Java-среды (или в предоставленной CICS Java-среде, находящейся под контролем другой области CICS), для этой Java-программы требуется эквивалент команды EXEC CICS LINK. Как показано ниже, Java-эквивалент команды EXEC CICS LINK довольно прост:

Program aProg = new Program();
aProg.setName(targetProgram);
aProg.link(theChannel);

В этом фрагменте кода targetProgram ― переменная, содержащая имя вызываемой (LINKed to) CICS-программы. Метод link(theChannel) пытается вызвать программу и передать ей указанный канал и все контейнеры, находящиеся в этом канале. Поместите приведенный выше фрагмент кода в блок try/catch.

С теоретической точки зрения это все, что нужно сделать ― сериализовать объект в байтовый массив, поместить байтовый массив в контейнер, связанный с каналом, вызвать целевую программу, а затем десериализовать байтовый массив, переданный в контейнере, в объект данных, который можно использовать в своей программе.

Для выполнения всех этих шагов лучше всего создать набор параметризованных классов. Прорабатывая идеи, изложенные в этой статье, мы написали набор классов, который можно использовать для ознакомления с этими шагами и синтаксисом команд, а также расширять в собственных целях. (Эти Java-классы не прошли никакого официального тестирования в IBM и приводятся "как есть" для иллюстрации идей, изложенных в этой статье.) Описанный здесь подход облегчает жизнь разработчикам Java-приложений, но оказывает влияние на производительность. Так что при использовании методов, описанных в этой статье, проверьте результаты на производительность; если приложение работает недостаточно быстро, то вместо сериализации данных из объектов данных Java при передаче данных между Java-программами преобразуйте их в поле-ориентированную структуру последовательных байтов (другими словами, используйте традиционное методы передачи данных CICS, которые применяются при передаче данных в CICS-программы, написанные на разных языках, а не только на Java).

Использование предлагаемых Java-классов для передачи объектов Java между Java-программами CICS

При передаче объектов Java между JVM-средами на базе CICS исходной Java-средой CICS может быть:

  • приложение CICS dynamic scripting;
  • программа-оболочка Web-сервиса на базе Axis2;
  • клиентская Java-программа CICS Transaction Gateway;
  • OSGi-среда на базе CICS;
  • обобщенная среда JVM на базе CICS.

Целевые JVM-среды на базе CICS, в которых используется целевая Java-программа бизнес-логики:

  • OSGi-среда на базе CICS;
  • обобщенная среда JVM на базе CICS.

Повторим, что OSGi-среда на базе CICS – это стратегическое место размещедля бизнес-логики на основе Java в CICS, потому что она обеспечивает максимальную гибкость бизнес-логики и позволяет многократно использовать бизнес-логику на основе Java с помощью разнообразных способов взаимодействия CICS, включая Web-сервисы, интерфейс RESTful, WebSphere MQ и CICS dynamic scripting.

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

Передача объектов Java из обобщенной среды JVM CICS, JVM на основе OSGi или JVM Axis2

При передаче объектов Java из обобщенной среды JVM CICS, JVM на основе OSGi или JVM Axis2 разница заключается лишь в способе указания местоположения передаваемого Java-класса. Объект DDW_CicsObjectTransporter, приведенный в этой статье, позволяет установить связь с целевой Java-программой с именем TARGET, передавая объекты с использованием следующего подхода:

String abc = "Some information to Pass";
Employee emp = new Employee("John Doe");
DDW_CicsObjectTransporter transporter = 
    new DDW_CicsObjectTransporter();
transporter.addObject("abc",abc).
    addObject("emp",emp).
    execute("TARGET");

// и после ответа программы

String errorString = (String)transporter.getObject("error");
If (errorString != null) {
    processError();
} else {
    Manager newManager = (Manager)transporter.getObject("mgr");
    // обработка/отображение возвращенного объекта Manager
}

В классе DDW_CicsObjectTransporter, прилагаемом к этой статье, при ответе на приведенный выше пример кода происходит следующее.

  1. Предложенный класс DDW_CicsObjectTransporter (транспортер) использует имя канала DDWddwObjTrnsptr. Если транспортеру передан канал с этим именем или он уже создал канал с этим именем, то он и будет использоваться. В противном случае транспортер создает канал с именем DDWddwObjTrnsptr. Таким образом, если создается экземпляр второго транспортера, он будет использовать тот же канал с именем DDWddwObjTrnsptr, так как тот уже образован первым экземпляром класса.
  2. Метод execute() вызывает запрос LINK к указанной программе.
  3. При вызове метода addObject(String containerName, Object obj) объект obj сериализуется и помещается в контейнер containerName.
  4. Транспортер проверяет, что ссылка на объект, указанная объектом obj, содержит поле с именем serialVersionUID, но не проверяет, что объекты, указанные obj, содержат поле serialVerisionUID. Такая проверка нагружает процессор, и ее можно исключить, вызвав метод transporter.setCheckForSerialVersionUIDBeforeSerialization(false).
  5. Если вызван метод getObject(String containerName), то байтовый массив из указанного контейнера десериализуется, и объект возвращается. Метод getObject() возвращает объект типа Object, поэтому необходимо привести тип возвращенного объекта к ожидаемому типу объекта.
  6. При вызове метода removeObject(String containerName) транспортер вызывает метод deleteContainer(containerName) в канале DDWddwObjTrnsptr для удаления контейнера.
  7. В ошибочных ситуациях при использовании каналов и контейнеров принято возвращать контейнер ошибки (с некоторыми согласованным именем), указывающий на причину ошибки. Поэтому в случае обнаружения ошибочной ситуации (такой как "клиент не найден") бизнес-логика ЦЕЛЕВОЙ программы должна добавить в транспортер объект error. Приведенный выше пример кода проверяет наличие ошибки по контейнеру error. Если он существует, запрос не удался, и нужно обработать ошибку. Если контейнер error отсутствует, запрос выполнен успешно.
  8. Если удаленный транспортер в ЦЕЛЕВОЙ программе столкнулся с ошибкой при сериализации/десериализации или при попытке получения, добавления или удаления контейнеров, удаленный DDW_CicsObjectTransporter выдает исключение и помещает в канал контейнер ошибки DDWddwObjTErrorM. Если локальный транспортер обнаруживает этот контейнер ошибки, любой запрос метода transporter вызовет исключение с указанием причины ошибки в удаленном транспортере.
  9. Аналогично если локальный транспортер сталкивается с проблемой при сериализации/десериализации объекта или при получении, добавлении или удалении контейнеров, он выдает исключение, указав причину ошибки. В случае любой ошибки в транспортере любой запрос метода transporter в транспортере приведет к исключению с указанием первопричины. Если вам не нравится такое поведение, вы можете вызвать методы
    transporter.checkForTransporterErrorsInChannel(false) и
    transporter.writeTransporterErrorsToChannel(false).
  10. Некоторые сообщения об ошибках, выдаваемые, когда собственная десериализация Java вызывает ошибку при десериализации объектов, на которые ссылаются другие объекты, не содержат хороших указаний на причину ошибки. Транспортер может только передать ту информацию, которая ему предоставлена.
  11. Если возникли проблемы с транспортером, можно воспользоваться методом transporter.setDebugLevel(9), чтобы транспортер записывал сообщения в CSMT Transient Data (укажите 0, если не нужны отладочные сообщения - чем больше число, тем подробнее сообщения). Для записи в stdout вместо очереди TD используйте:
    transporter.setPrintToTdQueue(false).
    Если нужно отправлять сообщения в очередь TD, отличную от CSMT, используйте:
    transporter.setTdQueueForPring("NAME").
    В конструкторе транспортера также можно задать уровень отладки, чтобы получать сообщения инициализации транспортера. Для этого используйте:
    DDW_CicsObjectTransporter transporter = new
    DDW_CicsObjectTransporter(9);
    .

Java-среде на базе CICS потребуется доступ к классу DDW_CicsObjectTransporter, содержащемуся в файле com.ibm.ddw.cics.object.transporter.jar из загрузки для этой статьи:

  • для обобщенной среды JVM CICS добавьте JAR-файл к переменной CLASSPATH_SUFFIX в свой файл JVMProfile Java-программы CICS (о программах в обобщенной среде JVM и файлах JVMProfile говорится в первой статье этого цикла);
  • для JVM-среды Axis2, предоставляемой CICS, добавьте в свое приложение пакет com.ibm.ddw.cics.object.transporter;
  • для OSGi-среды CICS можно выбрать любой из трех способов сделать транспортер объектов доступным для OSGi-комплектов:
    1. Включить исходный код в пакет com.ibm.ddw.cics.object.transporter как один из пакетов OSGi-комплекта, в котором используется транспортер.
    2. Добавить файл com.ibm.ddw.cics.object.transporter.jar со своим приложением в корневой каталог комплекта и указать местоположение JAR-файла в параметре CLASSPATH манифеста OSGi-комплекта.
    3. Поместить файл com.ibm.ddw.cics.object.transporter.jar в общедоступное место файловой системы и z/OS UNIX System Services и указать местоположение JAR-файла в параметре CLASSPATH манифеста OSGi-комплекта.

Преимущество варианта 3 заключается в том, что все ваши OSGi-комплекты будут обращаться к одной и той же версии объектного кода транспортера, но если требуется переносить OSGi-комплект, рассмотрите один из первых двух вариантов. Выбирая между вариантом 1 или 2, используйте вариант 2, если вы предпочитаете рассматривать транспортер объектов как "черный ящик" и не трогать его исходный код.

Пакет com.ibm.ddw.cics.object.transporter нельзя использовать как самостоятельный OSGi-комплект и включать в параметр OSGI_BUNDLES= файла JVMProfile JVMServer OSGi, так как правила видимости OSGi приведут к тому, что при попытке десериализации объектов транспортер объектов получит исключение ClassNotFoundException. Каждый пакет, использующий транспортер объектов, можно импортировать в OSGi-комплект транспортера объектов, но это нецелесообразно, так как при каждом новом использовании транспортера объектов его OSGi-комплект придется изменять. Прилагаемый к этой статьеJAR-файл com.ibm.ddw.cics.object.transporter включает в себя как исходный код, так и файлы .class.

Передача Java-объектов из среды CICS dynamic scripting

Как говорилось выше, CICS dynamic scripting содержит интерпретатор PHP и Groovy, реализованный на языке Java, и работает на JVM-сервере CICS. Мост PHP-Java позволяет создавать экземпляры и вызывать Java-классы и методы. Создавать экземпляры и вызывать Java-классы и методы можно и с помощью Groovy. Поэтому DDW_CicsObjectTransporter можно использовать для передачи объектов Java из сценариев PHP или Groovy в предоставленную CICS обобщенную среду JVM или JVM на основе OSGi, что позволяет писать логику представления на PHP или Groovy, сохраняя бизнес-логику на базе Java в обобщенной среде JVM или OSGi-среде CICS.

Java можно использовать и в качестве языка программирования в приложении CICS dynamic scripting, хотя здесь это не показано. Использование транспортера объектов в Java-программе, работающей в среде CICS dynamic scripting, аналогично использованию транспортера объектов в обобщенной среде JVM CICS, за исключением того, что файл com.ibm.ddw.cics.object.transporter.jar нужно поместить в каталог lib приложения CICS dynamic scripting и выполнить zero resolve для приложения.

Вот простой пример использования DDW_CicsObjectTransporter из простого PHP-сценария.

<html>
<head><title>Link to a CICS Java program with objects</title></head>
<body>
<?php
try {
    // создание нескольких Java-объектов с помощью моста PHP-Java 
    $someString = "some string";
    $myManager = new Java('com.ddw.transporter.test.Manager');
    $myManager->setManagerName('Roy');
    $staffArray = new Java('java.util.ArrayList');
    $aStaff = new Java('com.ddw.transporter.test.Staff', "Dennis");
    $staffArray->add($aStaff);
    $myManager->setStaff($staffArray->toArray());

    // транспортировка объектов в/из указанной Java-программы CICS
    $transporter = new
Java('com.ibm.ddw.cics.object.transporter.DDW_CicsObjectTransporter');
    $transporter->addObject("someString", $someString);
    $transporter->addObject("myManager", $myManager);
    $transporter->execute("PROGRAMB");    // invoke CICS Java program
    $responseData = $transporter->getObject("responseData");
    echo $responseData;
} catch (Exception $e1) {
    echo 'Exception: '.$e1->getMessage();
}
?>
</body>
</html>

В приведенном выше примере кода процесс передачи объектов одинаков для предоставленных CICS сред Axis2, обобщенной среде JVM и OSGi.

  • Мы добавляем массив Staff к объекту Manager, вводим объект Manager в транспортер, а затем вызываем Java-программу CICS PROGRAMB.
  • Блок try/catch выполняет проверку на исключения, но транспортер выдает только исключение DDW_CicsObjectTransporterException, так что можно было бы проверять только на него.

Чтобы использовать DDW_CicsObjectTransporter в приложении CICS dynamic scripting, добавьте com.ibm.ddw.cics.object.transporter.jar в каталог lib приложения и выполните zero resolve.

Прием Java-объектов в JVMServer на базе обобщенной среды JVM CICS или OSGi

Для приема объектов в Java-программу, работающую на JVM-сервере на базе обобщенной среды JVM CICS или OSGi, можно использовать следующий код с DDW_CicsObjectTransporterr.

DDW_CicsObjectTransporter transporter = 
    new DDW_CicsObjectTransporter();
Employee emp = (Employee)transporter.getObject("emp");
// работа с объектом employee 
transporter.removeObject("abc");    // может также удалять объекты
Manger mgr = new Manger("Joe Bloggs");
transporter.addObject("mgr",mgr);  // добавление новых или измененных объектов
return;

В приведенном выше примере кода:

  1. Предоставленный класс DDW_CicsObjectTransporter (транспортер) использует имя канала DDWddwObjTrnsptr. В данном случае, поскольку эта Java-программа вызвана транспортером из удаленной Java-программы на основе CICS, текущий канал (канал, переданный этой программе) имеет имя DDWddwObjTrnsptr. Можно использовать методы транспортера getObject(), removeObject() и addObject().
  2. Любые объекты, добавленные к транспортеру, будут возвращаться в вызывающую программу.
  3. Можно создать второй или третий экземпляр транспортера, хотя это приведет к некоторой путанице. Все экземпляры транспортера будут использовать текущий канал, поскольку его имя DDWddwObjTrnsptr. Никаких конфликтов не будет.
  4. Хотя это не показано, метод execute() можно использовать для вызова другой Java-программы еще в одной Java-среде на базе CICS.
  5. В ошибочных ситуациях при использовании каналов и контейнеров принято возвращать контейнер ошибки (с некоторыми согласованным именем), указывающий на причину ошибки. Поэтому в случае ошибки вызываемая программа (данная программа) должна добавить в канал контейнер ошибки. Например, можно добавить следующий код:
    String error = "The customer named "+theCustomerName+" was not found");
    transporter.addObject("error", error);
    .
    А вызывающая программа должна иметь доступ к данным об ошибках:
    String error = (String)transporter.getObject("error");
    // значение NULL, если нет 'error'if (error != null)
    {// ошибку можно обработать здесь или выдать новое исключение ApplicationException(error);}
  6. Если этот транспортер столкнулся с ошибкой сериализации/десериализации или при попытке получения, добавления или удаления контейнеров, он выдает исключение и помещает в канал контейнер ошибки DDWddwObjTErrorM. Если транспортер вызывающей программы обнаруживает этот контейнер ошибки, то любой запрос метода транспортера вызовет исключение, указывающее причину ошибки в этом (удаленном) транспортере.
  7. Если вызывать любые методы этого транспортера после того как он обнаружил проблему сериализации или десериализации, он выдаст исключение с описанием первопричины. Если вам не нравится такое поведение, вы можете вызвать метод
    transporter.checkForTransporterErrorsInChannel(false),
    а если вы не хотите возвращать ошибки транспортера транспортеру вызывающей программы, вызовите метод
    transporter.writeTransporterErrorsToChannel(false).
  8. Некоторые сообщения об ошибках, выдаваемые, когда собственная десериализация Java вызывает ошибку при десериализации объектов, на которые ссылаются другие объекты, не содержат хороших указаний на причину ошибки. Транспортер может только передать ту информацию, которая ему предоставлена.
  9. Если возникли проблемы с транспортером, можно воспользоваться методом transporter.setDebugLevel(9), чтобы транспортер записывал сообщения в CSMT Transient Data CICS. Укажите 0, если не нужны отладочные сообщения - чем больше число, тем подробнее сообщения. Для записи в stdout вместо очереди TD используйте:
    transporter.setPrintToTdQueue(false).
    Если нужно отправлять сообщения в очередь TD, отличную от CSMT, используйте:
    transporter.setTdQueueForPring("NAME").
    В конструкторе транспортера также можно задать уровень отладки, чтобы получать сообщения инициализации транспортера. Для этого используйте:
    DDW_CicsObjectTransporter transporter = new
    DDW_CicsObjectTransporter(9);

Java-среде на базе CICS потребуется доступ к классу DDW_CicsObjectTransporter, содержащемуся в файле com.ibm.ddw.cics.object.transporter.jar из загрузки для этой статьи.

  • Для обобщенной среды JVM CICS добавьте JAR-файл к переменной CLASSPATH_SUFFIX в файле JVMProfile Java-программы CICS (о программах в обобщенной среде JVM и файлах JVMProfile говорится в первой статье этого цикла).
  • для OSGi-среды CICS можно выбрать любой из трех способов сделать транспортер объектов доступным для OSGi-комплектов:
    1. Включить исходный код в пакет com.ibm.ddw.cics.object.transporter как один из пакетов OSGi-комплекта, в котором используется транспортер.
    2. Добавить файл com.ibm.ddw.cics.object.transporter.jar в приложение (в корневой каталог вашего комплекта) и указать местоположение JAR-файла в параметре CLASSPATH манифеста OSGi-комплекта.
    3. Поместить файл com.ibm.ddw.cics.object.transporter.jar в общедоступное место файловой системы z/OS UNIX System Services и указать местоположение JAR-файла в параметре CLASSPATH манифеста OSGi-комплекта.

Преимущество варианта 3 заключается в том, что все ваши OSGi-комплекты будут обращаться к одной и той же версии объектного кода транспортера, но если требуется переносить OSGi-комплект, рассмотрите один из первых двух вариантов. Выбирая между вариантом 1 или 2, используйте вариант 2, если вы предпочитаете рассматривать транспортер объектов как "черный ящик" и не трогать его исходный код.

Пакет com.ibm.ddw.cics.object.transporter нельзя использовать как самостоятельный OSGi-комплект и включать в параметр OSGI_BUNDLES= файла JVMProfile JVMServer OSGi, так как правила видимости OSGi приведут к тому, что транспортер объектов получит ClassNotFoundException при попытке десериализации объектов. Каждый пакет, использующий транспортер объектов, можно импортировать в OSGi-комплект транспортера объектов, но это нецелесообразно, так как при каждом новом использовании транспортера объектов его OSGi-комплект придется изменять. Прилагаемый к этой статье JAR-файл com.ibm.ddw.cics.object.transporter включает в себя как исходный код, так и файлы .class.

Производительность

Одно из первых замечаний специалистов, рецензировавших эту статью, касалось ухудшения производительности. Это цена сериализации и десериализации объектов. При использовании предоставленного транспортера объектов следует оценить производительность приложения на ранних стадиях разработки, чтобы убедиться, что она отвечает вашим требованиям. Хотя для передачи данных между Java-программами на основе CICS с использованием традиционного подхода поле-ориентированной последовательности байтов требуются запуск дополнительной утилиты и знание некоторых деталей процедурных языков, таких как COBOL или PL/I, этот традиционный подход может работать лучше.

В пример транспортера для этой статьи введена проверка ошибок, и большая часть этого механизма проверки ошибок по умолчанию включена. Для повышения производительности предоставленного примера кода транспортера можно использовать перечисленные ниже способы отключения проверки некоторых ошибок. Кроме того, по умолчанию при обнаружении ошибок несоответствия версий выдается предупреждение, и транспортер продолжает функционировать. Если вы хотите, чтобы в случае обнаружения удаленного транспортера другого уровня транспортер отключался, используйте метод setStopTransporterActivityIfLocalRemoteVersionsDifferent(true).

setCheckForTransporterErrorsInChannel(false);
   // Не проверять ошибки предыдущих запросов
setCheckForSerialVersionUIDBeforeSerialization(false); 
   // Не отводить время на проверку поля serialVersionUID сериализуемых объектов
setCheckTheTransporterLevelWithWhichWeAreCommunicating(false); 
   // Не отводить время на проверку, 
   // находятся ли локальный и удаленный транспортеры на одном и том же уровне

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

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

Решение проблем передачи объектов

Для транспортера объектов можно задать уровень сообщений отладки с помощью поля int со значением от 1 до 9 в качестве аргумента конструктора или с помощью метода transporter.setDebugLevel(5). Чем больше число, тем подробнее сообщения. Если нужно, чтобы сообщения поступали в stdout, вызовете transporter.setPrintToTdQueue(false), иначе сообщения будут поступать во временное хранилище данных CSMT. Если нужно изменить место назначения, вызовете transporter.setTdQueueForPrint("ABCD").

В конструкторе транспортера также можно задать уровень отладки, чтобы получать сообщения инициализации транспортера. Для этого используйте:
DDW_CicsObjectTransporter transporter = new
DDW_CicsObjectTransporter(9);
.

Распределение рабочей нагрузки

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

Взаимодействие разных языков

Одним из преимуществ системы CICS является ее способность взаимодействовать с бизнес-логикой, написанной на разных языках программирования. Методы, приведенные в этой статье, предполагают, что нужно передавать данные между двумя Java-программами на базе CICS, работающими в двух разных Java-средах, предоставленных CICS. Так как никакие языки, кроме Java, не понимают сериализованных объектов Java, подход транспортера объектов нельзя использовать для взаимодействия с программами CICS, написанными на ассемблере, C, C++, COBOL или PL/I. В среде CICS для взаимодействия между Java и ассемблером, COBOL или PL/I нужно переводить данные в формат, понятный программе на ассемблере, COBOL или PL/I – поле-ориентированную последовательность байтов.

Сериализация объектов Java

Преимущества и недостатки, а также детали процесса сериализации объектов (с помощью собственного механизма сериализации Java или некоторых существующих подпрограмм сериализации/десериализации с открытым исходным кодом) рассматриваются в соответствующей документации по Java.

Заключение

В этой статье описаны шаги, необходимые для передачи объектов данных Java между Java-программами, работающими в разных Java-средах, предоставляемых CICS:

  • сериализация объекта данных Java в байтовый массив;
  • помещение байтового массива в контейнер CICS, связанный с каналом;
  • вызов эквивалента команды EXEC CICS LINK для передачи канала, содержащего контейнеры с сериализованными объектами данных Java;
  • в программе, с которой установлена связь, извлечение байтового массива из контейнера CICS и его десериализация в объект данных Java.

И, наконец, в статье описываются прилагаемые Java-классы, реализующие приведенные в ней методы. Эти Java-классы не прошли никакого официального тестирования в IBM и приводятся "как есть" исключительно для иллюстрации идей, описанных в статье. Предлагаемый здесь подход облегчает жизнь разработчикам Java-приложений, но, как и в любой среде, влияет на производительность. При использовании этих методов оцените свои результаты, чтобы определить, работает ли приложение с приемлемым уровнем производительности; в противном случае при передаче данных между Java-программами вместо сериализованных объектов следует использовать преобразование данных из объектов Java в поле-ориентированную последовательность байтов.

В Части 3 будет показано, как передавать объекты данных Java из клиентской программы CICS Transaction Gateway Java в среду CICS Transaction Server Java.


Загрузка

ОписаниеИмяРазмер
Пример кодаcom.ibm.ddw.cics.object.transporter.zip28 КБ

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere, Технология Java
ArticleID=831024
ArticleTitle=Передача объектов данных между Java-средами CICS: Часть 2: Методы передачи объектов данных Java
publish-date=08202012