Monday, April 21, 2008

Создание Java-расширений для OpenOffice.org

Продолжение здесь.

OpenOffice.org - это не только набор офисных программ, это еще и платформа для разработки приложений и расширений.

В этом посте я расскажу как создать простое расширение для OOo. Мое расширение будет вести журнал активности пользователя, а именно фиксировать когда и какие файлы были открыты, сохранены или распечатаны.

Хорошей отправной точкой для знакомства с программирование для OOo является книга OpenOffice.org 2.3 Developer's Guide (она же в PDF, 17 МБ), на основе которой я и сделал свою реализацию.

API SDK, которым мы будем пользоваться для создания нашего расширения, позволяет получить полный контроль (в том числе удаленно по сети) над офисными приложениями OOo. Достигается это за счет использования технологии компонентного программирования UNO (Universal Network Objects). На сегодняшний день API SDK доступно практически для всех языков программирования, включая Java, C++, CLI (C#, VB.NET), Python и других, включая встроенный скриптовый язык OOo Basic.

Мы будем пользоваться привязкой UNO к языку Java.

Для создания UNO компонентов разработчики OOo предлагают инструменты для интеграции с разными IDE, в частности, есть плагины для Eclipse и NetBeans. NetBeans я не смотрел, хотя в книге есть ссылки только на NetBeans, а вот для Eclipse плагин я посмотрел. Все, что он делает - это позволяет создавать простые компоненты, задействуя утилиты OOo для компиляции собственных IDL интерфейсов в java-классы.

В нашем случае эта возможность не потребуется - мы не будем создавать своих интерфейсов, вместо этого мы будем пользоваться готовыми интерфейсами SDK OOo, в частности com.sun.star.task.XAsyncJob, который позволит интегрировать в окружение OOo наш сервис, который подключится к шине обработчиков событий документов OOo.

Наше расширение мы будем создавать при помощи Maven2. Следует отметить, что у разработчиков OOo есть плагин для интеграции с Maven2 (maven-ooo-plugin), но:

  1. его нет в публичных репозиториях, а можно только скачать исходники из репозитория OOo и собрать плагин самому;
  2. он, также как и плагины для IDE, поддерживает только интеграцию с утилитами OOo, например, для компиляции IDL интерфейсов в java-классы;
  3. он все еще находится на стадии разработки и не поддерживает необходимые функции, например, сборку артефактов в готовый компонент *.oxt.
Вот, что у меня получилось в итоге (см. рисунок)

После запуска mvn clean verify на выходе мы получим готовую сборку расширения activity-monitor-service-1.0.oxt.

Файл oxt (OOo eXTension) представляет собой zip-архив со следующим содержимым:

activity-monitor-service-1.0.oxt \
META-INF \
manifest.xml
activity-monitor-service-1.0.jar \
META-INF \
MANIFEST.MF
org \ ...
description.xml
jobs.xcu

manifest.xml


Файл манифеста, который описывает содержимое этого oxt-архива. Здесь перечислены *.xcu и *.jar файлы.
<?xml version="1.0" encoding="UTF-8"?>
<manifest:manifest>
<manifest:file-entry
manifest:full-path="${artifactId}-${version}.jar"
manifest:media-type="application/vnd.sun.star.uno-component;type=Java" />
<manifest:file-entry manifest:full-path="jobs.xcu"
manifest:media-type="application/vnd.sun.star.configuration-data" />
</manifest:manifest>

activity-monitor-service-1.0.jar


В этом jar'е находятся классы реализации нашего расширения.

У нас, класс, который реализует интерфейс com.sun.star.task.XAsyncJob (org.keyintegrity.ooo.ActivityMonitor), также является регистрационным классом, то есть в нем реализованы два статических метода - фабрика сервиса и регистратор сервиса. Для их реализации в SDK входит два класса-помощника (первый, второй). Так как это статические методы, то они не могут быть навязаны каким-то интерфейсом, про них нужно просто помнить. Интерфейс com.sun.star.lang.XServiceInfo предоставляет OOo информацию о сервисах, которые предоставляет данный компонент.

MANIFEST.MF


Стандартный манифест jar-файла, в котором содержится указание на регистрационный класс нашего сервиса.

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: dmitrygusev
Build-Jdk: 1.5.0_06
RegistrationClassName: org.keyintegrity.ooo.ActivityMonitor

description.xml


Файл описания нашего расширения. Такая информация, как версия расширения, версия OOo, для которого оно было разработано и др. хранится здесь.
<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006"
xmlns:d="http://openoffice.org/extensions/description/2006"
xmlns:xlink="http://www.w3.org/1999/xlink">
<version value="${version}" />
<dependencies>
<OpenOffice.org-minimal-version value="2.4"
d:name="OpenOffice.org 2.4" />
</dependencies>
</description>

jobs.xcu


Конфигурационный файл, который регистрирует наш сервис, а именно подписывает его на события OnLoad, OnSaveDone, OnSaveAsDone и OnPrint. Сюда также можно включить конфигурационную информацию для сервиса - у нас это имя файла, где ведется журнал.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE oor:component-data SYSTEM "../../../../component-update.dtd">
<oor:component-data oor:name="Jobs" oor:package="org.openoffice.Office"
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node oor:name="Jobs">
<node oor:name="MonitorJob" oor:op="replace">
<prop oor:name="Service">
<value>org.keyintegrity.ooo.ActivityMonitor</value>
</prop>
<node oor:name="Arguments">
<prop oor:name="fileName" oor:type="xs:string"
oor:op="replace">
<value>c:/Temp/activity-monitor-service.log</value>
</prop>
</node>
</node>
</node>
<node oor:name="Events">
<node oor:name="OnLoad" oor:op="fuse">
<node oor:name="JobList">
<node oor:name="MonitorJob" oor:op="replace" />
</node>
</node>
<node oor:name="OnSaveDone" oor:op="fuse">
<node oor:name="JobList">
<node oor:name="MonitorJob" oor:op="replace" />
</node>
</node>
<node oor:name="OnSaveAsDone" oor:op="fuse">
<node oor:name="JobList">
<node oor:name="MonitorJob" oor:op="replace" />
</node>
</node>
<node oor:name="OnPrint" oor:op="fuse">
<node oor:name="JobList">
<node oor:name="MonitorJob" oor:op="replace" />
</node>
</node>
</node>
</oor:component-data>


Естественно, все не так просто, как кажется на первый раз. Если оставить в стороне сложности, связанные с разборками в API OOo (они хотя бы описаны в книге), то на первый фон выходит создание каркаса проекта для расширения OOo и его реализация с Maven2.

Во-первых, как оказалось для версии SDK 2.4.0 в открытых Maven2 репозиториях еще нет артефактов необходимых артефактов. Поэтому пришлось делать их самому. Здесь помог тот самый Eclipse плагин. При создании проектов с его помощью в CLASSPATH проекта вставляются ссылки на необходимые jar'ы. Как оказалось, они идут в поставке самого OOo (даже не SDK):

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="source"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="build"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/juh.jar"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/jurt.jar"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/officebean.jar"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/ridl.jar"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/unoil.jar"/>
<classpathentry kind="lib" path="C:/dev/bin/ooo-2.4/program/classes/unoloader.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Именно из этих jar'ов я сделал артефакты и установил себе в локальный репозиторий.

В конце поста есть архив с готовыми артефактами; все что нужно - скопировать их себе в репозиторий.

Структура Maven2 проекта сделана таким образом, что все содержимое папки src/main/oxt будет скопировано в корень oxt-архива, который получается при сборке проекта. Эта папка является ресурсной папкой проекта и при сборке все содержимое фильтруется, так что в файлах конфигурации можно использовать выражения подстановки (например, ${version} в файле description.xml).

Я постарался сделать эту структуру как можно более универсальной, чтобы на ее основе каждый cмог сделать своё собственное расширение для OOo. Может быть кто-нибудь сделает из нее archetype?

Установка расширения в OOo


Чтобы установить расширение достаточно запустить *.oxt файл на выполнение (щелкнуть по нему два раза :), чтобы запустился Extension Manager OOo. Предварительно нужно закрыть все офисные приложения, иначе может быть поврежден реестр OOo.

Жмем OK и расширение установлено.

Примечание: Если устанавливать расширение повторно, то сначала нужно его удалить; в противном случае появится ошибка "Could not create java implementation loader". Правда, если попробовать еще раз - установка пройдет нормально.

Теперь можно проверить наш сервис в работе. Для этого откройте, сохраните или напечатайте какой-нибудь документ из любого приложения OOo. В файле журнала появятся записи, что-то вроде:

Mon Apr 21 00:19:35 MSD 2008 OnLoad file:///C:/Temp/ActivityMonitor.odt
Mon Apr 21 00:19:38 MSD 2008 OnSaveDone file:///C:/Temp/ActivityMonitor.odt
Mon Apr 21 00:19:45 MSD 2008 OnSaveAsDone file:///C:/Temp/ActivityMonitor-Modified.odt

Отладка расширения


Чему я всегда восхищался в отладчиках, так это возможности подключаться к любому процессу (локальному или удаленному). В Java это делается очень просто, благодаря JPDA.

При запуске OOo регистрирует все обработчики в своей шине событий на основании конфигурационных файлов (*.xcu). Когда очередное событие срабатывает оно идет по цепочке обработчиков и если очередной обработчик написан на Java, то OOo запускает JVM, в которую загружает этот обработчик.

Список виртуальных машин, доступных OOo, можно найти в меню Сервис | Параметры... ветка OpenOffice.org/Java.

Для того, чтобы к JVM можно было подключиться по JDWP нужно ее запускать с ключиками:

-Xdebug
-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n


Эти ключики можно вписать в окошке Параметры... конкретной JRE.

После этого к нашему сервису можно подключаться, например, из Eclipse. Для этого нужно выбрать Run | Open Debug Dialog... Создать новую конфигурацию в ветке Remote Java Application (дважды на ней щелкнуть). Параметры по умолчанию вновь созданной конфигурации подойдут, если в параметры JVM вы добавили точно такие строчки, как я показал выше.

Если нажать Debug, то Eclipse подключится к работающему экземпляру JVM OOo. Можно поставить точки останова, где нужно и ждать, пока вызов дойдет до нужной точки.

Примечание: Если при нажатии Debug Eclipse скажет "Connection refused" это значит, что OOo еще не загрузил экземпляр JVM, потому что наш обработчик еще не был ни разу вызван.


Примечание: В путях к OOo и SDK не должно быть пробелов. Для этих целей я пользуюсь утилитой junction, чтобы создавать символьные ссылки. Например, для OOo я сделал такую ссылку:

junction.exe c:\dev\bin\ooo-2.4 "c:\Program Files\OpenOffice.org 2.4"

Примечание: Все "раскрашенные" исходники я сделал с помощью Eclipse-плагина java2html и GNU Source-Highlight.

Файлы для загрузки


Файл проекта (исходники + собранный файл *.oxt) (13 КБ)
Maven2 артефакты SDK OOo 2.4 (1.4 МБ)

Примечание: Чтобы установить артефакты себе в локальный Maven2 репозиторий нужно распаковать архив в папку <userdir>/.m2/repository.

Примечание: Чтобы собрать проект и получить oxt файл, нужно выполнить mvn clean verify.

Примечание: Чтобы загрузить исходники в Eclipse, нужно предварительно выполнить mvn eclipse:eclipse. Затем в Eclipse File | Import... | Existing projects into Workspace | Next > выбрать папку с проектом и нажать Finish.

Thursday, April 03, 2008

AnjLab.SyncIT - все задачи в Microsoft Outlook

... в продолжение предыдущего поста.

Ввиду специфики моей деятельности (учеба, преподавание, работа/программирование, open source :) у меня каждый день копится очень много текущих задач, которые я не успеваю сделать за один день, а завтра вообще могу о них забыть и вспомнить в самый неподходящий момент.

Самый лучший способ этого избежать - это записать их себе в Outlook в виде задач.


Помимо прочих, в отдельную группу можно вынести те задачи, которые мне назначаются в процессе работы над проектами. Это могут быть, например, тикеты (bug'и, новые задачи и т.п.) в Trac'е, или задачи в dotProject, на которые я назначен ответственным.

В среднем за день приходит по 2-3 таких задачи. У меня все проекты настроены так, что при добавлении/изменении/удалении задачи мне на почту приходят уведомления и, чтобы планировать их вместе с остальными задачами приходится добавлять их ручками в список текущих задач Outlook.

Здесь есть несколько проблем, которые сводятся к тому, что следить за задачами в разных системах и ручками записывать себе детали каждой задачи - мягко говоря, лень :) Ни для кого не секрет, что программисты ленивые люди и рутина их вводит в уныние.

Чтобы перебороть эту лень :), у нас с Юрой возникла идея сделать приложение, которое бы следило за всеми моими задачами и автоматически синхронизировало их со списком моих текущих задач в Outlook.

