(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Разработка элемента языка для Rational Software Architect

Simon Джонстон (Simon Johnston), STSM, IBM Rational

В данной статье описаны методы, используемые для разработки элемента языка IBM Rational Software Architect (RSA), реализующего поддержку моделирования и генерирующего из UML-моделей исходный код на данном языке программирования. Данный элемент языка реализован в виде набора модулей для RSA, каждый из которых предоставляет определенный аспект решения по моделированию и генерации кода. В данной статье предполагается, что пользователи знакомы с архитектурой модулей Eclipse и способны разрабатывать модули для Eclipse или RSA.

Введение

В данной статье описан процесс разработки примера элемента языка, предоставляющего среду моделирования и преобразования кода для генерации кода на языке Objective-C из UML-моделей в IBM Rational Software Architect (RSA). Для тех, кто не знает, Objective-C происходит от языка С с добавлением объектно-ориентированных конструкций программирования. Развитие Objective-C шло параллельно C++, хотя C++ получил более широкое распространение. Но язык по-прежнему используется, ядро API для операционной системы Apple Mac OS X было разработано на Objective-C. Разработчики, работающие с этой операционной системой, знакомы с такой средой, как Cocoa.

Описанные в данной статье модули обеспечивают:

  • Преобразование из UML в Objective-C с помощью Rational Software Architect  Transformation Framework и Java Emitter Templates (JET) 
  • UML-профиль для моделирования Objective-C
  • Модель Data Type для типов данных Objective-C
  • Модель Template с примененным профилем и импортированной моделью типов данных
  • Пример модели

Структура элемента показана на рисунке 1. В данное время элемент состоит из трех модулей, которые подробней будут описаны в следующих разделах.

Рисунок 1. Модули, входящие в состав элемента
The plug-ins 

Примечание: для уменьшения размера изображений каждое имя, начинающееся с точки, фактически имеет префикс "com.ibm.xtools".

Моделирование на Objective-C

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

  1. Objective-C поддерживает только единичное наследование между классами, тогда как UML поддерживает множественное наследование;
  2. В основе Objective-C лежит C, поэтому используются типы указателей, которые сложно смоделировать в UML;
  3. В языке имеется конструкция (протокол), очень похожая на понятие интерфейса в Java или C#. Протоколы реализованы в классах;
  4. В языке имеется конструкция (категория), позволяющая программистам добавлять новые методы к существующим классам. В UML такой возможности нет;
    • Категория предоставляет только операции, но не атрибуты;
    • Категория не поддерживает наследование и не может реализовать протоколы.
  5. Атрибуты в классе могут быть только наследуемые (не основаны на классе). Атрибуты могут быть публичными, частными или защищенными;
  6. Операции с классом могут основываться на экземпляре или на классе. Все операции публичны;
  7. При определении параметров операции каждый из них, помимо имени для реализации, имеет имя, которое используется вызывающей программой. В UML такого нет.

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

Таблица 1: Моделирование Objective-C

Название Тип Свойства Описание
Категория Класс Нет Этот стереотип применен к классу для его обработки как категории, а не как класса. Категория может не иметь атрибутов, все операции должны быть публичными
Среда Пакет Нет Среда представляет собой коллекцию связанных заголовков, распространяемых как модуль программы. Обратите внимание, что профиль Objective-C не включает этот стереотип. Существующий стереотип будет повторно использоваться в профиле Basic.
Протокол Интерфейс Нет Этот стереотип означает, что интерфейс должен обрабатываться как определение протокола. Стереотип является дополнительным, предполагается, что все интерфейсы рассматриваются в качестве протоколов.
Атрибут Свойство pointers: String Чтобы обойти проблему, связанную с указателями, предоставляется способ регистрации типов указателей как свойства данного стереотипа. Такой способ автоматически применяется к стереотипу и ко всем элементам моделей.
Класс Класс Нет Стереотип класса применяется для предоставления ограничений. При его применении, возможно, у класса не будет статических атрибутов, все операции должны быть публичными. Такой способ автоматически применяется к стереотипу и ко всем элементам моделей.
Параметр Параметр messageName : String
pointers : String
Свойства этого стереотипа принимают значения, не предоставляемые UML. Такой способ автоматически применяется к стереотипу и ко всем элементам моделей.

На рисунке 2 показан пример модели, демонстрирующей общие структуры в контексте. Код, соответствующий интерфейсу класса для AddressModelClass, представлен в Листинге 1.

Рисунок 2: Пример исходной модели 
Source Model 

Примечание: Классы NSObject и NSURLClient предоставляются средой Mac OS X Cocoa Framework (см. Листинг 1).

Листинг 1. AddressModelClass

        
@interface AddresModelClass : NSObject <NSURLClient>
{
  @public
  NSString* _Street1;
  NSString* _Street2;
  NSString* _City;
  NSString* _State;
  NSString* _PostalCode;
  NSString* _Country;
  @private 
  id _Formatter;
}

/* Class Operations */
- (id)init;
- (id)initWithStreet:(NSString*)Street 
            withCity:(NSString*)City 
           withState:(NSString*)State
      withPostalCode:(NSString*)PostalCode
         withCountry:(NSString*)Country;
- (id)initFromURL:(NSURL*)url;
- (NSString*)formatAddress;

/* Accessors */
- (void)setStreet1:(NSString *)newStreet1;
- (NSString*)Street1; 
- (void)setStreet2:(NSString *)newStreet2;
- (NSString*)Street2;
- (void)setCity:(NSString *)newCity;
- (NSString*)City;
- (void)setState:(NSString *)newState;
- (NSString*)State;
- (void)setPostalCode:(NSString *)newPostalCode;
- (NSString*)PostalCode;
- (void)setCountry:(NSString *)newCountry;
- (NSString*)Country;

/* protocol NSURLClient */
- (void)URL:(NSURL *)sender resourceDataDidBecomeAvailable:(NSData *)newBytes;
- (void)URL:(NSURL *)sender resourceDidFailLoadingWithReason:(NSString *)reason;
- (void)URLResourceDidCancelLoading:(NSURL *)sender;
- (void)URLResourceDidFinishLoading:(NSURL *)sender;
@end


Разработка ресурсов моделирования

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

UML-профиль и модель типа данных

Первый модуль упаковывает два ресурса: профиль, о котором говорилось в предыдущем разделе, и библиотеку типов данных. Это модуль является моделью основных типов, обычно используемых в программировании на Objective-C. На рисунке 3 показаны зависимости модулей RSA. Точки расширения, используемые в модуле, позволяют просмотреть дополнительные сведения.

Рисунок 3: Зависимости для модуля профиля
 Dependencies

Прежде всего, с помощью стандартного мастера модулей Eclipse New Plug-In Project необходимо создать новый проект модуля и назвать его com.ibm.xtools.sample.profiles.objectivec. Не выбирайте никаких дополнительных мастеров, перечисленных на странице шаблонов данного мастера, создав пустой модуль plugin.xml. В результирующий проект добавьте две папки: profiles и libraries. Они будут использоваться для артефактов, предоставляемых модулем.

Показанный на рисунке 4 профиль с именем ObjCProfile.epx реализует набор стереотипов в соответствии с представленным ранее описанием.

Рисунок 4: Профиль ObjCProfile.epx
 ObjCProfile.epx

Библиотека с именем ObjCDataTypes.emx предоставляет внутренние типы данных, наследуемые из С, и добавленные Objective-C. Структура этой модели библиотеки показана на рисунке 5. Обратите внимание, что стереотип «modelLibrary» из профиля Basic необходимо добавить к модели, чтобы пакет RSA мог его распознать.

Рисунок 5: Библиотека OBJCDataTypes.emx
 OBJCDataTypes.emx

Для включения этих ресурсов в модуль и их доступности требуется добавить расширения модулей для регистрации библиотеки типов данных и профиля. Подробные сведения об этих расширениях представлены в листинге 2.

Листинг 2. Файл модуля профиля и библиотеки plugin.xml

        
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
   id="com.ibm.xtools.sample.profiles.objectivec"
   name="Objective-C Profile Plug-in"
   version="1.0.0"
   provider-name="IBM"
   class="com.ibm.xtools.sample.profiles.objectivec.ObjectivecPlugin">

   <runtime>
      <library name="objc-profile.jar">
         <export name="*"/>
      </library>
   </runtime>

   <requires>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.core.runtime"/>
      <import plugin="com.ibm.xtools.uml2.msl"/>
      <import plugin="com.ibm.xtools.emf.msl"/>
   </requires>

   <!-- First the pathmap entry used in the profile extension -->
   <extension 
      id="com.ibm.xtools.sample.profiles.objectivec.pathmap" 
      name="Objective-C Profile Pathmap" 
      point="com.ibm.xtools.emf.msl.Pathmaps">
      <pathmap 
         name="OBJC_PROFILES" 
	 plugin="com.ibm.xtools.sample.profiles.objectivec" 
	 path=""/>
   </extension>
	
   <!-- Add the required profiles -->	   
   <extension
      id="com.ibm.xtools.sample.profiles.objectivec.profile"
      name="ObjectiveCProfile"
      point="com.ibm.xtools.uml2.msl.UMLProfiles">
      <UMLProfile
         id="com.ibm.xtools.sample.profiles.objectivec.profile"
         name="Objective-C"
         path="pathmap://OBJC_PROFILES/profiles/ObjCProfile.epx"
         required="false"
        visible="true">
      </UMLProfile>
   </extension>

   <!-- Add the library data type model -->
   <extension
      id="objcdatatypes"
      name="Objective-C Data Types Library"
      point="com.ibm.xtools.uml2.msl.UMLLibraries">
      <UMLLibrary
         id="objcdatatypes"
         name="Objective-C Data Types"
         path="pathmap://OBJC_PROFILES/libraries/ObjCDataTypes.uml2"
         required="false"
         visible="true">
      </UMLLibrary>
   </extension>

</plugin>

Данный модуль создан.

Модели шаблонов и примеров

Модель шаблона используется в Rational Software Architect, если пользователь выбирает меню File -> New -> UML Model; при этом открывается диалоговое окно, в котором можно выбрать модель из списка текущих зарегистрированных моделей шаблонов. После выбора модели Rational Software Architect  обрабатывает копию шаблона в выбранном проекте. Пример модели берется в RSA в галерее Samples, по существу, это завершенный пример, использованный ранее (AddressModelClass).

Как и на рисунке 3, на рисунке 6 представлены зависимости этого модуля в Rational Software Architect  и на платформе Eclipse. Таким же образом, как и профиль, создайте другой пустой модуль и назовите его com.ibm.xtools.sample.models.objectivec. Как и ранее, создайте две новых папки (examples и templates) для хранения содержимого.

Рисунок 6: Зависимости для модуля профиля
 Dependencies2

Для включения модели шаблона прежде всего необходимо запустить исполняемое приложение. Это необходимо для того, чтобы модель шаблонов в модуле профилей использовала библиотеку профилей и типов данных. Модуль профилей будет активироваться при запуске другого приложения. После запуска исполняемого приложения создайте новый проект моделирования и в нем новую пустую модель, назвав ее Objective-C Model.emx. Rational Software Architect  автоматически открывает эту модель. Ключевые действия здесь необходимы для связи этой модели с ранее созданным профилем и библиотекой.

Сначала выберите саму модель и откройте панель Properties, затем на вкладке Profiles нажмите кнопку Add. Открывается диалоговое окно с двумя секциями: одна для зарегистрированных профилей, в другой можно выбрать профиль из файла. Нужный профиль должен находиться в списке зарегистрированных профилей (см. рисунок 7).

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

Рисунок 7: Добавление профиля Deployed Profile
Deployed Profile 

Далее необходимо подключить библиотеку типов данных. Для этого нажмите правой кнопкой мыши модель и выберите Import Model Library. Библиотека моделей должна появиться в списке зарегистрированных библиотек (см. рисунок 8).

Рисунок 8: Добавление развернутой библиотеки моделей 
Deployed Model 

Перед сохранением и закрытием модели создайте новый пакет с именем MyFramework, а затем примените к нему стереотип «framework» из профиля Basic. Модель должна выглядеть аналогично рисунку 9.

Рисунок 9: Структура шаблона модели
Template Model 

Наконец, необходимо упаковать модель в виде шаблона в новый модуль. Для этого требуется создать в папке шаблонов в рабочем пространстве разработки файл .ve, содержимое которого показано в листинге 3. В эту папку также нужно поместить только что созданную модель, а также значок для отображения в диалоговом окне New UML Model (в данном случае использован значок стандартной модели из RSA). Разработка самого шаблона на этом закончена.

Листинг 3. Файл .ve

        
#
# START NON-TRANSLATABLE
#
id=com.ibm.xtools.sample.models.objectivec.template
templateFile=Objective-C Model.emx
icon=Objective-C Model.gif
#
# END NON-TRANSLATABLE
#

name=Objective-C Model
description=Create a new Model for designing frameworks and applications in Objective-C.

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

Еще нужен простой HTML-файл (overview_simple.html), описывающий созданный пример. Этот файл будет включен в галерею примеров. Файл полностью соответствует HTML-стандарту, но ссылка на действие Install the Sample является обратным вызовом в Rational Software Architect  для выполнения установки. Это показано в листинге 4 (обратите внимание, что текст здесь переформатирован для более четкого представления, не используйте повторно следующий текст). Обратите внимание, что функция liveAction идентифицирует имя мастера, который будет определен в plug-in.xml. Это необходимо выполнить правильно.

Листинг 4. Оперативные действия на странице галереи примеров

        
<a href="#" 
   onclick='liveAction("com.ibm.xtools.sample", 
      "com.ibm.xtools.sample.internal.LiveActionDelegate", 
      "com.ibm.xtools.sample.models.objectivec.simplewizard")' >
   <img src="/SampleGallery/topic?file=com.ibm.gallery.common/images\import_obj.gif" 
      border="0" 
      width="16" 
      height="16" 
      alt="Import icon">
