|
Вероотступник Geronimo: Что нового в OpenEJB 3.0
Статьи
→
Обзоры, аналитика, практические пособия по разработке ПО
Спецификация Java 2 Platform, Enterprise Edition (J2EE) сделала технологию Java главенствующей в области разработки корпоративных приложений. Долгие годы данная технология пыталась занять это положение и до сих пор успешно сохраняет его, что в очередной раз подтвердилось в редакции спецификации Java Platform, Enterprise Edition 5 (Java EE 5). OpenEJB с самого начала был составной частью Geronimo. Его версия 3.0 является ключевым компонентом в реализации Geronimo спецификации Java EE 5. В данной статье рассказывается о принципах, лежащих в основе Enterprise JavaBeans (EJB) 3, а также о новых возможностях OpenEJB, благодаря которым обеспечиваются новые важные функции Geronimo.
История EJB
Первая спецификация EJB от IBM, разработанная в 1997 г., как полагают многие, стала значительной вехой в эволюции Java-технологий. Компоненты EJB и серверы приложений J2EE, которые их использовали, были вскоре положительно восприняты сообществом разработчиков корпоративных приложений. Однако критика EJB не заставила себя ждать. В основном критике подвергались трудность для понимания и сложность разработки EJB.
Спецификация EJB была рассчитана на решение таких сложных проблем как распределенные вычисления, управление транзакциями и персистентность данных. Сложные проблемы не всегда возможно решить простыми методами, поэтому изначально спецификации EJB отражали те сложные проблемы, на решение которых они были направлены. В результате этого разработчикам приходилось нелегко. Разобравшись в EJB, можно использовать мудреные инструменты, и работать становится легче. Но для начинающих пользователей EJB трудностей хватало.
Версии спецификаций EJB 1.0 и 1.1 были разработаны и выпущены компанией Sun Microsystems. Все последующие спецификации создавались с использованием Java Specification Requests (JSR) и проходили сертификацию через Java Community Process (JCP). Участие сообщества в разработке ключевой элемент в эволюции Java-технологий. Трудности, с которыми сталкивались разработчики EJB, были учтены в JCP. Результатом этого явилась спецификация EJB 3.0, законченная в мае 2006 г.
Теперь компоненты EJB уже не были направлены только на решение сложных проблем, они также стали развиваться в направлении упрощения разработки. Цель EJB 3.0 сделать начальную стадию разработки легче, а приложения более удобными в сопровождении. Мы расскажем, насколько проще стала EJB версии 3.0 по сравнению с EJB 2.1. Во-первых, давайте посмотрим на OpenEJB, которая является реализацией EJB и одной из основ Geronimo.
OpenEJB EJB 1.1
OpenEJB существует приблизительно с 2000 г. Ее основателями были Дэйвид Блевинс (David Blevins) и Ричард Монсон-Хейфел (Richard Monson-Haefel). Блевинс также стоял у истоков Geronimo, поскольку OpenEJB был самым приемлемым выбором для реализации EJB в Geronimo. OpenEJB была одной из первых реализаций спецификации EJB 1.1. Она обеспечивала прямую реализацию компонентов (beans) для сеансов удаленного доступа и использовала Castor для реализации компонентов персистентности entity bean, управляемой контейнером (container-managed persistence CMP). С самого начала OpenEJB был направлен на облегчение труда разработчиков. Например, OpenEJB допускал использование встроенных контейнеров (и даже встроенных баз данных), чтобы легче было писать тесты для создаваемых EJB-компонентов. В большинстве реализаций EJB-компоненты было настолько трудно тестировать, что для этого приходилось разрабатывать сложные инфраструктуры (самый яркий пример JUnitEE). OpenEJB стал очень качественной реализацией для EJB 1.1 по скорости и удобству для пользователя. Однако для состыковки с потребностями Geronimo потребовалась определенная эволюция OpenEJB.
OpenEJB и Geronimo EJB 2.1
Geronimo был задуман как реализация (с открытым кодом) спецификации J2EE 1.4. Эта спецификация включала спецификацию EJB 2.1. OpenEJB был реализацией EJB 1.1. Версия EJB 2.1 была значительно расширена по сравнению с версией 1.1, в том числе были добавлены локальные интерфейсы для сессионных компонентов (session beans) и компонентов, управляемых сообщениями (MDB), язык запросов для методов поиска компонентов entity bean и поддержка представления сессионных компонентов в виде Web-сервисов.
К счастью, в команде разработчиков Geronimo (а тогда в нее вошло много специалистов, внесших свой вклад в создание OpenEJB) оказалась много талантов, и они постарались реализовать все свойства EJB 2.1 в OpenEJB, таким образом содействуя тому, чтобы в дальнейшем Geronimo стала реализацией J2EE 1.4. В процессе разработки OpenEJB кое в чем приобрела сложность, характерную для спецификации EJB. Например, встраиваемый контейнер, столь полезный при тестировании элементов, явился побочным эффектом борьбы за совместимость с EJB 2.1. Но Java-разработчикам повезло: не за горами было появление EJB 3.
EJB 3.0
Так что же так впечатляет в EJB 3.0? Легче всего будет понять EJB 3.0, сравнивая его с EJB 2.1. Давайте построим простой EJB-компонент в каждой из версий. В следующих разделах мы создадим простой сессионный компонент, не меняющий состояния в процессе исполнения (stateless), который будет выдавать текущее время. Посмотрим сначала, как это делается в EJB 2.1.
EJB-компонент Time среда EJB 2.1
Попробуем выявить сложности, которые вызывали трудность работы с EJB как у опытных разработчиков EJB, так и у начинающих. Наш гипотетический EJB-компонент можно описать при помощи простого интерфейса, показанного в листинге 1.
Листинг 1. Простой интерфейс Time
package org.developerworks.time;import java.util.Date;public interface Time { public Date currentTime (); }
|
Теперь преобразуем его в EJB. Сначала надо переопределить интерфейс, как показано в листинге 2.
Листинг 2. Интерфейс Time в EJB
package org.developerworks.time;import java.rmi.RemoteException;import java.util.Date;import javax.ejb.EJBObject;public interface Time extends EJBObject{ public Date currentTime () throws RemoteException; }
|
Весьма похоже, но все таки неприятно то, что интерфейс пришлось изменять. В расширении EJBObject, кажется, нет ничего плохого, потому что это обычный интерфейс-маркер (marker interface). Хуже всего то, что приходится менять сигнатуру метода для объявления того, что он генерирует исключение RemoteException. В EJB 2.0 эта проблема решается за счет добавления альтернативного локального интерфейса, как показано в листинге 3.
Листинг 3. Локальный интерфейс для Time
package org.developerworks.time;import java.util.Date;import javax.ejb.EJBLocalObject;public interface TimeLocal extends EJBLocalObject{ public Date currentTime ();}
|
Все в порядке, RemoteException больше не выдается. Конечно, все-таки мы создали два интерфейса для описания одного сервиса. Невозможно добиться, чтобы удаленный интерфейс расширял локальный (что казалось бы логичным), потому что его метод currentTime генерирует RemoteException, а локальный интерфейс этого не делает и т.д. Декларация этого интерфейса кажется нам вынужденной, но это еще ничего по сравнению с тем, что вы увидите при реализации.
Можно представить простую реализацию для исходного интерфейса, например, как в листинге 4.
Листинг 4. Реализация исходного интерфейса
package org.developerworks.time;import java.util.Date;public class TimeBean implements Time { public Date currentTime () { return new Date (); } public TimeBean () { }}
|
Это чересчур просто для EJB 2.1. В листинге 5 еще одна версия того же самого.
Листинг 5. TimeBean Реализация EJB
package org.developerworks.time;import java.rmi.RemoteException;import java.util.Date;import javax.ejb.EJBException;import javax.ejb.SessionBean;import javax.ejb.SessionContext;public class TimeBean implements SessionBean { public void ejbCreate () { } public Date currentTime () { return new Date (); } public void ejbActivate () throws EJBException, RemoteException { } public void ejbPassivate () throws EJBException, RemoteException { } public void ejbRemove () throws EJBException, RemoteException { } public void setSessionContext (SessionContext sessionContext) throws EJBException, RemoteException { } public TimeBean () { }}
|
Откуда появились все эти методы ejbXYZ? Они все санкционируются интерфейсом SessionBean. Они являются методами возврата жизненного цикла. Они очень полезны в сложных сценариях, в которых происходит много обработки и расчетов для жизненного цикла сложных компонентов сессии. Однако это классический случай программирования от и до (то есть, наихудший из возможных сценариев).
Но мы еще не закончили работу с версиией EJB 2.1. Нужно создать интерфейсы Home и LocalHome. Их использует контейнер, но обеспечивает разработчик. Например, в листинге 6 показан интерфейс Home.
Листинг 6. Интерфейс Time Home
package org.developerworks.time;import java.rmi.RemoteException;import javax.ejb.CreateException;import javax.ejb.EJBHome;public interface TimeHome extends EJBHome{ public static final String COMP_NAME= «java:comp/env/ejb/Time»; public static final String JNDI_NAME= «Time»; public Time create () throws CreateException,RemoteException;}
|
Интерфейс LocalHome почти такой же. Он расширяет код EJBLocalHome, а не EJBHome, и тогда его метод Create не будет генерировать исключение RemoteException.
В довершение всех неудобств нам еще придется написать дескриптор размещения для нашего EJB. Этот дескриптор размещения свяжет все воедино и даст контейнеру дальнейшие инструкции о том, как ему управлять EJB. В листинге 7 показан возможный дескриптор размещения для нашего компонента.
Листинг 7. Дескриптор размещения
<?xml version= «1.0» encoding= «UTF-8»?><ejb-jar id= «ejb-jar_1» xmlns= «http://java.sun.com/xml/ns/j2ee» xmlns:xsi= «http://www.w3.org/2001/XMLSchema-instance» xsi:schemaLocation= «http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd» version= «2.1»> <display-name>Time</display-name> <enterprise-beans> <!-- Session Beans -→ <session id= «Session_Time»> <display-name>Time</display-name> <ejb-name>Time</ejb-name> <home>org.developerworks.time.TimeHome</home> <remote>org.developerworks.time.Time</remote> <local-home>org.developerworks.time.TimeLocalHome</local-home> <local>org.developerworks.time.TimeLocal</local> <ejb-class>org.developerworks.time.TimeSession</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session></ejb-jar>
|
Надеюсь, теперь вы поняли, насколько трудно стало работать, когда появился EJB. Как же EJB 3.0 решает эту проблему? Посмотрим.
EJB-компонент Time среда EJB 3.0
Давайте заново напишем EJB-компонент Time при помощи EJB 3.0. Как и раньше, начнем с интерфейса, описывающего сервис. Только на этот раз работы по превращению его в интерфейс EJB будет меньше. Посмотрите на листинг 8.
Листинг 8. Интерфейс TimeBean
package org.developerworks.time;import java.util.Date;import javax.ejb.Remote;@Remotepublic interface Time { public Date currentTime ();}
|
Обратите внимание, насколько это похоже на листинг 1. Все, что мы добавили, аннотацию, которая объявляет, что этот интерфейс удаленный. Нам не пришлось расширять интерфейс и генерировать исключение RemoteException. Спецификация EJB 3.0 позволяет вообще не включать аннотацию, если класс реализации правильно аннотирован и реализует только один интерфейс. Но для тренировки полезно будет вставить сюда аннотацию, ведь с ней кодом станет легче управлять. Теперь можно перейти к реализации, представленной в листинге 9.
Листинг 9. Реализация EJB TimeBean
package org.developerworks.time;import java.util.Date;import javax.ejb.Stateless;@Statelesspublic class TimeBean implements Time{ public Date currentTime (){ return new Date (); }}
|
Такие EJB-компоненты часто называют простыми старыми Java-объектами (plain old Java objects POJO), потому что единственное указание на то, что это EJB аннотация @Stateless. Не нужно реализовывать никакие возвраты в составе интерфейса. Если вам потребуется реализовать такой возврат, вы сможете просто добавить метод и добавить аннотацию с объявлением возврата. Этому методу можно дать любое название, потому что реализуется не интерфейс.
Перейдем к дескриптору размещения. Постойте, да ведь он не один! Если вы еще раньше не убедились в важности EJB 3.0 (а соответственно, и Java EE 5), надеемся, теперь вам все понятно. Это огромный прорыв в обеспечении легкости разработки. Конечно, это всего лишь спецификация. Для того чтобы использовать все эти замечательные идеи, потребуется реализация. И тут появляются Geronimo 2.0 и OpenEJB 3.0.
Geronimo 2 Java EE 5
Вы разобрались лишь в самых базовых вещах, но наверняка уже поняли, что Java EE 5 далеко ушла от J2EE 1.4. В ней сохранились многие из старых понятий. Сервер приложений предоставляет те же сервисы, что и раньше (например, распределенные вычисления, управление транзакциями и персистентность). Однако API-интерфейсы для этих сервисов разительно отличаются. Теперь разрабатывать EJB значительно проще, но это значит, что серверы приложений Java EE 5 должны обеспечивать большую функциональность, чем ранее. Поэтому разработчикам Geronimo было чем заняться, когда пришла пора реализовывать спецификацию Java EE 5. Особенно это касалось OpenEJB, потому что, как я уже говорил, ее рассчитывали сделать основой для Geronimo, а в нем реализована революционно новая спецификация EJB 3.0.
На момент написания данной статьи Apache Geronimo прошел сертификацию Java EE 5.0 TCK. Все разработчики довольны возможностью использования нового API EJB 3 и развертывания более простого и понятного кода в Geronimo.
Статус Инкубатора
Интересно отметить, что проект OpenEJB теперь является одним из проектов в инкубаторе Apache Incubator. Группа разработчиков Apache Geronimo очень содействовала реализации OpenEJB в EJB 2.1, потому что это было ключевым вопросом для реализации Geronimo в J2EE 1.4. Однако OpenEJB еще не был полностью готов присоединиться к Apache. Потребовалось проделать массу бумажной работы, но сейчас OpenEJB часть Инкубатора. EJB 3.0 реализовывается как проект Apache, и его успешное завершение очень поможет OpenEJB получить статус Apache-проекта высшего уровня.
Заключение
В этой статье много говорилось об эволюции спецификаций J2EE и EJB. Вы увидели, насколько мощна эта спецификация, но также поняли, что это привело к сложности программной модели, в результате чего Java-разработчикам приходилось нелегко. Вы понимаете, что спецификации Java EE 5 и EJB 3.0 созданы для того, чтобы решить эти больные вопросы и повысить эффективность разработки на Java. Это значительно более простая программная модель, благодаря которой возрастает не только непосредственно производительность труда разработчика, результатом должны стать приложения, которые будет намного легче поддерживать и обслуживать.
В первом релизе Geronimo была реализована спецификация J2EE 1.4. OpenEJB сделало ее составной частью реализацию EJB 2.1. Сейчас в Geronimo реализуется спецификация Java EE 5, а дело OpenEJB реализовать спецификацию EJB 3.0. Уже многое сделано, поэтому советую вам скачать последний, значительно обновленный релиз Geronimo тогда вы почувствуете все преимущества Java EE 5 и EJB 3.0. Когда вы в следующий раз сделаете аннотацию для POJO, чтобы превратить его в EJB, не забудьте сказать спасибо группе разработчиков OpenEJB.
27.01.2008
Комментарии
Добавить комментарий (анонимные комментарии не публикуются!!!)
Новости и пресс-релизы СМ-Консалт
21.02.2012 12:42:20 Новая статья: IT и психология. Человеческий фактор в парном программировании: почему многие не получают желаемого от его внедрения?
Статья, находящаяся перед вами, открывает цикл статей о человеческом
факторе, Agile-практиках и других полезных приемах, используемых при
управлении командами в ИТ. Объединяет рассматриваемые практики и приемы
одно – они позволяют проявиться положительным эффектам, связанным с
человеческим фактором. И мы объясняем, почему с точки зрения психологии,
это происходит. Так сказать, подводим теоретическую и экспериментальную
базу под то, что себя уже давно зарекомендовало и работает. Или под то,
что работает не у всех, и потому является предметом оживленных споров и
дискуссий. И начинаем мы наши исследования с рассмотрения эффекта
парного программирования через призму экспериментов социальной
психологии.
Отдельную благодарность за рецензию и время, потраченное на прочтение
первого варианта статьи, выражаем Асхату Уразбаеву,
ценные замечания которого позволили не только улучшить данную статью,
но и позволили убедиться в необходимости и востребованности именно цикла
статей!
Читать -->
27.12.2011 16:15:27 Компания "СМ-Консалт" получила отзыв о работах в Федеральной Налоговой Службе (ГНИВЦ ФНС)
Специалистами ООО «СМ-Консалт» в 2010-2011г. был выполнен проект
по настройке и внедрению системы управления жизненным циклом разработки
программных систем в части управления изменениями и конфигурациями на
основе Microsoft Visual Studio Team Foundation Server 2010 для
Филиала Федерального государственного унитарного предприятия «Главный
научно-исследовательский вычислительный центр Федеральной налоговой
службы» в Приволжском Федеральном округе (Филиал ФГУП ГНИВЦ ФНС России в
ПФО).
28.11.2011 15:05:11 Новая статья: "Всегда ли «Да» – это «Да»? Или как нас вынуждают принимать решения"
Мы предлагаем вашему вниманию цикл статей, в основу которых положены
психологические практики и приемы, позволяющие влиять на решения,
принимаемые людьми. Эта идея была логическим продолжением ряда
выступлений с докладами о коммуникациях в проектах разработки и
внедрения ПО. Давайте, не откладывая в долгий ящик, начнем с самого
простого приема убеждения, с которым сталкиваемся ежедневно в магазинах,
в транспорте, в разговорах с коллегами… да мало ли где еще!
Авторы: Новичков Александр и Карабанова Галина.
Читать -->
10.10.2011 11:16:06 Компания «СМ-Консалт» открывает новое направление продаж - ПО Adobe Connect
Программное обеспечение Adobe Connect является гибкой системой
web-коммуникации с высоким уровнем информационной безопасности. Adobe
Connect предоставляет такие важнейшие функции корпоративного
взаимодействия, как деловое общение и совместная работа сотрудников на
уровне предприятий, дистанционное обучение, организация широкомасштабных
сетевых семинаров и презентаций. Система Adobe Connect базируется на
технологии Adobe Flash, а также Air, и поэтому позволяет подключать
сотрудников к единому пространству взаимодействия через web-браузер с
любых устройств.
17.09.2011 21:40:22 Новая статья: "Разработка прикладного программного обеспечения с использованием Rational Unified Process на Иркутском Авиационном заводе"