На самом деле, поводом для этих двух постов об Outlook как раз и стал выход первого официального публичного релиза AnjLab.SyncIT - Open Source проекта, над которым мы работали последние 2 недели и который позволяет решить описанные проблемы.

Изначально планировалась только поддержка Trac'а, потому что и мы в keyintegrity и Юра в AnjLab используем Trac для ведения своих проектов (отсюда, кстати, и начальное название проекта - outlooktrac).

Так как хостинг outlooktrac располагается на Google Code, то второй системой, которую мы решили поддержать стал Google Code.

Ну и, наконец, поддержку dotProject'а я включил потому, что мы используем ее в keyintegrity для поддержки наших внутренних процессов.

Скачать последнюю версию, включая исходники, можно со страницы проекта.

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

Мой Outlook

В Outlook'е есть две вещи, которые мне нравятся и которыми я пользуюсь каждый день - это календарь и задачи. Да, я не пользуюсь почтой в Outlook, потому что Gmail пока никто еще не победил :)

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

Кстати, к разговору о Gmail, у Google тоже есть календарь, но каких-то весомых преимуществ перед Outlook'ом я пока в нем не нахожу. Единственная польза, которую я из него извлек - это двухсторонняя синхронизация с Outlook'ом, благодаря которой я могу открыть свой календарь для Насти и подписаться на ее календарь, чтобы вместе планировать наше время.