</a>
   
<a href="#" 
   onclick='liveAction("com.ibm.xtools.sample", 
      "com.ibm.xtools.sample.internal.LiveActionDelegate", 
      "com.ibm.xtools.sample.models.objectivec.simplewizard")' >
   Import the sample
</a>

Снова необходимо рассмотреть упаковку, хотя это относительно просто, так как основная часть работы будет связана с файлом plug-in.xml. Для упаковки примера, включенного в галерею примеров, необходимо создать .zip файл с примером модели и файл .project среды Eclipse. Это файл проекта довольно прост (см. листинг 5). После создания zip-файла добавьте его к папке примеров в проекте модуля.

Листинг 5. Пример файла проекта

         
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
   <name>SampleObjectiveCProject</name>
   <comment></comment>
   <projects>
   </projects>
   <buildSpec>
      <buildCommand>
         <name>com.ibm.sse.model.structuredbuilder</name>
         <arguments></arguments>
      </buildCommand>
   </buildSpec>
   <natures></natures>
</projectDescription>

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

Окончательный файл plugin.xml, связывающий все вместе, показан на листинге 6. Расширение для шаблонов модели очень простое: оно только определяет папку, в которой Rational Software Architect  ищет файлы. С другой стороны, расширения для галереи примеров более сложные, для них требуется регистрации как обзорной HTML-страницы, так и мастера, запускаемого по действию установки.

