Продолжается подписка на наши издания! Вы не забыли подписаться?

AOP@Work: Новая версия AJDT упрощает АОП-разработку

Авторы: Мэтт Чепмэнн (Matt Chapman)
IBM
руководитель проекта AJDT
IBM

Источники: Перевод статьи из серии AOP@Work
http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=AOP@work

Материал предоставил: IBM
Опубликовано: 01.11.2006

AspectJ Development Tools for Eclipse (AJDT) не так давно претерпела существенные изменения, в основном в области улучшения интеграции с платформой Eclipse. Эти изменения предоставили AspectJ-разработчикам лучший доступ к инструментальной поддержке на платформе Eclipse. В этой статье я расскажу о AJDT 1.2 для Eclipse 3.0 и AJDT 1.3 для Eclipse 3.1.

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

В статье для исследования возможностей AJDT я буду использовать общепринятые сценарии. Все сценарии отражают действия, выполняемые типичными AspectJ-разработчиками; например, первый сценарий предполагает создание простого AspectJ-проекта с нуля. Это как раз то, что разработчик, начинающий работать с AspectJ, непременно сделает для ознакомления с языком и с инструментами. Более сложные сценарии включают введение аспектов в существующие Java-проекты и работу с различными многопроектными средами. Я также расскажу о поддержке новых возможностей AspectJ 5 и проведу вас через процесс миграции с AJDT 1.1. Завершится статья рассказом о разработке самого AJDT (то есть разработке AJDT с помощью AJDT!), а также описанием некоторых изменений, ожидаемых в ближайшем будущем.

Обратите внимание, AJDT 1.2 – последняя стабильная версия для Eclipse 3.0, пришедшая на смену AJDT 1.1.12, а AJDT 1.3 – стабильная версия для Eclipse 3.1. Промежуточные версии AJDT 1.2 для Eclipse 3.1 выпускались, но для того, чтобы выпустить стабильную версию для Eclipse 3.1, потребовалась отдельная линия разработки, что и привело к выпуску AJDT 1.3. За исключением особо оговоренных случаев все сказанное к статье относится к обеим версиям. Главное отличие состоит в функциональности, специфичной для AspectJ 5, которая в целом требует Eclipse 3.1.

Чтобы скачать последние версии AJDT и Eclipse, воспользуйтесь ссылками из раздела Ресурсы. Чтобы воспроизвести примеры из этой статьи, потребуется и то, и другое.

AJDT с нуля

Java-разработчику, начинающему знакомство с AspectJ, полезно будет для начала написать простую AspectJ-программу. Это можно сделать, воспользовавшись примерами из руководства по AspectJ, или одной из многих замечательных книг и статей по AspectJ (см. раздел Ресурсы). Процесс создания нового AspectJ-проекта в Eclipse очень похож на создание Java-проекта. Просто выберите File > New > Project > AspectJ Project, или воспользуйтесь кнопкой New AspectJ Project на инструментальной панели. Появится визард, почти идентичный визарду New Java Project.

На самом деле, AspectJ-проект – это и есть Java-проект (в терминах Eclipse у него есть Java-природа в дополнение к AspectJ-природе), так что любые инструменты и дополнительные модули, работающие с Java-проектами, будут работать и с AspectJ-проектами. Ключевое отличие состоит в компиляторе, который Eclipse использует для этого проекта: вместо JDT Java-компилятора используется AspectJ-компилятор. AspectJ-компилятор – это расширение JDT Java-компилятора, и, естественно, он полностью пригден для компиляции Java-кода.

В следующем разделе я покажу некоторые возможности AJDT, вступающие в игру в простом сценарии разработки.

Визард New Aspect

Благодаря сходству AspectJ- и Java-проектов мне не придется объяснять вам, как создать папки, пакеты и классы, или как настроить путь к классу – это должно быть в крови у большинства Eclipse Java-разработчиков (см. Ресурсы). Аналогично, редактирование классов выглядит так же, как всегда. Вы можете по-прежнему использовать Java-редактор, и массу сберегающих время возможностей типа автодополнения, исправления ошибок и упорядочивание директив import.