На сайте СМ-Консалт открыт новый раздел Статьи наших заказчиков об успешных внедрениях IBM Rational и Microsoft. Статьи для данного раздела пишутся нашими заказчиками и рассказывают о сути проектов внедрения технологий IBM и Microsoft. Первая статья, представленная вашему вниманию написана сотрудниками Иркутского Авиационного Завода (ИАЗ).
Иркутский авиазавод имеет длительный опыт разработки программного
обеспечения для информационной поддержки ключевых бизнес-процессов
предприятия. Однако, в связи с увеличивающейся сложностью и повышением
требований к разрабатываемому программному обеспечению, возникла
настоятельная необходимость усовершенствовать процесс разработки:
повысить качество разрабатываемых программных продуктов,
стандартизировать процесс с увеличением его эффективности.
С целью повышения качества программного обеспечения собственной
разработки и сокращения сроков разработки руководство Управления
информационных технологий (УИТ) Иркутского Авиационного Завода в 2006г. приняло решение о внедрении технологии разработки ПО на базе методологии Rational Unified Process и с использованием инструментов автоматизации IBM Rational.
13.09.2011 12:07:29 Новый тренинг «Коммуникации и психология межличностных отношений в ИТ-проектах»

Компания «СМ-Консалт» представляет новый тренинг, организуемый совместно с компанией «КарьерKаб» - «Коммуникации
и психология межличностных отношений в ИТ-проектах.
Тренинг позволит понять, насколько коммуникации в проектах важнее инструментов, что люди и их взаимоотношения зачастую оказываются решающим фактором, определяющим успех проекта. Если более пятидесяти процентов рабочего времени вы тратите на взаимодействие с заказчиком, если вам небезразлична судьба вашей команды и вы хотите, чтобы ваша команда работала как часы, реализуя проекты точно, вовремя и без перерасхода ресурсов - наш тренинг поможет в этом.
01.08.2011 17:44:25 Наша компания получила отзыв о сотрудничестве с ОАО «Нордеа Банк»