Листинг 6. Шаблон и файл примера plugin.xml

        
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
   id="com.ibm.xtools.sample.models.objectivec"
   name="Objective-C Models Plug-in"
   version="1.0.0"
   provider-name="IBM"
   class="com.ibm.xtools.sample.models.objectivec.ObjectivecPlugin">

   <runtime>
      <library name="objc-models.jar">
         <export name="*"/>
      </library>
   </runtime>

   <requires>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.core.runtime"/>
      <import plugin="com.ibm.xtools.modeler.ui.wizards"/>
      <import plugin="com.ibm.xtools.sample"/>
   </requires>

   <!-- Add the model templates -->
   <extension
	  point="com.ibm.xtools.modeler.ui.wizards.template">
	  <directory path="templates"/>
   </extension>

   <!-- Add the example model -->
   <extension
  	  id="umlmodels.samples"
      point="com.ibm.samplegallery.sample">
      <sample
         href="examples/overview_simple.html"
         name="Objective-C Simple Example"
         category="com.ibm.samplegallery.category.technology.umlmodels"
         id="com.ibm.xtools.sample.models.objectivec.overview_simple">
      </sample>	
   </extension>
    
   <extension
	  id="simplewizard"
      point="com.ibm.samplegallery.importWizard">
      <wizard
         banner="com.ibm.xtools.sample.umlmodels/icons/model_wiz.gif"
         name="Sample Objective-C UML Model Project"
         class="com.ibm.xtools.sample.internal.InstallProjectWizard"
         finalPerspective="com.ibm.xtools.modeler.internal.ui.perspectives.ModelingPerspective"
         id="com.ibm.xtools.sample.models.objectivec.simplewizard">
         <projectsetup
            pagetitle="Import Objective-C UML Model Project"
            name="SampleObjectiveCProject"
            label="Project Name:"
	        open="Objective-C Model.emx"
            pagedescription="Create a project with a sample Objective-C UML model.">
            <import
               dest=""
               src="examples/simple.zip">
            </import>
         </projectsetup>
      </wizard>
   </extension>