Обычно, события, встречи и собрания в календаре задаются один раз и на пол года, и в течение этого времени практически не изменяются. Вся "текучка" - в задачах, о которых в следующем посте.

Wednesday, March 12, 2008

Lifetime Management with BPEL (Part III)

В июне 2006-го я начал этот блог чтобы делиться результатами своей деятельности в keyintegrity.

В то время я ходил в американский дом и мой английский был "в апогее" и, может быть поэтому, я начал блог на этом языке. Почти сразу же я понял, что задумка оказалась неудачной - это можно заметить по количеству английских постов - их 3 :)

Хотелось делиться этой информацией и обсуждать ее, причем делать это с русскими. Чтобы мои сокурсники или хотя бы какие-то студенты из моего университета услышали про такие технологии, как BPEL. Было очень обидно когда никто, включая самых молодых преподавателей, не понимал, что ты делаешь и чем занимаешься, хотя бизнес-процессы, их описание и управление - были одним из главных направлений моей кафедры. Но дальше SADT-анализа и UML никто не видел/не хотел видеть/не хватало времени заниматься... Не с кем было поговорить и обсудить эти темы не только на английском (где они и где мы), но и на русском... Может быть это и стало одной из основных причин, почему я длительное время вообще ничего сюда не писал.

Чтобы хоть как-то исправить ситуацию я написал курсовую работу Webseller и даже "выбил" академическую лицензию дизайнера ActiveBPEL для кафедры (тогда он еще был платным). На следующий год, кстати, по ActiveBPEL были поставлены лабораторные работы... Было приятно :)

