(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 Clearcase Floating User From Rational Clearcase Lt Floating User Trade Up License + Sw Subscription & Support 12 Months
IBM Rational Functional Tester Floating User License
IBM RATIONAL Quality Manager Quality Professional Authorized User Single Install License + Sw Subscription & Support 12 Months
Rational ClearCase Multisite Floating User License
IBM RATIONAL Clearcase 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 "с нуля"
Компьютерные книги. Рецензии и отзывы
Проект mic-hard - все об XP - новости, статьи, советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100