</plugin>

Для проверки успешного добавления примера в галерею примеров прежде всего следует запустить исполняемое приложение. Запустив приложение, выберите меню Help -> Samples Gallery и откройте папку Technology Samples, а затем папку UML models. В этой папке должен находиться пример Objective-C. После прочтения связанного обзорного текста можно нажать ссылку установки. Ссылка установки вызывает мастера, создающего новый проект, и позволяющего переименовать проект перед его добавлением к рабочему пространства. На рисунке 10 показана галерея примеров с успешно интегрированным примером.

Рисунок 10: Samples Gallery
Samples 

Разработка преобразования из UML в Objective-C

Преобразование представляет собой один из трех модулей, для которого требуется писать код. Код позволяет UML2 API считывать модель, технология JET помогает записать собственно преобразование и экспортировать текст в ресурсы файловой системы. На рисунке 11 показана отдельная точка расширения, используемая модулем.

Рисунок 11: Зависимости для модуля профиля
Dependencies3 

Создание модуля преобразования

Для создания скелета модуля используйте стандартный мастер модулей Eclipse, как и для создания предыдущих двух модулей. Но в этот раз выберите мастер содержимого. Сначала назовите модуль com.ibm.xtools.sample.transform.objectivec и переместите его в список шаблонов. Выберите из списка шаблон Plug-in with Transformation и переходите к следующей странице. На странице New Transformation Provider не изменяйте имя пакета, но измените имя класса на UML2ObjCTransformationProvider, затем переходите к следующей странице. На этой странице требуется сделать несколько изменений: необходимо сделать Name более читаемым, добавить префикс к имени Class и изменить Target Model Type на Resource (см. рисунок 12).