Кстати, сейчас похоже их линейка называется ActiveVOS...

Но это все лирика, начатое всеравно нужно завершать, поэтому я назвал этот пост - Lifetime Management with BPEL (Part III), чтобы наконец-то закончить эту серию. Я не буду писать на английском и не буду здесь представлять законченного примера использования этого паттерна. Я даже не буду писать на BPEL, просто опишу словами то, что хотел.

Чтобы реализовать то, о чем я писал в предыдущей части нужно процесс (или его часть/scope, в которой определено состояние, например, содержимое корзины) заключить в контейнер Pick с несколькими обработчиками сообщений, среди которых должны быть:
  1. обработчики onMessage, которые меняют состояние процесса (например, изменяют наполнение корзины);
  2. обработчики onMessage, после которых процесс выйдет из scope'а (например, товары из корзины пойдут на оформление заказа);
  3. обработчик onAlarm, который определяет время жизни состояния, после которого состояние должно сброситься.
Действие обработчиков 1 и 2 должны заканчиваться асинхронным вызовом этого же процесса. Изюминка заключается в том, что эти вызовы нужно выравнять при помощи correlationSet с контейнером Pick, чтобы последующие вызовы обработчиков этого процесса работали с той же корзиной. Это позволяет после каждого изменения состояния корзины продлевать время ее жизни на интервал, указанный в onAlarm.

В correlationSet в данном случае можно передавать, например, идентификатор корзины, по которому можно найти ее в БД.

Вот собственно и все. Лучше поздно, чем никогда :)

P.S.
Второй причиной, почему английский язык плох для ведения блога - потому что он не родной для меня и сковывает меня в красноречии :)

Кстати, этот же вывод я сделал по опыту разработок в нашей компании. Программисты не пишут комментарии... Это относится и к коду, и к документации (я имею в виду javadoc) и к комментариям к комитам...

Правилом хорошего тона является английский язык в комментариях - ведь код будут читать другие, особенно если это open source проект... Но всеже лучше что-то, чем совсем ничего... После того, как мы стали использовать русский язык в наших проектах, производительность заметно повысилась (как минимум один живой пример этому есть - это я :). И уже не лень и не напрягает написать пару лишних строк в описании метода, которые иллюстрируют примеры его использования и т.д. и т.п.

Практика сложилась так, что наши (русские) программисты умеют лучше читать и понимать английский, чем писать на нем и им разговаривать.

Ну, а если возникнет необходимость описать API, то его можно продублировать на английском языке - перевести самому или будет дешевле передать эту задачу переводчикам.

С одной стороны меня греет то, что русский open source от этого только выиграет, по крайней мере я так думаю :)

А с другой стороны есть правило - комментарии писать на языке заказчика. Так что делайте выводы сами.

Thursday, February 28, 2008

Социальные сервисы укрепляют корни :)

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

Недавно я зарегистрировал в одноклассниках свою маму :) У нее вообще вызвало неописуемый восторг, после того как она нашла знакомых с которыми не виделась больше 30 лет!

Но помимо знакомых, оказалось, что у нас очень много родственников, причем, о которых я даже и не подозревал. Точнее я всегда знал, что родственников у нас много и что кто-то живет за границей (в Европе, в Штатах), кто-то в СНГ, а кто-то по России... И у меня давно была мысль построить генеалогическое дерево, чтобы узнать - сколько же всетаки у нас в роду человек, где они живут/жили, как их зовут, кто они есть, чем занимаются, ну и так далее... Я думаю, я не один такой - интересно же :)

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

Пока на прошлой неделе не набрел на отличный сервис - kindo.ru. За каких то пару часов я завел 100 (!) человек и до сих пор в голове есть те, которых я знаю и которые на очереди туда попасть... :)

И в основном это заслуга интерфейса - он очень удобный и радует глаз своей красотой и динамикой (Flash во всей своей красе :). Чтобы добавить родственника - нужно просто щелкнуть на том, с кем у него есть родственная связь и выбрать один из вариантов:

Мама, папа, братья, сестры, дяди, тети, бабушки и их родственники - сразу же всплывут в памяти :)

Кроме того, если у кого-то из родственников есть Интернет и он умеет им пользоваться (Настя, привет :) то можно отправить им приглашение и они будут вместе с вами заполнять ваше семейное древо!