Следующий шаг – создание аспекта. Аспект в AspectJ – единица модульности, имеющая много общего с классом в Java. Выберите File > New > Other > AspectJ > Aspect или воспользуйтесь выпадающим меню New Type на инструментальной панели, чтобы запустить визард New Aspect, отличающийся от визарда New Class всего несколькими опциями.

Редактор AspectJ

После создания нового аспекта вы увидите его уже открытым в редакторе (на этот раз в редакторе AspectJ) и, возможно, заметите, что новый файл имеет расширение .aj, принятое в AspectJ для аспектов (классы можно оставить в файлах .java). Попробуйте добавить в новый аспект какой-нибудь AspectJ-код. Вы обнаружите, что возможности редактирования очень близки к имеющимся для Java-кода. Возьмем, например, следующие возможности:

Все очень знакомо, не так ли? Несколько недостающих возможностей – например, quick fixes в аспектах и автодополнение некоторых вещей, например, имен pointcut-ов – появятся в следующих версиях AJDT.

Сохранение аспекта вызовет компиляцию проекта (если вы не отключите автоматическую сборку, что приведет к необходимости нажимать кнопку Build, как в Java-проектах). Если аспект содержит advice, влияющий на код проекта, вы увидите, что в Cross References появятся некие вхождения, а в левой части редактора – некие маркеры. Это два способа, которыми AJDT показывает сквозную (crosscutting) природу AspectJ-проектов.

Отображение сквозной функциональности

Представления Cross References и Outline можно считать партнерами. В то время как представление Outline показывает структуру текущего документа, представление Cross References показывает сквозные отношения для текущего элемента. Удобно расположить Cross References под Outline, как показано на рисунке 1. Если это окно скрыто, его можно открыть, выбрав Window > Show View > Other > AspectJ, или щелкнув правой кнопкой на элементе в Outline и выбрав в контекстном меню Open Cross References.

Щелчок внутри метода в редакторе приводит к появлению окна Cross References, содержащего crosscutting-информацию для данного метода, как показано на рисунке 1.

Clicking within a method in the editor causes the Cross References view to show any crosscutting information for that method, as illustrated in Figure 1:


Рисунок 1. Классы в окнах Outline и Cross References.

В данном случае можно видеть, что метод привязывается с помощью некого advice-а в аспекте GetInfo. Вы можете щелкнуть по этому advice-у, чтобы перейти к нему. После этого сам advice будет показан в Cross References, изображенном на рисунке 2, где отношения показаны с другой точки зрения.


Рисунок 2. Аспект в окнах Outline и Cross References.

Вы можете также выбрать возможность не связывать Cross References с редактором. При этом Cross References не будет реагировать на выбор в редакторе или Outline, что может быть полезным, если вы хотите сохранить видимым конкретный список crosscutting-информации. Еще одна возможность – отображение crosscutting-информации для всего текущего файла, а не только для текущего элемента.

Наконец, некоторые разработчики не хотят, чтобы Outline постоянно занимал место на экране. Они вызывают Quick Outline (из меню Navigate, или, чаще, нажатием Ctrl+O), который появляется поверх редактора. Такая же функциональность имеется и для Cross References. Нажатие Ctrl+Alt+X (или другого клавиатурного сочетания, назначенного пользователем в настройках AJDT) выведет на экран окно Quick Cross References, показанное на рисунке 3. В случае Quick Outline повторное нажатие клавиатурного сокращения заставит окно показать также и унаследованные члены. В Quick Cross References аналогичный механизм используется для переключением между crosscutting-информацией для текущего элемента и для всего файла.


Рисунок 3. Окно Quick Cross References.

Пиктограммы маркеров и их декораторы