Рисунок 12: Свойства New Transformation
Transformation 

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

  • UML Element Type = Class
  • ID = com.ibm.xtools.sample.transforms.objectivec.transformation.classrule
  • Name = Class Rule
  • Class = UML2ObjCClassRule
  • Package = com.ibm.xtools.sample.transforms.objectivec.transformation.rules
  • UML Element Type = Interface
  • ID = com.ibm.xtools.sample.transforms.objectivec.transformation.interfacerule
  • Name = Interface Rule
  • Class = UML2ObjCInterfaceRule
  • Package = com.ibm.xtools.sample.transforms.objectivec.transformation.rules

Затем диалоговое окно можно закрыть. Создается код и модуль, результирующий файл plugin.xml выглядит так, как показано в листинге 7.

Листинг 7. Файл преобразования plugin.xml

        
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
   id="com.ibm.xtools.sample.transforms.objectivec"
   name="Objective-C Transformation Plug-in"
   version="1.0.0"
   provider-name="IBM"
   class="com.ibm.xtools.sample.transforms.objectivec.UML2ObjCPlugin">

   <runtime>
      <library name="objc.jar">
         <export name="*"/>
      </library>
   </runtime>

   <requires>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.core.runtime"/>
      <import plugin="com.ibm.xtools.common.core"/>
      <import plugin="com.ibm.xtools.transform.core"/>
      <import plugin="com.ibm.xtools.transform.uml2"/>
      <import plugin="org.eclipse.uml2"/>
   </requires>

   <extension
      point="com.ibm.xtools.transform.core.transformationProviders">
      <TransformationProvider
         class="com.ibm.xtools.sample.transforms.objectivec.transformationProvider.UML2ObjcCTransformationProvider">
         <Priority
            name="Highest">
         </Priority>
         <Transformation
            version="1.0.0"
            name="UML to Objective-C"
            groupPath="com.ibm.xtools.sample.transforms.objectivec"
            sourceModelType="UML2"
            targetModelType="Resource"
            id="com.ibm.xtools.sample.transforms.objectivec.transformation">
            <Property
               readonly="true"
               name="system.transformation.property"
               value="ClassName=
               com.ibm.xtools.sample.transforms.objectivec.transformationProvider.UML2ObjCTransformation;
               IsUMLKind=true;"
               id="system.transformation.property">
            </Property>
         </Transformation>
      </TransformationProvider>
   </extension>

</plugin>


Добавление JET к проекту

Следующий шаг - добавление к проекту JET-типа и создание JET-шаблонов, которые будут использоваться для генерации исходного кода. Сначала выберите меню File -> New -> Other. Выберите в списке папку Java Emitter Templates, а затем мастер Convert Projects to JET Projects. Выберите проект преобразования в списке проектов мастера и нажмите Finish. При этом к проекту добавляется не только JET-тип (и конструкторы), но в проекте также создается папка Templates. Наконец, перед записью первого шаблона, необходимо настроить последний шаг, представляющий собой запись JET своего исходного кода. Для этого выберите проект и откройте Properties, затем выберите JET Settings и убедитесь, что в поле Source Container установлено src (см. рисунок 13).

Рисунок 13: Настройка JET Settings
JET Settings 

Теперь можно создавать собственные шаблоны! Во-первых, это файл скелета, который JET использует как контейнер для сгенерированного Java-класса. Для этого откройте папку шаблонов и создайте новый текстовый файл с именем JET.skeleton (File -> New -> File), а затем добавьте содержимое, показанное в листинге 8.

Листинг 8. Файл JET.skeleton

        
/**
 * This class was generated automatically from a JET template.
 * Copyright (c) 2005,2006 IBM Corporation.
 *
 * @author Simon Johnston
 * @generated
 */
public class CLASS {

   /**
    * The body of this method is generated from a JET template and is intended to
    * be called by an RSA Transformation Framework Rule class.
    *  
    * @param argument a Map containing parameters required by the script.
    * @return the text of the expanded template.
    */
   public String generate(Object argument) {
      return "";
   }
}


Теперь нужно создать фактический шаблон, который будет использоваться для генерации исходного кода для данного UML-класса. Эта операция выполняется в двух местах. Во-первых, создайте новый JET-шаблон, который JET преобразует в Java-класс. Во-вторых, правило, созданное мастером проекта нового модуля, должно вызывать этот сгенерированный JET класс. Итак, создайте простой пустой шаблон. Создайте новый текстовый файл с именем ObjCClassHeadTemplate.javajet и добавьте в него следующий код (см. листинг 9).

Листинг 9. Шаблон ObjCClassHeadTemplate.javajet

        
<%@ jet package="com.ibm.xtools.sample.transforms.objectivec.jetsrc" 
        imports="java.util.* org.eclipse.uml2.*" 
        class="ObjCClassHeadTemplate"
        skeleton="JET.skeleton" 