Сервис еще достаточно молодой, хотя уже переведен на 12 (поправьте меня, если я не прав) языков, включая русский и даже китайский :) Хотя, потенциал у него, мне кажется , огромный. Конечно, это всего лишь поделка по сравнению с настоящими генеалогическими системами, с которыми работают ученые генеалогии, но социальный аспект наряду с простотой использования могут сыграть здесь свое дело.

Тем более, что для начала ничего больше и не надо, а, чуть погодя, создатели обещают добавить функции экспорта древа в формат GEDCOM, от которого можно будет сделать следующий шаг, если кого-то потянет на более серьезные исследования :)

P.S.
В команде Kindo есть русские :)

Sunday, February 17, 2008

Yandex is a Russian feed aggregator

Сегодня в статистике FeedBurner появился новый RSS-агрегатор Yandex Blog Search

Напомню, что с первого июня 2007 FeedBurner принадлежит Google, и врятли в Google не знают, что такое Яndex...

Но для Google Яndex всего лишь русский RSS-агрегатор :)

Friday, February 15, 2008

Top 100 living geniuses

Наткнулся сегодня на список ста ныне живущих гениев от The Daily Telegraph

Wednesday, January 16, 2008

16-го января 2008 - День покупок

Сегодня Oracle купила, наконец-таки, BEA. Рано или поздно этого следовало ожидать.

И еще одна, уже неожиданная для меня новость. В блоге MySQL появился пост о том, что Sun хочет купить MySQL. Очень интересно будет понаблюдать за этой ситуацией.

Friday, December 21, 2007

Проблемы с консолью Windows

Если в Java-приложении на консоль выводится информация на русском языке (например при запуске тестов через Maven2), то Windows все русские символы по умолчанию выводит как абракадабру:



Раньше я не обращал особо на это внимание, потому что всеравно отладку делаю в Eclipse, где все нормально. Давно надо было уже пофиксить - вот здесь рассказывается как (меняем кодовую страницу chcp 1251 и ставим шрифт Lucida Console).

Обновление 04.05.2008
Опять столкнулся с этой проблемой, только теперь в установке Oracle BI. При установке можно было выбрать на каком языке выводить сообщения сервера. Я выбрал русский и в консоль опять полезла абракадабра.

После установки Oracle BI OC4J запускается автоматически при запуске Windows (в реестре делается соответствующая запись со ссылкой на oc4j.cmd). Я сделал свой командный файл и обновил запись в реестре, чтобы она указывала на мой файл. Вот что в этом файле:


TITLE oc4j-bi
CHCP 1251
"E:\OracleBI\oc4j_bi\bin\oc4j.cmd" %1

При первом запуске нужно зайти в свойства окошка консоли и выбрать шрифт Lucida Console и при сохранении свойств выбрать "Применить настройки для всех окон с таким заголовком".


Проблема номер два, но это уже скорее к Windows, чем к консоли.
В очередной раз наткнулся на проблему с превышением длинны командной строки (8Кб максимум). Причиной стал JPOX Enhancer, который строит слишком длинную строку для запуска своей утилиты. Пришлось делать workaround.

Все это про Windows XP, не знаю, изменилось ли что-то в Vista?

Идентификация сервисов SOA от IBM

Пришла сегодня рассылка от IBM developerWorks Россия "Моделирование SOA: Часть 1. Идентификация сервисов".

Это перевод статьи, а оригинал датируется вторым октября 2007.
Интересно, что в этот же день я читал доклад на семинаре, в котором затрагивалась эта же тема.
Разница лишь в том, что IBM иллюстрирует подход на примере UML и семействе продуктов IBM® WebSphere® (в частности Business Modeler), а я использовал BPMN для этих целей.

Saturday, November 24, 2007

SOA в корпоративной информационной системе

Написал черновик статьи, в которой попытался собрать различные высокоуровневые методологии/технологии (SOA, бизнес-процессы, автоматизация, OLTP, OLAP и т.д.) в единую информационную систему.
Получилось довольно размыто, обзорно и, естественно, туда поместилось не все, что хотелось. Но для закрепления определенного этапа - я думаю достаточно.

SOA в корпоративной информационной системе (161 КБ)

Обновление 25.04.2008

Статья опубликована: Вестник филиала Всероссийского заочного финансово-экономического института в г. Владимире. Выпуск 2. - Владимир, 2007. - 218 с. ISBN 5-89368-767-1 стр. 109-113

Обращение к private-элементам в Java (Java Reflection)

Недавно у нас с Ивом состоялся разговор о private-элементах Java (приватные классы, поля и т.д.)
Он был уверен, что если класс объявлен как приватный - его экземпляр нельзя создать где-либо еще, кроме как из класса, в котором он был объявлен. То же самое с приватными полями - если поле описано с модификатором доступа private, то к нему нельзя получить доступ если нет соответствующих getter/setter-методов.

На самом деле, механизм Java Reflection позволяет сделать с кодом все, что угодно и получить доступ к любой информации о коде и к состоянию объектов.

PublicClass.java