В 2010-2011 гг. наши специалисты провели в Нордеа Банке проект по предварительному обследованию, развертыванию инструментальных средств и ряд тренингов по обучению методологии и работе с продуктами IBM Rational: «Методология разработки программных систем IBM Rational Unified Process», «Управление требованиями с использованием IBM Rational RequisitePro», «Управление изменениями в IBM Rational ClearQuest».
24.06.2011 01:27:57 Бесплатный семинар-вебинар «Повышение эффективности IT подразделений и качества разрабатываемого ПО с использованием современных методологий и технологий»
Компании СМ-Консалт , Legal SoftWaveTM и DNA приглашают Вас посетить бесплатный семинар-вебинар, посвященный обзору технологий и методологий, которые позволяют повысить эффективность ИТ подразделений. На семинаре рассматриваются технологии IBM Rational, Microsoft TFS, а также системы аналитической обработки информации (Business Intelligence) (IBM SPSS, Deductor, QlikView и другие).
Планируемая продолжительность семинара - 8 академических часов.
Место проведения: Санкт-Петербург (очно) и Интернет (для всех желающих: приходите сами и приглашайте друзей!).
Дата и время: 14 июля 2011 в 9 00.
ВНИМАНИЕ: если вы не сможете очно приехать на семинар - это не страшно, так как семинар будет транслироваться через интернет в формате вебинара и к нему, после регистрации, смогут присоединиться все желающие. Трансляция будет осуществляться посредством технологии Adobe Connect Pro , это позволит Вам присоединяться к конференции без установки дополнительного ПО - только интернет браузер.
Смотреть программу -->
07.06.2011 13:02:44 Компания "СМ-Консалт" провела серию успешных семинаров для ГНИВЦ ФНС России