%>
<%
   /*
    * This template will either generate the header (.h file) or body (.m file) consisting of the
   * Objective-C representation of a given UML Class. The restriction on classes in UML are only
    * that only single inheritance is supported. Also, Objective-C only supports public methods
    * and so private and protected operations in the model will not be generated. Instance variables
    * (attributes/properties) may be public, protected or private but may not be marked static.
    *
    * The UML Class may have the stereotype "category" applied (or a corresponding keyword) in which
    * case the class is restricted also to not provide any additional instance variables.
    */
   final Map parameterMap = (Map) argument;
   if (parameterMap == null) {
      return stringBuffer.toString(); 
   }
%>


Как можно видеть, ожидается, что новый класс (ObjCClassHeadTemplate.java) добавляется к пакету jetsrc, JET выполняет это при сохранении текстового файла. Перед подробным рассмотрением преобразования внесем исправления в правило, чтобы класс вызывал этот сгенерированный класс. Для этого откройте класс UML2ObjCClassRule и добавьте предложения импорта, показанные в листинге 10. Первые два предложения являются просто классами Java-библиотек, третье классом Eclipse и четвертое - сгенерированный JET класс шаблона (в данный момент пропустите четвертое предложение).

Листинг 10. Требуемые предложения импорта

        
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFolder;
import com.ibm.xtools.sample.transforms.objectivec.jetsrc.ObjCClassHeadTemplate;
import com.ibm.xtools.sample.transforms.objectivec.utils.*;

Замените метод createTarget кодом, приведенным в листинге 11. Обратите внимание, что код вызывает шаблон дважды, и использует класс утилит для создания в рабочем пространстве файла на основе шаблона. Также можно заметить, что Java-класс HashMap используется для передачи параметров в JET-шаблон. В шаблоне выше, сгенерированном Java, предполагалось, что параметр argument имеет значение Map.

Листинг 11. Метод createTarget в UML2ObjCClassRule.java

        
   public Object createTarget(ITransformContext ruleContext) {
      /*
       * Extract the class and target from the rule context passed to us.
       */ 
      org.eclipse.uml2.Class theClass = (org.eclipse.uml2.Class)ruleContext.getSource();
		
      if (theClass != null) {
         if (ruleContext.getTargetContainer() != null && ruleContext.getTargetContainer() instanceof IFolder) {
            final IFolder folder = (IFolder)ruleContext.getTargetContainer();

            /*
             * Set up the arguments in a map in preparation to create the header file.
             * Generate the header source using the JET template, passing in the map object.
             */ 
            Map map = new HashMap();
            map.put("GEN_CLASS", theClass);
            map.put("GEN_BODY", new Boolean(false));
				
            ObjCClassHeadTemplate template = new ObjCClassHeadTemplate(); 
            String fileContent = template.generate(map);	
            ResourceUtils.createFile(folder, theClass.getName() 
            + ".h", fileContent, this.getProgressMonitor(ruleContext));
	
            /*
             * Set up the arguments in a map in preparation to create the body file.
             * Generate the header source using the JET template, passing in the map object.
             */ 
            map.remove("GEN_BODY");
            map.put("GEN_BODY", new Boolean(true));
				
            fileContent = template.generate(map);
            ResourceUtils.createFile(folder, theClass.getName() 
            + ".m", fileContent, this.getProgressMonitor(ruleContext));
				
            /*
             * Refresh the workspace.
             */
            try {
               folder.refreshLocal(1, this.getProgressMonitor(ruleContext));
            } catch (Exception ex) {
               System.out.println("ERROR UML2ObjCClassRule.createTarget: exception refreshing folder.");
               ex.printStackTrace();
            }		
         } else {
            System.out.println
            ("ERROR UML2ObjCClassRule.createTarget: targetContainer is either null or not an IFolder.");
         }
      }		
      return null;
   }
   


Преобразование класса

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

  • Вывод заголовка класса, включая предложения импорта и стандартный комментарий;
  • В заголовочном проходе вывод всех переменных экземпляра класса;
  • Вывод всех методов:
    • В заголовочном проходе просто вывод определений;
    • В проходе реализации вывод полного объявления и тела метода, где требуется (далее);
  • Еще одна итерация атрибутов и вывод методов доступа;
    • В заголовочном проходе просто вывод определений доступа;
    • В проходе реализации вывод полного тела объявления в соответствии со стандартными шаблонами (далее);
  • Вывод завершения класса

Тела специальных методов

В Objective-C имеется несколько специальных методов, хотя в отличие от Java или C++ они не являются специальными собственно для языка. Скорее эти методы являются специальными в соответствии с соглашением по именованию. Эти специальные методы включают выделение ресурсов, освобождение ресурсов и инициализацию объектов. Наряду с такими методами в Objective-C для средств доступа имеются другие соглашения или идиомы. Для демонстрации специальных методов и идиом рассмотрим интерфейс класса, представленный в листинге 12.