01
02 public class PublicClass {
03
04
/**
05
* Значение этой переменной нельзя непосредственно установить из Java-кода
06 * оператором присваивания, но, как будет видно дальше, это значение можно
07 * изменить при помощи механизма рефлексии.
08 */
09 private int a = 0;
10
11 public int getA() {
12 return a;
13 }
14
15 /**
16 * Это приватный класс. Дальше в примерах мы создадим экземпляр этого класса
17 * и вызовем на нем метод <code>toString()</code>.
18 *
19 * Этот класс может существовать только в контексте экземпляра
20 * {@link PublicClass}; мы увидим, как можно установить контекст для нового
21 * экземпляра {@link PrivateInnerClass}.
22 *
23 * @author dmitrygusev
24 *
25 */
26 @SuppressWarnings("unused")
27 private class PrivateInnerClass {
28 @Override
29 public String toString() {
30 return "Hello from PrivateInnerClass instance!";
31 }
32 }
33
34 }


TestAccessPrivateMembers.java

01 import static org.junit.Assert.assertEquals;
02
03 import java.lang.reflect.Constructor;
04 import java.lang.reflect.Field;
05 import java.lang.reflect.Member;
06
07 import org.junit.Test;
08
09 public class TestAccessPrivateMembers {
10
11 /**
12 * Получим список объявленных конструкторов. Методы
13 * <code>java.lang.Class.getDeclaredXXX()</code>, например,
14 * {@link Class#getDeclaredConstructors()}, возвращают список всех
15 * объявленных элементов ({@link Member}), а не только
16 * <code>public</code>.
17 *
18 * Если нужно получить только <code>public</code> элементы, то можно
19 * воспользоваться методами <code>java.lang.Class.getYYY()</code>
20 * (например, {@link Class#getConstructors()}).
21 *
22 * @see java.lang.reflect.Member
23 * @see java.lang.Class
24 * @see java.lang.reflect.Field
25 * @see java.lang.reflect.Method
26 * @see java.lang.reflect.Constructor
27 */
28 @Test public void accessPrivateMembers() throws Exception {
29 /*
30 * В данном случае у нас лишь один inner-класс - PrivateInnerClass
31 */
32 Class<?> clazz = PublicClass.class.getDeclaredClasses()[0];
33
34 /*
35 * Получим его конктруктор по умолчанию
36 */
37 Constructor<?> constr = clazz.getDeclaredConstructors()[0];
38
39 /*
40 * Установим признак доступности этого конструктора, чтобы его можно
41 * было вызвать
42 */
43 constr.setAccessible(true);
44
45 /*
46 * Создадим класс-контекст для внутреннего класса
47 */
48 PublicClass pc = new PublicClass();
49
50 /*
51 * Создадим экземпляр внутреннего класса, передав класс-контекст в
52 * качестве параметра конструктору
53 */
54 Object o = constr.newInstance(pc);
55
56 /*
57 * Вызовем метод toString() на внутреннем классе
58 */
59 assertEquals("Hello from PrivateInnerClass instance!", o.toString());
60
61 /*
62 * Прочитаем значение private-переменной через соответствующий
63 * getter-метод
64 */
65 assertEquals(0, pc.getA());
66
67 /*
68 * Изменим значение этой private-переменной. Для этого нужно получить
69 * соответствующий объект java.lang.reflect.Field, у которого есть метод
70 * Field.set(object, value).
71 */
72 Field fieldA = pc.getClass().getDeclaredField("a");
73
74 fieldA.setAccessible(true);
75
76 fieldA.set(pc, 2);
77
78 /*
79 * Прочитаем значение private-поля - оно должно быть равно 2
80 */
81 assertEquals(2, pc.getA());
82 }
83
84 }

Tuesday, November 06, 2007

Сувениры Java

Заметил, что у меня накопилось уже много сувениров так или иначе связанные с тематикой Java. Буду выкладывать их в этот пост, интересно посмотреть... :)

Постер JavaPolis 2007


Прислали сегодня приглашение на JavaPolis 2007, в конверте был постер конференции. Пока что это эксклюзив, его видели меньше 3000 человек в мире :) Точнее те из них, кто также запросил подтверждение о регистрации на конференции :)

Резиновый Duke

На Sun Tech Days 2006 в Москве и Sun Tech Days 2007 в Питере ведущий (не помню, как его зовут... Джефри?), который объявлял спикеров, да и все спикеры, включая Джеймса Гослинга, во время выступлений кидали в зал резиновых Duke'ов, футболки с логотипами Duke/Sun/Java и прочие сувениры.
Этот Duke с STD2007, его поймала моя Настя :) Стоит сейчас у нас дома на компьютерном столе.

Monday, November 05, 2007

Семинар Keyintegrity "Основы Java"

В середине октября 2007 я с моими коллегами Павлом Чурсиным и Алексеем Солодовниковым провели многодневный обучающий семинар по теме "Основы Java" в ТатАСУНефть.

Семинары состояли из двух дней лекций, и одного дня лабораторных работ.