Если посмотреть на редактор с кодом, к которому применен advice, слева от кода можно увидеть пиктограммы маркеров. Они указывают наличие и тип advice-а, используя те же пиктограммы, что в Outline и Cross References. Для before, after, и around advice-ов применяются различные пиктограммы. Каждая из пиктограмм имеет два варианта – с маленьким вопросительным знаком и без него. Вопросительный знак означает, что существует runtime-тест для определения того, что advice применяется в этой точке, например, когда указатель cflow применяется в pointcut-ах. Вариант без вопросительного знака применяется, когда соответствие может быть полностью определено при компиляции.

Если щелкнуть правой кнопкой по маркеру, в контекстном меню можно увидеть позицию Advised By, и подменю, показывающее источник advice-а. Если выбрать вхождение в этом подменю, этот advice будет открыт в редакторе. В advice-е вы увидите дополнительные маркеры, показывающие crosscutting-отношения с другой стороны, через подменю Advises, как показано на рисунке 4. Эти симметричные маркеры позволяют переходить от источника к цели advice-а. Аналогичные маркеры и подменю используются для inter-type объявлений.

Декораторы пиктограмм такэже используются для отображения сквозной функциональности. Если вернуться к окну Outline, показанному на рисунке 1, можно заметить маленькие оранжевые стрелочки слева от трех методов. Эти стрелочки – декораторы пиктограмм Eclipse для Java-элементов. Они используются либо для указания того, что на данный элемент непосредственно воздействует advice, либо что он содержит точку подключения, к которой подключается advice. Эти визуальные подсказки появляются практически везде, где используются Java- элементы, включая окна Outline, Cross References и Members в режиме просмотра Java Browsing.


Рисунок 4. Маркеры и контекстные меню.

Конвертация Java-проекта

После получения некоторого опыта работы с AspectJ и AJDT на простом тестовом проекте типичный следующий шаг разработчика – взять существующий Java-проект и постараться ввести в него аспект-другой. Например, вы можете захотеть добавить контролирующие аспекты, скажем, проверяющий наличие нежелательных вызовов System.out.println или Exception.printStackTrace, или аспекты реализующие персистентность, или аспектно-ориентированную реализацию паттерна проектирования.

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

Превратив Java-проект в AspectJ-проект, вы можете поинтересоваться, какая между ними разница. Ответ – «очень небольшая». Вы по-прежнему редактируете Java-классы в Java-редакторе, используя стандартное outline-представление документа, и все возможности, к которым привыкли, включая quick fixes, автодополнение и подчеркивание ошибок красным. Также, сохранение изменений в классе приведет к быстрой инкрементальной компиляции проекта, а в настройках свойств проекта можно задать привычные опции компилятора. Каждая корректная Java-программа является одновременно и корректной AspectJ-программой, так что ваш код будет компилироваться так же, как и раньше.

На самом деле компилятор AspectJ – это расширение Java-компилятора Eclipse, а AJDT расширяет инструменты JDT настолько прозрачно и последовательно, насколько это возможно. Это то, что имеется в виду при разговорах о бесшовной интеграции. Именно такая цель ставилась при разработке AJDT 1.2/1.3, и мы неплохо продвинулись по этому пути (далее в статье я расскажу о некоторых остающихся ограничениях). Цель бесшовной интеграции – максимально облегчить первые шаги при переходе на AspectJ, и проложить дорогу к получению реальной пользы от программирования с использованием аспектов.

Управление несколькими проектами

Сборка исходного AspectJ-кода включает две отдельные фазы: компиляция исходного кода в .java и .aj для генерации .class-файлов и последующее применение аспектов к сгенерированным .class-файлам. Вторая фаза, известная как интеграция (weaving), и составляет ключевое различие между AspectJ- и Java-компиляторами. Процесс компиляции Java управляется установками classpath. Те же установки classpath используются при компиляции AspectJ-кода, и задаются в Eclipse точно так же. Однако этих установок не всегда достаточно для управления обеими фазами – компиляции и интеграции. Поэтому для AspectJ-проектов введены еще две настройки.

