學習如何創建和調用一個能夠在headless 操作(命令行)模式中運行從而在兩個 UML 模式之間生成一個變更列表的 Ant 任務。先決條件:這些工具都必須是 7.0.0.5版本: IBM® Rational® Application Developer,IBM® Rational® Software Architect, 或者 IBM® Rational® Software Modeler。
IBM® Rational® Software Architect 以及它的相關產品(參見說明) 為小組的模型驅動開發(MDD)以及平行開發提供強有力的 UML 建模技術。這些包括轉換和比較-合併技術。
註釋:
在這篇文章中,“Rational 軟體”表示這些產品中的任何一個:Rational® Software Architect, Rational® Application Developer, 或者 Rational® Software Modeler。
這裡有幾種情形,對通過命令行工具在模型之間產生差別列表是十分有利的,在一個構建過程或者當量中或許只是作為一個步驟。例如:
這篇文章主要研究 MDD 情形,因為這很可能就是這個技術所需要的情形。而在其它 情形採用此技術則相對比較直接。
在代碼和模型之間產生差量列表的選項
根據這個項目規模的大小,主模型的變更可來自多個開發人員。一個構件可能需要在將它們引入到主模型之前瀏覽來自單個貢獻者的變更設置。通常情況下,這是由一個轉換來完成的,比如 Java-to-UML。這個轉換會產生一個反映 Java 代碼當前狀態的 UML 模型。要查看主模型和一個源自此代碼的模型之間的區別,可以採取幾種方式來實現。
方法之一是將這個目標轉換輸出作為這個主模型。在 Rational 軟體環境中運行此轉換將會啟動一個可視的結構合併會話(正如 融合 ——請參見下面的 Note),這樣可以在把它們應用到主機(目標)模型之前展現一個變更列表。這種方法將會在委託此結構合併會話之上修改這個主模型。
註釋: 融合 (一個 結構對比)是一項僅僅利用合格的名稱來對照模型的技術,並且為在模型之間或者結構變更提供一個機制,而且無論這些模型是否共享一個始祖。它還受到合併模型命令的刺激。融合廣泛地應用於 MDD 中 調整工作流程。
然而,這項技術卻不能自動從命令行中產生。相反,這個合併技術(請參見下面的 Note)卻可用來將這個問題轉換為身份的對照。一個生成的模型可以保存到一個位置標誌符(一個空白模型),與主模型合併,然後對照會話就可以運行,從而創建一個變更列表(請參見圖 1)。這個合併工具和身份對照技術都允許自動化和命令行的調用。
註釋: 模型 聯合就是一項可以改善目標模型的元素身份使其與源模型中相同的元素相匹配的技術。它利用精密的身份匹配器來產生在稍後的模型中可以匹配的關鍵元素,這樣以來這些元素 ID 就可以向前移動。這樣就有效地在這些模型之間創建了一個始祖關係,它們似乎都是直接從一個到另一個這樣演化而來的。這樣利用這篇文章中所描述的方法就可以使它們變得具有可比性。
圖 2 顯示了在這些模型之間的可視化合併過程中,當點擊 Save deltas 按鈕時這些差量列表是如何保存的。假設這個標識必須從一個可視化會話中產生,並且由於要剖析這個文件從而創建更多精緻的瀏覽工具十分困難,就會採用可替換機制和文件格式。
運行一個 Ant 任務實現自動化
這種方法是由一個 Apache Ant 任務實現自動化的。Ant 任務可以從命令行開始以批量處理模式運行,這樣可以產生一個變更列表並將它們保存到一個文件中。此外,生成的變更列表可以以可導向模式保存。Compare Merge 中的功能可以下載這樣的文件到 Rational 軟體並用 Delta Annotation Viewer 來瀏覽它們,如圖 3所示(請參見資源,可學習更多的關於 deltas 的知識)。
創建一個 Eclipse Ant 項目
假設這樣的情景:
要滿足這些需求,您將創建一個您可以通過命令部署的 Ant 任務類。
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Ant Plug-in Bundle-SymbolicName: com.acme.headless.ant;singleton:=true Bundle-Version: 1.0.0 Bundle-Activator: com.acme.headless.ant.Activator Bundle-Vendor: ACME Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.ant.core, org.apache.ant, org.eclipse.gmf.runtime.emf.core.compatibility, com.ibm.xtools.transform.core, com.ibm.xtools.uml.core, com.ibm.xtools.uml.msl, com.ibm.xtools.comparemerge.modelconverter, com.ibm.xtools.comparemerge.delta.annotation.ui, com.ibm.xtools.comparemerge.core Eclipse-LazyStart: true |
package com.acme.headless.ant.task; public class DifferencesLogger extends org.apache.tools.ant.Task { // ant task parameter variables // absolute path to transformation configuration (.tc) file public String transformConfigPath; // absolute path to the master model to be compared to public String masterModelPath; // absolute path to the auto-generated changes log (the file does not have pre-exist) public String deltaLogFileName; // absolute path to a blank model template public String blankModelPath; // private members private String tempModelName = "HTBlankModel"; //$NON-NLS-1$ private URI tempModelURI = null; } |
/* * Execute task * (non-Javadoc) * @see org.apache.tools.ant.Task#execute() */ public void execute() throws BuildException { try { // load transformation configuration file IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( new Path(transformConfigPath)); ITransformConfig config = TransformConfigUtil.loadConfiguration(file); //prepare Java to UML transformation forward context by switching its target container to point to a temporary, empty model file ITransformContext forwardContext = createTarget(config); //execute transformation IStatus status = TransformController.getInstance(). execute(config, forwardContext, false, true, null); System.out.println("Completed transform execution, status = " + status.getMessage()); if (status.getCode() == IStatus.OK) { // instantiate model alignment facade ModelConverterFacade mc_facade = new ModelConverterFacade(); //verify that master copy does exist File baseFile = new File(getMasterModelPath()); if (!baseFile.exists()) { System.out.println("Invalid master copy path: " + getMasterModelPath()); System.out.println("Please correct the parameter and re-run the script"); return; } // obtain model file created by transformation. Verify it exits File contributorFile = new File(getTemporaryModelURI().toFileString()); if (!contributorFile.exists()) { System.out.println("Error during transformation: failed to create target file"); System.out.println("Verify that " + contributorFile.getParent() + " is not read-only”); return; } // align master and contributor files if (!mc_facade.alignSingleModelFile(baseFile, contributorFile, null, contributorFile)) { System.out.println("Error during model alignment"); System.out.println(contributorFile.getAbsolutePath() + " should exist!"); return; } // compare aligned models and save changes log compareWithEachOther(baseFile, contributorFile); } } catch (Exception e) { e.printStackTrace(); System.out.println("Failed execution" + e.getLocalizedMessage()); } } |
<extension point="org.eclipse.ant.core.antTasks"> <antTask class="com.acme.headless.ant.task.DifferencesLogger" library="delta_logger.jar" name="diff_logger"> </antTask> </extension> |
bin.includes = META-INF/,\ delta_logger.jar,\ plugin.xml source.delta_logger.jar = src/ output.delta_logger.jar = bin/ |
圖 5. 創建 Ant 構建文件
安裝運行環境
要闡述這個步驟,我們已經在附加的 Projects.zip 壓縮文件中提供了三個案例(請參見 下載)。按照下列這些步驟來使用這三個項目:
<target name='mytest'> < diff_logger transformConfigPath='C:\targets\my-workspace\Java Project\J2UML.tc' masterModelPath='C:\targets\my-workspace\Model Project\Blank Model.emx' deltaLogFileName='C:\targets\my-workspace\Model Project\changes_log.xml' blankModelPath='C:\targets\my-workspace\Model Project\template\EmptyModel.emx' /> </target> |
<project name="AntRunnerPlugin" default="mytest" basedir="."> |
註釋:
確保 C:\targets\my-workspace 是由您工作空間的真實位置所代替的。
運行環境現在已經安裝,這個任務可以在 Rational 軟體中,也可以在 headless 操作模式中運行。
這個 EMF 層級 deltas (單個的變更), 顯示在葉節點,可以在 UML 層級很方便地歸到複核的 deltas 中。這些複合構件代表姿勢或者其它邏輯分類(比如一個拖拽-放下複合對象圖解,這將導致一個組位置變更,包裹-相關變更,比如變更到特定的包裹複合 delta,等等)。
在 headless 操作模式中運行這個任務
setlocal REM RUNANT_DIR=This directory (which may, or may not, be your current working directory) set RUNANT_DIR=%~dp0 set debug= if not '%1' == 'debug' goto studio set debug=-Xdebug -Xnoagent -Djava.compiler=none ^ -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 :studio REM The root directory of your Studio installation set STUDIO_DIR=C:\Program Files\IBM\SDP70 if not exist '%STUDIO_DIR%'\jdk\jre set STUDIO_DIR=%RUNANT_DIR%..\..\.. if not exist '%STUDIO_DIR%'\jdk\jre echo ERROR: incorrect STUDIO_DIR=%STUDIO_DIR% if not exist '%STUDIO_DIR%'\jdk\jre goto done :java if not $%JAVA_DIR%$==$ goto workspace set JAVA_DIR=jdk\jre\bin :workspace if not $%WORKSPACE%$==$ goto check REM ####################################################### REM ##### you must edit the 'WORKSPACE' setting below ##### REM ####################################################### REM *********** The location of your workspace ************ set WORKSPACE=C:\targets\my-workspace :check REM ************* The location of your workspace ***************** if not exist '%WORKSPACE%' echo ERROR: incorrect workspace=%WORKSPACE%, edit this runAnt.bat and correct the WORKSPACE envar if not exist '%WORKSPACE%' goto done set LOCATIONS=-DSTUDIO.DIR=%STUDIO_DIR% -DSTUDIO.RUNANT= %RUNANT_DIR% -DSTUDIO.WORKSPACE=%WORKSPACE% :run @echo on '%JAVA_DIR%\java' -cp '%STUDIO_DIR%\startup.jar' %debug% org.eclipse.core.launcher.Main -debug -application org.eclipse.ant.core.antRunner -data '%WORKSPACE%' -file %WORKSPACE%\AntRunnerPlugin\build.xml |
改編一個客戶的轉換
[火星人 ] 實現 UML 模型的自動化比較及合併:通過在 IBM Rational 軟體交付平台上運行一個 Ant 任務已經有839次圍觀