Некоторые вопросы, рассмотренные в рамках лекций:

  1. Введение в Java
    1. Историческая справка
    2. Платформы Java ME/SE/EE
    3. Версии платформы Java
    4. JRE/JDK и JVM
  2. HelloWorld
    1. Точка входа в приложение, аргументы командной строки, код возврата
    2. Из чего состоят, как компилируются и запускаются приложения Java
  3. Поддержка ООП в Java
    1. Классы в Java
      1. Атрибуты класса
        • Имя
        • Модификаторы класса
        • Поля
        • Методы
        • Конструктор
        • Инициализатор
      2. Вложенные, Анонимные и Абстрактные классы
    2. Наследование и полиморфизм
    3. Интерфейсы
    4. Статический контекст
  4. Пакеты
  5. JavaBean и POJO
  6. Синтаксические конструкции языка
    1. Основные конструкции
    2. Потоки выполнения
      1. Исключительные ситуации
      2. Иерархия исключительных ситуаций
    3. Аннотации
    4. Generics
  7. Collections API (java.util.*)
    1. Collections, List, Set, Queue
    2. Vector, Stack
    3. Map
  8. Многопоточность
    1. Thread/Runnable
    2. Concurrency API (java.util.concurrency.*)
  9. I/O Streaming API (java.io.*)
    1. Serializable
    2. Input/OutputStream и иерархия
  10. И др.
На третий день были запланированы две лабораторные работы:
  • потоковый ввод/вывод и Collections API
  • многопоточное приложение и ООП
Мы также подготовили методические указания для выполнения работ в Eclipse IDE (1,3 МБ). Там же можно найти текст заданий к лабораторным работам.

Лабораторная работа №1

Цель работы:

Ознакомиться со средой разработки Eclipse JDT. Закрепить навыки создания и отладки простых консольных приложений на Java. В этой работе используются:

  • стандартные пакеты для работы с потоковым вводом/выводом,
  • сериализация объектов,
  • разбор параметров командной строки,
  • Java Collections API,
  • определение простых классов (JavaBeans),
  • сортировка списка объектов из этих классов по заданным критериям.

Лабораторная работа №2

Цель работы:

В этой предполагается создание утилиты для работы с файловой системой. Основными особенностями являются:

  • Использование возможностей ООП в Java: работа с интерфейсами и абстрактными классами, перегрузка методов;
  • Использование рекурсии для работы с файловой системой;
  • Создание многопоточного приложения с разделением общих объектов и синхронизацией потоков.

Исследовать возможности многопоточного программирования и применения интерфейсов, абстрактных классов и наследования в Java.


Решения для лабораторных работ можно скачать здесь (15 КБ).

Отдельно хочется отметить BlueJ - отличная вещь для преподавания ООП и Java.

Семинар Keyintegrity "Сближая бизнес и IT: методология и инструментарий BPM для эффективного управления бизнес-процессами предприятия"

Второго октября 2007 компания Keyintegrity провела бесплатный семинар в г. Набережные челны по теме "Сближая бизнес и IT: методология и инструментарий BPM для эффективного управления бизнес-процессами предприятия".

Я читал доклад о взаимосвязи SOA, BPMN и BPEL (презентация прилагается, 173 КБ).

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

На демонстрации разбирался пример, опубликованный в одном из предыдущих постов, реализованный на Intalio|BPMS.

Особенно хочется отметить роль Open Source'овых продуктов. Известно, что внедрение SOA рекомендуется начинать постепенно, с "маленьких" бизнес-процессов, потихоньку на практике знакомясь с особенностями применения данной методологии. Закупать для этих целей полнофункциональные продукты уровня Enterprise, такие как, например, семейство продуктов WebSphere (ESB, Process Server, и т.д.) - слишком дорогое удовольствие, а применение бесплатных Open Source аналогов может быть вполне оправданным.

Функциональных возможностей Open Source аналогов может быть вполне достаточно и для их дальнейшего использования в production, а если возникнет необходимость в переносе уже реализованного функционала на коммерческие продукты, то этот процесс не займет больших усилий:

  1. С одной стороны благодаря поддержке открытых стандартов - для переноса возможно нужно будет поменять только схемы деплоймента (BPEL, WS, Java EE и т.д.);
  2. С другой стороны это связано с одной из моделей коммерческого Open Source. Производители коммерческого ПО выносят базовую функциональность своих продуктов в Open Source, оставляя в коммерческой версии функции, необходимые для применения в production. В этом случае все проекты смогут работать в коммерческой версии "как есть".

Saturday, November 03, 2007

Java-, WS- и XML-технологии в проекте WebSeller

Проект WebSeller, который я делал в магистратуре в рамках курсовой работы/проекта в 2005 году.

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

Аннотация
Цель данного учебного проекта – получить навыки разработки распределенных программных систем на платформе J2EE. В качестве основной архитектуры рассматривается сервис-ориентированная архитектура (Service-Oriented Archi-tecture, SOA) на основе web-служб. Рассмотрены основные технологии разра-ботки web-служб, в частности – JAX-RPC и язык описания бизнес процессов на основе web-служб – BPEL, а также разработаны две web-службы с использова-нием рассмотренных технологий.
В проекте используются, в основном, продукты Apache Software Foundation и другие open source проекты. Дается краткое описание использованных техноло-гий и приемы работы с ними.
Так же уделяется внимание унифицированному процессу RUP, как подходу к проектированию подобных учебных проектов.
В приложениях на компакт диске представлены исходные коды в виде проекта для IDE Eclipse 3.1; набор разработанных артефактов RUP для проекта, а также дистрибутивы использованных программных технологий.