Проведенные семинары были посвящены средствам разработки и тестирования программного обеспечения компании Майкрософт для сотрудников ГНИВЦ ФНС России. Слушатели семинаров отметили высокую квалификацию тренеров компании "СМ-Консалт" по организации учебного процесса и повышению квалификации специалистов, прошедших обучение.
Индивидуальный подход при решении любых вопросов, возникающих в процессе обучения, оперативность принятия решений, гарантированное выполнение взятых на себя обязательств и профессионализм позволили провести обучение на самом высоком уровне.
07.12.2010 12:28:15 Мы идем в Твиттер!

Наша компания открыла аккаунт в системе микроблоггинга Twiter.Теперь все официальные и неофициальные новости будут появляться в нашей ленте в Twitter.
Там же возможно будет задать прямые вопросы специалистам СМ-Консалт, по всем вопросам, связанным как с деятельностью компании, так и с техническими аспектов продуктов IBM и собственных решений СМ-Консалт.
Следуйте за нами!
https://twitter.com/cmconscom
11.11.2010 14:14:14 Осенний марафон Microsoft ALM Road Show
Компания СМ-Консалт совместно с образовательным центром Careerlab провели серию семинаров в рамках мероприятий ALM Roadshow 2.0 в крупнейших городах, расположенных на Волге, – крупных научных центрах, в которых ИТ технологии находятся на высоком уровне. Семинары прошли в Самаре, Нижнем Новгороде и Казани. Cеминары были посвящены использованию новых инструментов MS Visual Studio Team System в проектах разработки ПО.
В семинарах принимали участие представители различных ролей процесса разработки ПО: от разработчиков до руководителей предприятий различного уровня. Темы, обсуждаемые в ходе семинара, вызвали большой интерес аудитории и немалое количество вопросов, на которые были предоставлены исчерпывающие ответы. В процессе семинара также было показано большое количество примеров, которые дают представление о возможностях инструментов MS Team System. Средняя оценка за семинар составила 4,6 балла по пятибальной шкале
08.09.2010 18:37:52 Скидки до 30% на программное обеспечение IBM Rational

Компания СМ-Консалт предлагает для всех желающих на льготных условиях приобрести программное обеспечение IBM Rational. Снижение цен связано с тем, что мы стараемся быть как можно ближе к нашим клиентам, многие из которых постепенно начали преодолевать последствия финансового кризиса.Наше предложение поможет с минимальными издержками приобрести ПО IBM Rational, что является хорошим капиталовложением.
Скидки до 1 декабря 2010 года:
- 20% скидки при покупке IBM Rational ClearCase, ClearQuest, CearCase LT, при приобретении пяти и более лицензий*;
- 30% скидки при покупке пяти любых продуктов IBM Rational + решение или тренинг СМ-Консалт*.
Для получения деталей обязательно свяжитесь с нашими менеджерами
|