Листинг 12. Пример интерфейса класса

        
@interface TestClass : NSObject
{
  @private
  NSString *name;
  NSArray *knownAs;
}

+(id)alloc;
-dealloc;
-init;

-(void)setName:(NSString *)newName;
-(NSString*)name;

-(void)addKnownAs:(NSString *)newKnownAs;
-(void)removeKnownAs:(NSString *)oldKnownAs;
-(NSArray *)knownAs;
@end

Этот простой класс имеет отдельную переменную экземпляра name, методы доступа, а также специальные реализации методов alloc, dealloc и init (большинство классов не требует реализации alloc или dealloc). Методы выделения и освобождения ресурсов подобны понятиям конструкторов в Java/C++; но в Objective-C задания на выделение ресурсов и инициализацию разделены на два метода (листинг 13), поэтому значения по умолчанию для набора переменных экземпляра, а также другие операции по инициализации находятся в методе init.

Листинг 13. Пример реализации класса

        
@implementation TestClass

+(id)alloc
{
  self = [super new];
  return self;
}

-(void)dealloc
{
  [name release];
  [knownAs release];
  [super dealloc];
}

- (id)init
{
  self = [super init];
  if (self) {
    name = @"";
    knownAs = [[NSArray alloc] init];
  }
  return self;
}

-(void)setName:(NSString *)newName
{
  [newName retain];
  [name release];
  name = newName;
}

-(NSString *)name
{ 
  return name; 
}

-(void)addKnownAs:(NSString *)newKnownAs
{
  [knownAs addObject: newKnownAs];
}

-(void)removeKnownAs:(NSString *)oldKnownAs
{
  [knownAs removeObject: oldKnownAs];
}

-(NSArray *)knownAs
{
  return knownAs;
}

Средства доступа в Objective-C немного более сложные, чем их аналоги в Java, вследствие протокола подсчета ссылок, реализованного всеми объектами, происходящими от NSObject. Рассматривать этот протокол подробно нет необходимости, поэтому рекомендуется использовать ранее представленные реализации.

Закодировав в JET-шаблоны правила, мы выполнили большую часть работы, и теперь можно протестировать преобразование.

Запуск преобразования

Для запуска преобразования, как и для всех тестов, необходимо запустить исполняемое приложение. После его запуска необходимо использовать модель Objective-C. Можно создать полностью новую модель или использовать модель шаблона с помощью меню File -> New, а также можно воспользоваться примером модели из Samples Gallery! Открыв модель, можно нажать правой кнопкой мыши отдельный класс, интерфейс или пакет и вызвать преобразование. Появляется меню Transformation. При выполнении преобразования в первый раз оно находится в меню Run Transformation, которое представлено на рисунке 14.

Рисунок 14: Меню Transform

 Transform menu

При запуске преобразования в первый раз оно также должно собрать некоторые параметры. Очевидно, что источник уже выбран, так как это был элемент, нажатый правой кнопкой мыши, но необходимо выбрать целевую папку, в которой будут созданы исходные файлы (см. рисунок 15). Преобразование запускается после нажатия кнопки Run, выбирает отдельные ресурсы и обновляет панель проекта.

Рисунок 15: Диалоговое окно Transformation
JET Settings 

Примечание: если используется перспектива Modeling, эти файлы в структуре проекта не отображаются. Для их просмотра переключитесь на перспективу Resource, файлы находятся в списке в Navigator.

Завершение

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

  • Зависимости между классами должны генерировать предложения #import;.
  • В данном примере в модели не создавалось никакой документации: возможно, следует сгенерировать комментарии;.
  • Существует соглашение, согласно которому некоторые модули Rational Software Architect  для регистрации тела метода используют комментарий стереотипный (или использующий ключевое слово), например, «body». Это полезное дополнение к данному примеру.;
  • В Objective-C существует соглашение для предоставления классу частных методов с помощью определения категории в файле реализации. Это может быть относительно простое дополнение с использованием сцепленных шаблонов.;
  • Многие приложения в Objective-C предоставляют заголовок упаковщика, импортирующий все заголовки вложенных классов. Это можно довольно легко выполнить, разработав правило упаковки.;
  • Наиболее важно то, что преобразование не выполняет слияния, поэтому любой код, добавляемый к сгенерированному классу, будет перезаписываться при повторном запуске преобразования.

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

  • Визуализация или сбор моделей из существующего исходного кода отсутствует. Без слияния, как указано ранее, несомненно, нет понятия «полного» проектирования;.
  • Такое преобразование допускает только структурные элементы: не происходит генерации из такого поведения моделей, как машины состояния или действия;
  • В настоящее время Rational Software Architect  идентифицирует файлы .h, сгенерированные редактором C/C++, в которых, как минимум, имеются проблемы с ключевыми словами @interface, @protocol и @end. Файлы .m распознаются как простые текстовые файлы. Истинный элемент языка для его поддержки должен также включать редактор - либо расширение существующего редактора, либо редактор, встроенный из приложения по редактированию текста;
  • Встроенная интеграция отсутствует, но после создания некоторого источника, вероятно, его следует встроить и запустить. Для этого потребуется добавить страницы конструктора, обработки ошибок и настроек.