Табл.: 2; Ил.: 15.

Скачать проект (2 МБ):
  • Пояснительная записка
  • Плакаты
  • Артефакты RUP
  • Проект WebSeller для Eclipse 3.1.1

Tuesday, October 02, 2007

Запускаемый BPMN

Пример простого BPMN процесса PurchaseOrder для Intalio|BPMS Designer 5.x
Ссылка на архив проекта здесь.


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

Условный переход выставлен так, чтобы всегда проходить по бОльшей ветке.

С русскими названиями были проблемы, так что пришлось воспользоваться атрибутами Technical Name активностей, а русские оставить только в качестве описания (Label).

P.S.
В продолжение темы.

Thursday, June 15, 2006

Lifetime Management with BPEL (Part II)

It's time now to explain to the reader what I mean using the term "Lifetime Management".

The basic idea is handling the timeouts as they were previously defined before (see Lifetime Management with BPEL (Part I) with BPEL Peek example).

Standard BPEL allows us to handle duration or deadline timeouts by defining how much time should elapse before the timeout event will occur or by specifying the deadline date and time for the deadline (onAlarm's for and until attributes accordingly).

The new way I'd like to declare the process timeout expression is so that onAlarm can handle an automatic duration prolongation in the case when some of the duration expression conditions were changed. It's important to notice that you can not just change onAlarm's expression via, say, Assign activity (at least I couldn't found the way how to do that, so please inform me if you know the way).

Lets take an example of how to use this functionality.

Imagine a web shop that keeps a personal shopping cart for each of its customers.

A user may surf through the web shop, put some products in the cart and make an order.

One of usecases for this web shop may be the following:

  • Customer wants to buy everything he placed in the cart (the good one :). In this case the system calculates an order and starts the process of billing and delivery of the products to the user;
Another possible usecase is:
  • Customer leaves the webshop page (doesn't matter how - by navigating to another URL or just closes the browser window).
What should become with a customer's shopping cart and all the goods that he placed into it in the last scenario? Should we release all the items from the cart immediately? But what if the user will return to the page and act as in the first use case? Then he would have to navigate the site once again and take all the stuff he already did few time ago - bad usability.

On the other hand if we left the items in the cart forever then no one other would be able to buy the stuff that is in the other user's cart since it's already reserved.

So we need to specify the cart lifetime somehow so that all the items were released and the cart were cleared after the specified time.

The typical solution for a web shop here nowadays is using HTTP session but as we are talking about Web Services the HTTP session is not suitable for that. So we may use BPEL that can give us the functionality we need at the higher level of abstraction.

Why not just use BPEL onAlarm duration (the for attribute)? Since, as I already said above, it is not possible to change the duration expression at runtime while this is required to set the new cart lifetime after each cart update (say after adding new item to cart).

In the next part we'll see how to implement this example using BPEL and discuss some key aspects that you should pay attention for while using BPEL here...

Lifetime Management with BPEL (Part I)

Here we go...

I'd like to show you an example of BPEL (read BEEPLE :) that allows to implement some kind of a lifetime management using web-services.

This implementation is based on BPEL's Pick activity, and right before we start I'd like to introduce readers in what this activity is need for. Those who familiar with that may freely skip this part.

So, as I already said, BPEL have the Pick activity that is like widely known Switch/Case language construction in programming languages (Java, C++ or Pascal Case/Of). Those constructions have a possibility of redirecting control flow based on some expression, for instance (Java):

switch (directionExpression) {
case LEFT:
moveLeft();
break;
case RIGHT:
moveRight();
break;
case UP:
moveUp();
break;
case DOWN:
moveDown();
break;
default: // Hold
}
In BPEL the Pick activity is the analog of the Switch statement. Pick's OnMessage statements are like Switch's case statements.

To be true to the reader I'd like to say that BPEL have the Switch activity too. The main thing that distinguish Pick from Switch constructions is that Pick is a blocking activity, that means that the expression that manages the process control flow is a message that BPEL process instance is waiting for to receive, and the flow would be frozen until this message arrives, while in Switch we already have this expression defined as a process variable and the alternative flow may be picked up without any delay.

Now I'd like you to mention the default statement. Pick has the analog of this statement that corresponds the situation when no message were arrived to the Pick activity during some time period (or by deadline) - the timeout; and the activity that is responsible to handle such timeouts is Pick's OnAlarm.


So the BPEL code using Pick may looks like:
<pick>
<onMessage operation="approve">
<!-- TODO Implement OnApprove -->
</onMessage>
<onMessage operation="reject">
<!-- TODO Implement OnReject -->
</onMessage>
<!-- Timeout will occur in one minute -->
<onAlarm for="&quot;PT1M&quot;">
<!-- TODO Implement OnTimeout -->
</onAlarm>
</pick>


to be continued...

References