Первая из них – inpath. Всё, указанное в ней, будет доступно интегратору (weaver), и все применимые аспекты будут вплетены в код. Вхождения в inpath проекта можно добавить в разделе свойств проекта InPath, для вызова которого нужно выбрать пункт Properties из контекстного меню проекта. Вхождения могут быть как JAR-файлами или каталогами классов, например, каталогом bin другого проекта. Все, включенное в inpath, копируется в результирующий каталог проекта, после потенциального применения аспектов.

Вторая дополнительная настройка - aspectpath. Если inpath управляет списком того, во что вставляется код аспектов, aspectpath указывает, что именно вставляется. Другими словами, любой аспект, указанный в aspectpath, становится доступным процессу интеграции, как если бы они присутствовали в исходной форме в проекте. Эта настройка задается на странице свойств AspectJ-проекта Aspect Path и может содержать JAR-файлы или каталоги.

Настройка output JAR также присутствует в разделе AspectJ свойств проекта. Эта настройка заставляет компилятор помещать создаваемые class-файлы напрямую в JAR-файл, а не в в результирующий каталог проекта.

Использование аспектов из других проектов

Чтобы посмотреть на работу описанных выше настроек, рассмотрим пример рабочей среды. Возьмем два проекта, один – MyAspects, а второй – WeaveMe. Оба они – AspectJ-проекты, хотя второй может содержать аспекты, а может и не содержать. Проект MyAspects содержит некие аспекты, нужные проекту WeaveMe. Чтобы связать эти проекты, просто щелкните правой кнопкой мыши по проекту WeaveMe, выберите Properties и перейдите к разделу AspectJ Aspect Path. Затем, на закладке Libraries, нажмите Add Class Folder и выберите каталог bin (или как там он у вас называется) проекта MyAspects.

Нажмите ОК для сборки проекта с новыми установками и, предполагая, что срезы (pointcuts) аспектов соответствуют позициям в коде WeaveMe, примените ассоциированные advice-ы. Маркеры редактора и окно Cross References по-прежнему будут показывать отношения "advised by", но теперь исходный аспект будет показан как бинарный, и перейти к нему не получится. Это сделано потому, что в общем случае аспект может находиться вне рабочей среды Eclipse, например, во внешнем JAR-файле. Однако, по крайней мере в данном случае, исходный код аспекта находится в рабочей среде, только в другом проекте, так что, возможно, в следующей версии AJDT можно будет подключиться и перейти к аспекту в другом проекте.

Важно заметить, что типы, доступные через aspectpath, должны быть доступны и во время исполнения. К счастью, в AJDT это просто – вместо выбора Run > Java Application можно использовать новую конфигурацию запуска Run > AspectJ/Java Application. Она совпадает с Java-конфигурацией запуска, за тем исключением, что она автоматически добавляет вхождения aspectpath в classpath времени исполнения. Второе, не связанное с первым отличие состоит в том, что конфигурация запуска AspectJ/Java может также обнаруживать любые методы main, содержащиеся в аспектах.

Интеграция аспектного кода в Java-проекты

Что если у вас есть проект, содержащий Java-код в исходной форме или в JAR-файле, к которому нужно применить аспекты? Если нужно держать аспекты отдельно от проекта, можно оставить его в форме Java-проекта, и создать отдельный AspectJ-проект, в котором и выполнять интеграцию. В этом случае вы просто добавляете в "AspectJ InPath" в настройках AspectJ-проекта ссылку на Java-код, используя кнопки Add JARs или Add Class Folder.

При выполнении бинарной интеграции наподобие описанной выше у вас уже не будет маркеров в исходном коде, показывающих, где выполняется вставка. В данном случае поможет опция компилятора: на закладке Other настроек компилятора для AspectJ-проекта (или в глобальных настройках) выберите опцию Output weaving info messages to problems view. Теперь при сборке проекта окно Problems будет выводить информацию об интегрируемых типах, как показано на рисунке 5:


Рисунок 5.

Заметьте, что если на входе был JAR-файл, вы можете захотеть использовать опцию Output JAR, описанную выше, чтобы напрямую генерировать интегрированную версию исходного JAR-файла.

Разработка аспектных библиотек

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

Если проект, использующий библиотеку аспектов, содержит конкретную версию любого из требуемых абстрактных аспектов, два проекта можно связать, просто добавив проект библиотеки на закладку Projects страницы свойств Java Build Path. Поскольку конкретный проект локален для проекта, обычного просмотра classpath будет достаточно для нахождения супер-аспекта.

Заметьте также, что маркеры редактора и окно Cross References показывают источник вставляемого кода как абстрактный супераспект. Это корректно, так как advice находится именно там; однако в этой ситуации срез точек вставки конкретного объекта управляет вставкой кода, и интерес представляет чаще всего именно это. В следующих версиях AJDT для обеспечения такой связи будет отображаться отношение "uses pointcut". Учитывая потенциал многократно используемых библиотек аспектов, в последующих версиях AJDT можно ожидать улучшения их поддержки.

Работа с проектами дополнительных модулей

Растущая популярность платформы Eclipse означает, что все больше разработчиков создают расширения для нее. Хорошо то, что AspectJ легко использовать для работы с модулями расширения. Просто возьмите проект модуля расширения и щелкните по нему правой кнопкой мыши, чтобы конвертировать его в AspectJ-проект так же, как Java-проект. Вам предложат добавить зависимость от модуля расширения org.aspectj.runtime. AspectJ-программы имеют runtime-зависимость от файла aspectjrt.jar, и для проектов модулей расширения эта зависимость удовлетворяется маленьким расширением org.aspectj.runtime. После добавления этой зависимости к проекту можно начинать использовать аспекты при разработке расширений.

Ограничения интеграции AJDT и Eclipse

В некоторых областях интеграция AJDT и Eclipse не бесшовна, например, при создании расширений, где опция Create Ant Build File with AspectJ Support была добавлена параллельно имеющейся Create Ant Build File. Расширения Eclipse должны привносить отсутствующую функциональность, а не заменять имеющуюся, но в данном случае лучше было бы, если бы существующую функциональность удалось расширить для работы с AspectJ-проектами. Тогда пользователь видел бы один пункт Create Ant Build File для AspectJ- и Java-проектов, и в обоих случаях все бы «просто работало». В подобных случаях лучший подход – это создать запрос на улучшение базовой функциональности Eclipse, чтобы сделать ее расширяемой там, где такая расширяемость имеет смысл.

Eclipse Plug-in Development Environment (PDE) позволяет сгенерировать build-файл для Ant (build.xml) для проекта модуля расширения. AJDT предоставляет аналогичную возможность для проектов модулей расширения, использующих AspectJ. Щелкните правой кнопкой мыши по файлу plugin.xml и выберите PDE Tools > Create Ant Build File with AspectJ Support. Сгенерированный файл build.xml будет похож на сгенерированный для проекта Java-расширения, но вместо использования для компиляции исходного кода Ant-задачи javac будет использоваться задача iajc, предоставленная AspectJ.

Управление большими проектами

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

Визуализация на уровне проекта

Как вы уже видели, маркеры в редакторе AspectJ и окне Cross References ясно показывают crosscutting-информацию для отдельных файлов. Чего они не показывают, так это насколько широко применяется сквозная функциональность – где она пересекается с текущим проектом или хотя бы с несколькими пакетами. Такую перспективу может предоставить Visualiser.

Простейший путь вызвать Visualiser – переключиться в вид Aspect Visualization, показывающий визуальное представление выбранного проекта, состоящее из столбцов для каждого исходного файла с высотой, пропорциональной числу строк в нем. На этих столбцах нарисованы полоски в позициях, соответствующих позициям вставки кода (или потенциальной вставки кода в случае дополнительной runtime-проверки). Цвет полосок соответствует аспекту (см. рисунок 6).