Поэтому, как можно заметить, имеется множество упражнений, разобраться с которыми читатели смогут самостоятельно.

Создание элемента и обновление сайта

Теперь необходимо создать элемент, заключающий три модуля. Это относительно просто: создайте новый проект элемента (File -> New -> Feature Project), задайте имя проекта com.ibm.xtools.sample.language.objectivec и выберите три модуля, которые нужно включить в элемент. Когда мастер закончит работу, можно отредактировать файл feature.xml и добавить описание и т.д. В результате файл должен выглядеть примерно так, как показано на листинге 14.

Листинг 14. Файл feature.xml

        
<?xml version="1.0" encoding="UTF-8"?>
<feature
   id="com.ibm.xtools.sample.language.objectivec"
   label="com.ibm.xtools.sample.language.objectivec"
   version="1.0.0"
   provider-name="IBM">

   <install-handler/>

   <description>RSA Objective-C Language Modeling</description>

   <copyright>(C) Copyright IBM Corp. 2004.  All Rights Reserved.</copyright>

   <requires>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.core.runtime"/>
      <import plugin="com.ibm.xtools.modeler.ui.wizards"/>
      <import plugin="com.ibm.xtools.sample"/>
      <import plugin="com.ibm.xtools.uml2.msl"/>
      <import plugin="com.ibm.xtools.emf.msl"/>
      <import plugin="com.ibm.xtools.common.core"/>
      <import plugin="com.ibm.xtools.transform.core"/>
      <import plugin="com.ibm.xtools.transform.uml2"/>
      <import plugin="org.eclipse.uml2"/>
   </requires>

   <plugin
      id="com.ibm.xtools.sample.models.objectivec"
      download-size="0"
      install-size="0"
      version="1.0.0"/>

   <plugin
      id="com.ibm.xtools.sample.profiles.objectivec"
      download-size="0"
      install-size="0"
      version="1.0.0"/>

   <plugin
      id="com.ibm.xtools.sample.transforms.objectivec"
      download-size="0"
      install-size="0"
      version="1.0.0"/>

</feature>

Наконец, необходимо создать проект Update Site. Сделать это относительно просто: назовите проект com.ibm.xtools.sample.language.objectivec.site и включите в него ранее созданный элемент. Также стоит добавить к сайту категорию, чтобы облегчить пользователям навигацию при добавлении к своей конфигурации проекта update site. Все это представлено в листинге 15. Для распространения элемента теперь можно развернуть сайт в Интернете или создать сайт обновления архива (что очень просто: нужно заархивировать содержимое проекта Update Site, пользователи могут выполнить установку непосредственно из zip-файла).

Листинг 15. Файл site.xml

        
<?xml version="1.0" encoding="UTF-8"?>
<site>
   <feature 
      url="features/com.ibm.xtools.sample.language.objectivec_1.0.0.jar" 
      id="com.ibm.xtools.sample.language.objectivec" version="1.0.0">
      <category name="Objective-C Language Feature"/>
   </feature>
   <category-def 
      name="Objective-C Language Feature" 
      label="language.objectivec">
      <description>
         Modeling profile, template and example for Objective-C with UML to source transformation.
      </description>
   </category-def>
</site>

Заключение

В заключение можно заметить, что приложения Rational Software Architect  в общем, и особенно приложение преобразования с JET, предоставляют замечательную базу для разработки элементов языка. Можно заметить, что при разработке такого элемента он не обязательно должен быть тривиальным, безусловно, получение рациональной функции «модель->код» не является таким уж сложным. Кроме того, хотя в этой статье описан подход, где цель заключается в полноценном языке программирования, этим подход не ограничивается: можно использовать генерацию для развертывания дескрипторов, конфигурации, определения данных и т.д.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 07.11.2006 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
IBM Rational Functional Tester Floating User License
Rational ClearQuest Floating User License
IBM RATIONAL Clearcase Floating User From Rational Clearcase Lt Floating User Trade Up License + Sw Subscription & Support 12 Months
IBM RATIONAL Quality Manager Quality Professional Authorized User Single Install License + Sw Subscription & Support 12 Months
IBM RATIONAL Rose Enterprise Floating User License + Sw Subscription & Support 12 Months
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Программирование на Visual Basic/Visual Studio и ASP/ASP.NET
ЕRP-Форум. Творческие дискуссии о системах автоматизации
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100