Рисунок 6. Visualiser.

Как видите, на экране имеется основное окно Visualiser и вспомогательное окно Visualiser Menu, где перечислены отображаемые аспекты. В этом меню можно отключить показ тех или иных аспектов. Например, можно отключить отображение аспекта логирования, мешающего видеть другие аспекты. Элементы управления на инструментальной панели Visualiser позволяют увеличить или уменьшить масштаб, уменьшить представление до размеров окна, показывать только столбцы, где используется вставка кода (иначе незадействованные столбцы закрашиваются серым) и переключиться между уровнями классов и пакетов (где все классы пакета показываются в одном столбце). Наконец, можно использовать выпадающее меню для доступа к другим возможностям, например, странице настроек отображения. Кроме показа мест вставки кода визуализация включает показ выражений "declare error" и "declare warning". Эта возможность включается на инструментальной панели Visualiser Menu. Цвета, используемые для представления различных аспектов, можно выбрать из списка. Выбранные цвета запоминаются.

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

Visualiser позволяет открыть нужный класс, столбец или advice в редакторе с помощью двойного щелчка мышью или нажатия пробела. Стоит упомянуть, что Visualiser – это компонент общего назначения, который можно настроить на отображение чего угодно, от маркеров Eclipse до результатов поиска в Google. В Visualiser можно не только отображать пользовательские данные, но и изменять стили отрисовки колонок и цвета плосок.

<...>

Будущее AJDT

Если вы знакомы с предыдущими версиями AJDT, вы заметите, как много изменилось в AJDT 1.2 и 1.3. В AJDT 1.1 AspectJ-редактор имел меньше возможностей и использовался для редактирования как классов, так и аспектов, а outline-вид имел меньше возможностей, чем его аналог для Java. Новый AspectJ-редактор дает больше возможностей для редактирования аспектов, для редактирования классов теперь применяется стандартный Java-редактор, а в стандартный outline-вид введена поддержка аспектов. Это также значит, что визард настроек для глобальных изменений настроек среды больше не нужен.

Функциональность, связанная с генерированием ajdoc и поддержкой конфигураций сборки почти не изменилась, но большинство других областей расширены и улучшены. Появились новые способы отображения и навигации по crosscutting-структуре программы, поддержка экспорта в JAR-файлы, конвертации расширений файлов и создания build-файлов; кроме того, существенно улучшена поддержка для инкрементальной компиляции (которая теперь используется по умолчанию), а куда более гибкий Visualiser может работать с большими проектами. Даже документация подверглась капитальной переработке, чтобы помочь вам выжать из AJDT все возможное.

Несмотря на весь этот прогресс, работы еще много. Во-первых, есть проблема интеграции с Eclipse: в долгосрочной перспективе надежная, полностью интегрированная AJDT требуют большей расширяемости Java-инструментария Eclipse, чем имеющаяся сейчас, и мы надеемся, что наш опыт в разработке AJDT сможет помочь в этом. Во-вторых, всегда есть возможности инструментов AJDT, которые еще предстоит создать. Это и аспектно-ориентрованный рефакторинг, и улучшение средств разработки, и использование библиотек аспектов, да еще и разработка способов борьбы с «информационной перегрузкой» – например, интенсивное использование AspectJ в проекте может привести к появлению ошеломляющего количества crosscutting-маркеров. Разработка AJDT по-прежнему направляется запросами пользователей, поэтому, пожалуйста, сообщайте нам о наиболее нужных возможностях и наиболее мешающих ошибках. Если вы хотите принять участие в разработке, обращайтесь на домашнюю страницу AJDT, а также по ссылкам на Bugzilla, новостную группу, список рассылки для разработчиков и страницу текущих задач.

Ресурсы

........................
"С полным содержанием данной статьи можно ознакомиться в печатной версии журнала"

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

Copyright © 1994-2016 ООО "К-Пресс"