引言
IBM® WebSphere® MQ 環境功能強大並涉及許多對象定義。允許自動檢查這些對象定義的系統有助於加快 WebSphere MQ 網絡的開發與調試。
WebSphere MQ Explorer 是 WebSphere MQ 管理工具集的名稱,您可以使用它來創建、更改和刪除對象。MQ Explorer 基於 Eclipse 構建,可以通過 Eclipse 插件進行擴展。本文向您介紹如何編寫插件來在 WebSphere MQ 環境中執行檢查,並通過一個插件示例來驗證所有對象是否符合公司的命名標准。
將使用 Java™ 和 XML 來編寫該插件,同時該插件將實現可以從 WebSphere MQ Explorer GUI 啟動的檢查。結果將顯示在 Eclipse Problems View 中,並且可以分為 Errors、Warnings 或 Information 三類。
圖 1. WebSphere MQ Explorer GUI(介紹 Problems View 的用法以顯示測試和檢查的結果)
先決條件
本文假定您已經在 Linux® 或 Microsoft® Windows® 上安裝了 WebSphere MQ Explorer。本文還假定您希望使用 WebSphere MQ Explorer 附帶的 Eclipse 工作台。在缺省情況下,WebSphere MQ Explorer 禁用了 Eclipse 平台的完整工作台功能。要啟用該工作台,請依次選擇 Windows => Preferences => WebSphere MQ Explorer 和 Startup in an Eclipse workbench,然後重啟 WebSphere MQ Explorer。
圖 2. WebSphere MQ Explorer Preferences 對話框(顯示運行完整 Eclipse 工作台所需的設置)
本文還使用 WebSphere MQ Explorer Healthcheck SupportPac (MH01) 來減少自定義檢查所需的 Java 開發。您可以從本文底部下載 MH01 SupportPac(包括安裝說明)。它帶來了以下好處:
與 WebSphere MQ Explorer 和 Eclipse GUI 集成——用於運行新檢查的 GUI 控件自動包含在 GUI 中;檢查發現的結果顯示在 Problems View 中並為您進行管理;您提供的任何文檔都以適當的方式顯示和啟動;等等。
基本線程模型——當使用 WebSphere MQ Explorer GUI 時,您可以在後台運行新檢查,並且與其他測試並行進行,而無需考慮代碼中的線程含義。
您自己需要做的只是編寫邏輯代碼來檢查問題,以及描述應該如何描述您發現的潛在問題。
准備插件開發環境
Eclipse 插件開發透視圖
可以使用隨 Eclipse Java IDE 一起提供的 WebSphere MQ Explorer 來開發插件。要切換到 Eclipse 插件開發環境 (PDE),請選擇 Window => Open Perspective => Other。PDE 為您提供了開發環境概述、用於編輯 Java 和 XML 文件的編輯器以及其他許多有用的視圖。有關 PDE 的更多信息,請參閱下面的參考資料。
創建新項目
為您的代碼創建一個新的插件項目。右鍵單擊最新添加的項目旁邊的 Package Explorer,然後選擇 New => Plug-in Project。在本示例中,將新項目命名為 com.ibm.mq.explorer.healthcheck.samples。
創建後,打開為新插件自動生成的 plugin.xml。使用 Dependencies 選項卡將以下插件作為新插件的依賴項添加進來。其中有一些是核心 Eclipse GUI 插件的組合,也有一些是 WebSphere MQ 使用的項目:
com.ibm.mq.commonservices
com.ibm.mq.explorer.core
com.ibm.mq.explorer.healthcheck
com.ibm.mq.explorer.plugins
com.ibm.mq.explorer.ui
com.ibm.mq.internal.pcf
com.ibm.mq.internal.pcf.event
com.ibm.mq.runtime
org.eclipse.core.resources
圖 3. plugin.xml 中的依賴項
創建新測試
每個測試都需要:
插件的 XML 中的一個條目,用於向 WebSphere MQ Explorer GUI 提供為測試顯示的信息
一個執行測試的 Java 類
在 XML 中定義新測試
打開為您的插件生成的 plugin.xml。使用 Extensions 選項卡來向您的項目添加 com.ibm.mq.explorer.healthcheck.MQtests。
右鍵單擊 MQtests 擴展,添加一個新的 test 條目,它將定義您的測試:
圖 4. plugin.xml 中的新擴展
當選定測試項目時,輸入以下信息:
name —— 一個用戶友好的名稱,當表示此檢查時將顯示在 GUI 中
class —— 下一步您將編寫的 Java 類的完全限定名稱
id —— 此測試的唯一標識符(例如上面輸入的 Java 類的完全限定名稱)
description —— 該測試的一個簡短描述,將在 GUI 中顯示
testset —— 測試集的名稱。使用 GUI,您可以將測試分成幾組測試集(這在有大量測試時非常有用),也可以輕松地運行一組檢查。如果您輸入的測試集名稱不存在,則將為您創建一個。這是可選的,但是建議您這樣做。
furtherinfo —— HTML 頁面的位置,該頁面顯示有關此測試及其創建的結果的更詳細的信息。該 GUI 可以顯示用於解釋它們返回的結果的附加文檔,並提供如何解決問題的指南。文檔應該以 HTML 的形式提供,並且可以將其標識為下面兩種類型之一:
Internal(在插件內部) —— 存儲在提供測試本身的插件項目中。存儲位置應該定義在與 plugin.xml 文件本身相關的 XML 中;例如 doc/TestDoc.html。
External(在插件外部) —— 存儲在 Web 服務器上,允許將文檔的維護與測試本身分離開來。使用以 http:// 開頭的完整 URL 來指定位置。
例如,輸入以下內容來定義一個將對您的 MQ 環境的命名約定進行驗證的測試:
圖 5. plugin.xml 擴展
單擊 plugin.xml 選項卡並查看 XML 源。您的 XML 應該如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
id="com.ibm.mq.explorer.healthcheck.samples"
name="Custom WebSphere MQ Tests"
version="1.0.0"
provider-name="IBM developerWorks"
class="com.ibm.mq.explorer.healthcheck.samples.SamplesPlugin">
<runtime>
<library name="samples.jar">
<export name="*"/>
</library>
</runtime>
<requires>
<import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.core.runtime"/>
<import plugin="com.ibm.mq.commonservices"/>
<import plugin="com.ibm.mq.explorer.core"/>
<import plugin="com.ibm.mq.explorer.healthcheck"/>
<import plugin="com.ibm.mq.explorer.plugins"/>
<import plugin="com.ibm.mq.explorer.ui"/>
<import plugin="com.ibm.mq.internal.pcf"/>
<import plugin="com.ibm.mq.internal.pcf.event"/>
<import plugin="com.ibm.mq.runtime"/>
<import plugin="org.eclipse.core.resources"/>
</requires>
<extension point="com.ibm.mq.explorer.healthcheck.MQtests">
<test
furtherinfo="doc/QueueNamesInfo.html"
class="com.ibm.mq.explorer.healthcheck.samples.QueueNames"
description="A sample test to check queue names against simple naming conventions."
testset="Queues"
name="Naming Conventions"
id="com.ibm.mq.explorer.healthcheck.samples.QueueNames"/>
</extension>
</plugin>
MQtests XML 是在 Healthcheck 插件中定義的一個接口,它使 Healthcheck 能夠正確地從多個插件中查找和加載測試。有關插件體系結構的更多信息,請參閱下面的參考資料中的 Eclipse 文章。
用 Java 准備新測試
通過 Package Explorer 創建一個新的 Java 類,確保給它提供的名稱和包與前面定義的 XML 的 class 屬性中標識的位置一致。該類應該擴展 com.ibm.mq.explorer.healthcheck.objects.WMQTest。
Problems View 將繼續顯示任何現有的 WebSphere MQ Explorer Healthcheck 問題以及您的 Java 源的問題。您可以使用 Problems View 篩選器將這些問題過濾掉。
此時,我們選擇用最少的工作使 Java 類能夠編譯,也就是創建一個空的類。稍後我們將返回到該類的實現細節。
package com.ibm.mq.explorer.healthcheck.samples;
import com.ibm.mq.explorer.healthcheck.objects.WMQTest;
/**
* Empty test class - enough to compile.
*
* @author Dale Lane
*/
public class QueueNames extends WMQTest {
}
為新測試准備文檔
編寫要在 GUI 中與測試一同顯示的文檔。文檔應該用 HTML 編寫,並且保存在 plugin.xml 文件中指定的位置中。正如前面所描述的,這個位置可以是本地的(在插件內部,例如保存在 doc 文件夾中),也可以是遠程的(在 Web 服務器上)。
圖 6. 顯示HTML 文檔的位置的項目結構(與上面所示的 XML 一致)
部署測試
在 Package Explorer 中,右鍵單擊您的項目並選擇 Export。單擊 Deployable plug-ins and fragments。在打開的 Export 對話框中,單擊 Deploy as a directory structure 並設置一個目標目錄作為 Healthcheck 插件的安裝位置。Windows 中的缺省安裝位置是 C:\Program Files\IBM\WebSphere MQ\eclipse,而在 Linux 上為 /opt/mqm/eclipse/plugins/。
重啟 Eclipse。在重新打開之後,通過 Windows 菜單返回到 WebSphere MQ Explorer 透視圖。根據 plugin.xml 中的指定,新測試應該出現在 Queues 文件夾的 WebSphere MQ Healthcheck 節點下的 Navigator View 樹狀視圖中。如果您在該樹狀視圖中單擊您的新測試,則應該會在 Content View 頁面中顯示您的 HTML 文檔。
如果您的 HTML 文檔在 WebSphere MQ Explorer GUI 中不可見,則可能是沒有將 HTML 文件包含到插件的構建中。請將 HTML 文件添加到構建列表中,其方法是打開 build.properties 文件並在 Binary Build 列表中選擇您的文檔:
圖 7. 構建配置
一旦確認插件的結構工作正常,請返回到 PDE 來為測試提供實現。
在對 Java 代碼進行任何更改之後,都必須重復上述部署步驟來重新測試。或者,也可以在開發過程中使用 Run As => Run-time Workbench 來啟動 Eclipse 測試實例,它可以讓您不需要關閉開發環境就可以進行更改和測試更改。接下來可以在更改完成之後再執行上面列出的部署步驟。
用 Java 實現新測試
初步嘗試
我們將逐步構建我們的測試,並用下面的更加詳細的說明性文字來對示例源代碼進行注釋。我們的首次嘗試將返回靜態數據,並演示 WMQTest 接口的基本元素:
package com.ibm.mq.explorer.healthcheck.samples;
import java.util.ArrayList;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import com.ibm.mq.explorer.healthcheck.HealthcheckPlugin;
import com.ibm.mq.explorer.healthcheck.actions.WMQTestEngine;
import com.ibm.mq.explorer.healthcheck.objects.WMQTest;
import com.ibm.mq.explorer.healthcheck.objects.WMQTestResult;
/**
* A sample skeleton implementation of a Healthcheck test.
*
* Download the source from Resources below.
*
* @author Dale Lane
*/
public class QueueNames extends WMQTest {
// notice that no constructor is required
/**
* Starts the test.
*
* @param callback handle to the test engine running the test
* @param guimonitor handle to the object monitoring the test,
* provided to allow the test to periodically check
* if the user has tried to cancel the test running
* and provide additional user feedback
*/
public void runTest(WMQTestEngine callback, IProgressMonitor guimonitor) {
// start with the default implementation. this will store a handle
// to the test engine that will be needed when we want to submit
// any results at the end of the test
super.runTest(callback, guimonitor);
// start the progress monitor for this test
String myName = getTestName();
guimonitor.beginTask(myName, 10);
guimonitor.subTask("Getting preferences for test");
// prepare space to store any results we might want to return
ArrayList testResults = new ArrayList();
// generate nine meaningless test results
for ( int i=0; i < 9; i++ ) {
// update progress monitor
guimonitor.subTask("Generating test result " + i + " of 9");
// if the test has been cancelled, we break out of the
// for loop to return asap
if ( isCancelled() )
break;
try {
// wait here for two seconds to simulate lengthy test processing
Thread.sleep(2000);
} catch ( InterruptedException e ) {
// unexpected exception
Status internal_error = new Status(IStatus.ERROR,
"com.ibm.mq.explorer.healthcheck.coretests",
0,
"Unexpected exception encountered while "
+ "waiting for test to return",
e);
HealthcheckPlugin.getPlugin().getLog().log(internal_error);
}
// create a fake result and add it to the list
WMQTestResult nxtResult = new WMQTestResult(IMarker.SEVERITY_INFO,
"Blah blah blah test result number "
+ i + " here",
"QMGR_1",
"Queues");
testResults.add(nxtResult);
// increment progress monitor
guimonitor.worked(1);
}
// update progress monitor
guimonitor.subTask("Returning results to test engine");
// return any results that this test has generated
WMQTestResult[] finalresults =
(WMQTestResult[]) testResults.toArray(new WMQTestResult[testResults.size()]);
testComplete(finalresults);
// complete progress monitor
guimonitor.done();
}
}
請嘗試使用此示例代碼來修改您自己的測試對象,並將它重新部署到測試中。您應該能夠運行您的測試,並在 Eclipse Problems View 中顯示它生成的模擬結果。
有 MQ 參與的嘗試
現在,我們將向測試對象添加特定於 WebSphere MQ 的代碼,以允許它驗證隊列對象的名稱。
本文不是用 Java 編寫 WebSphere MQ 應用程序的教程。有關 Java API 的更多信息,請參閱手冊 Using Java。它可以向您說明如何修改此示例以訪問對象而不是隊列、屬性而不是對象名稱。然而,編寫代碼來與 Explorer GUI 集成的基本方法與此相同:
package com.ibm.mq.explorer.healthcheck.samples;
import java.io.IOException;
import java.util.ArrayList;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import com.ibm.mq.MQException;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.explorer.healthcheck.HealthcheckPlugin;
import com.ibm.mq.explorer.healthcheck.PreferenceStoreManager;
import com.ibm.mq.explorer.healthcheck.actions.WMQTestEngine;
import com.ibm.mq.explorer.healthcheck.objects.WMQTest;
import com.ibm.mq.explorer.healthcheck.objects.WMQTestResult;
import com.ibm.mq.explorer.ui.extensions.MQQmgrExtObject;
import com.ibm.mq.explorer.ui.internal.objects.ExplorerExtensionBase;
import com.ibm.mq.pcf.CMQC;
import com.ibm.mq.pcf.CMQCFC;
import com.ibm.mq.pcf.PCFMessage;
import com.ibm.mq.pcf.PCFMessageAgent;
/**
* A sample test used to check Queue Names against naming conventions.
* Queue names are checked if they begin with any of a set range of
* prefixes, defined in this class. Any names which do not start with
* one of the prefixes are output in an error.
*
* Download the source from Resources below.
*
* @author Dale Lane
*/
public class QueueNames extends WMQTest {
/** Maintain a count of how many queue managers we are waiting for replies from. */
private static int numberOfQmgrs = 0;
/** Stores the accepted queue name prefixes. */
private static final String[] ACCEPTED_Q_PREFIXES = { "SALES_",
"MARKETING_",
"SHIPPING_",
"INCOMING_",
"OUTGOING_" };
/** Stores the user preference for whether hidden queue managers should be included. */
boolean includeHiddenQmgrs = false;
/** Stores the user preference for whether system queues should be included. */
boolean includeSystemObjs = false;
/**
* Starts the test.
*
* @param callback handle to the test engine running the test
* @param guimonitor a handle to the object monitoring the test,
* provided to allow the test to periodically check
* if the user has tried to cancel the test running
* and provide additional user feedback
*/
public void runTest(WMQTestEngine callback, IProgressMonitor guimonitor) {
// start with the default implementation. this will store a handle
// to the test engine that will be needed when we want to submit
// any results at the end of the test
super.runTest(callback, guimonitor);
// prepare space to store any results we might want to return
ArrayList testResults = new ArrayList();
// get from Preferences whether we should include hidden queue managers
includeHiddenQmgrs = PreferenceStoreManager.getIncludeHiddenQmgrsPreference();
// get from Preferences whether we should include system queues
includeSystemObjs = PreferenceStoreManager.getIncludeSysObjsPreference();
// get a list of queue managers from the Explorer
ArrayList allQmgrs;
if (includeHiddenQmgrs){
allQmgrs = ExplorerExtensionBase.getAllQueueManagers();
}
else {
allQmgrs = ExplorerExtensionBase.getShownQueueManagers();
}
// how many queue managers are there?
numberOfQmgrs = allQmgrs.size();
// use the number of queue managers as a guide to track progress
guimonitor.beginTask(getTestName(), numberOfQmgrs);
// for each queue manager, submit a query
for (int i=0; i < numberOfQmgrs; i++){
// get next queue manager
MQQmgrExtObject nextQueueManager = (MQQmgrExtObject) allQmgrs.get(i);
// only submit queries to connected queue managers
if (nextQueueManager.isConnected()){
// get the name of the queue manager, for use in GUI
String qmgrName = nextQueueManager.getName();
// get a handle to a Java object representing the queue manager
MQQueueManager qmgr = nextQueueManager.getMQQueueManager();
try {
// get a PCF message agent to handle sending PCF inquiry to
PCFMessageAgent agent = new PCFMessageAgent(qmgr);
// use PCF to submit an inquire queue names query
PCFMessage response = submitQueueNamesQuery(qmgrName, agent);
// did we get a response to the query?
if (response != null){
// get the queue names out of the reply
String[] qnames = (String[]) response.getParameterValue(CMQCFC.MQCACF_Q_NAMES);
// check each name
for (int j=0; j < qnames.length; j++){
boolean qnameOkay = checkQueueName(qnames[j]);
if (!qnameOkay){
// if a problem was found with the name, we generate an
// error message, and add it to the collection to be
// returned
testResults.add(generateTestResult(qnames[j], qmgrName));
}
}
}
} catch (MQException e) {
// record error details
Status internal_error = new Status(
IStatus.ERROR,
"com.ibm.mq.explorer.healthcheck.coretests",
0,
"Error encountered while getting PCFMessageAgent to "
+ qmgrName,
e);
HealthcheckPlugin.getPlugin().getLog().log(internal_error);
}
}
// finished examining a queue manager
guimonitor.worked(1);
}
// return any results that this test has generated
WMQTestResult[] finalresults =
(WMQTestResult[]) testResults.toArray(new WMQTestResult[testResults.size()]);
testComplete(finalresults);
}
/**
* Used internally to submit INQUIRE_Q_NAMES query using PCF to given queue manager
*
* @param qmgrName name of queue manager to submit query to
* @param agent
* @return PCF response from queue manger
*/
private PCFMessage submitQueueNamesQuery(String qmgrName, PCFMessageAgent agent){
// build the pcf message
PCFMessage inquireQNames = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_NAMES);
inquireQNames.addParameter(CMQC.MQCA_Q_NAME, "*");
try {
// send the message
PCFMessage[] responseMsgs = agent.send(inquireQNames);
// check if results received successfully
if ( responseMsgs[0].getCompCode() == 0 ) {
return responseMsgs[0];
}
} catch (IOException e) {
// record error details
Status internal_error = new Status(
IStatus.ERROR,
"com.ibm.mq.explorer.healthcheck.coretests",
0,
"Error encountered while sending INQUIRE_Q_NAMES PCF to "
+ qmgrName,
e);
HealthcheckPlugin.getPlugin().getLog().log(internal_error);
} catch (MQException e) {
// record error details
Status internal_error = new Status(
IStatus.ERROR,
"com.ibm.mq.explorer.healthcheck.coretests",
0,
"Error encountered while sending INQUIRE_Q_NAMES PCF to "
+ qmgrName,
e);
HealthcheckPlugin.getPlugin().getLog().log(internal_error);
}
// for some reason, we don't have a response, so return null
return null;
}
/**
* Used internally to check the given queue name against the collection
* of acceptable prefixes.
*
* @param queueName queue name to check
* @return true if queue name is okay,
* false otherwise
*/
private boolean checkQueueName(String queueName){
// if this is a system object (i.e. it has a name which begins with
// "SYSTEM.") we check the
if ((queueName.startsWith("SYSTEM.")) || (queueName.startsWith("AMQ."))){
if (!includeSystemObjs){
// user has requested that we do not include system
// objects in the test, so we return true to
// avoid any problems being reported for this queue
return true;
}
}
// PCF response will white-pad the queue name, so we trim it now
queueName = queueName.trim();
// check the queue name against each of the acceptable prefixes
// in turn, returning true immediately if it is
for (int i=0; i < ACCEPTED_Q_PREFIXES.length; i++){
if (queueName.startsWith(ACCEPTED_Q_PREFIXES[i]))
return true;
}
// we have checked against all accepted prefixes, without
// finding a match
return false;
}
/**
* Used internally to generate a test result for the given queue name.
*
* @param queueName queue name that doesn't meet requirements
* @param qmgrName name of queue manager that hosts the queue
* @return generated test result
*/
private WMQTestResult generateTestResult(String queueName, String qmgrName){
return new WMQTestResult(IMarker.SEVERITY_ERROR,
"Queue (" + queueName.trim() + ") "
+ "does not begin with "
+ "a known prefix",
qmgrName,
"Queues");
}
}
請記下上面的源代碼
跳過下一部分。
創建您的測試對象
正如前面指定的,您的測試應該擴展 WMQTest。WebSphere MQ Explorer 將使用提供的構造函數來實例化該測試對象 WMQTest()。您不需要對此構造函數進行子類化。
測試屬性
下面的表格列出了 WMQTest 超類的一些屬性,以及它們的訪問方法。這些屬性不可由子類實現更改,但可能對輸出非常有用。
屬性名稱 屬性訪問器 屬性說明 test id getTestId() 一個字符串,它包含在 plugin.xml 中指定的測試的唯一標識符 name getTestName() 一個字符串,它包含在 plugin.xml 中指定的測試的用戶友好名稱 description getDescription() 一個字符串,它包含在 plugin.xml 中指定的測試說明 documentation path getFurtherInfoPath() 一個字符串,它包含在 plugin.xml 中指定的測試的 HTML 文檔位置創建測試結果
當測試發現需要向用戶返回某些東西時,它應該創建一個測試對象來描述問題。測試結果是作為 WMQTestResult 對象實現的,應該使用 new WMQTestResult(int severity, String description, String qmgrname, String objectType) 來創建。
severity 一個整數,標識問題嚴重程度,應該為以下值之一:IMarker.SEVERITY_ERROR、IMarker.SEVERITY_WARNING 或 IMarker.SEVERITY_INFO description 解釋測試發現的問題的字符串,將在 Problems View 中顯示 qmgrname 在其中發現問題的隊列管理器的名稱 objectType 一個字符串,它給出在其中發現問題的對象的類(例如 “Queues”、“Channels”等。)啟動測試
WebSphere MQ Explorer 調用 runTest(WMQTestEngine, IProgressMonitor) 來開始運行測試。測試的主體應該如下所述。
runTest 方法在開始時應該用 super.runTest(callback, guimonitor) 來調用 runTest 的缺省實現。它將句柄緩沖到提供的參數中,各種後台任務都需要這些參數。
WMQTestEngine 參數向運行測試的測試引擎提供了一個句柄。當一個測試還在進行中時,該句柄使用測試引擎的 returnResult(WMQTestResult[], WMQTest) 方法來讓測試返回結果:
此方法 (WMQTestResult[]) 的第一個參數包含要返回的結果。
第二個參數 (WMQTest) 應該是 this,以便測試引擎知道結果來自何處。
使用 WMQTestEngine 參數來返回中間結果是可選的,但是對長時間運行的測試可能十分有用。或者,可以在測試完成時返回測試結果,如下所示。
IProgressMonitor 參數向用於運行當前測試的 GUI 反饋監視器提供一個句柄。它讓測試同時提供當前運行的任務和/或子任務的文本反饋以及完成進度欄。
Progress Monitor 的句柄是由上述 runTest 的缺省實現緩存的,所以 Progress Monitor 的句柄也可以使用 WMQTest 方法 getGUIMonitor() 來訪問。
Progress Monitor 是一個核心 Eclipse 資源。有關如何使用它的詳細信息,請參閱 Eclipse API 文檔。下面的表格列出了一些有用的方法:
beginTask(String taskName, int numberOfStepsInTask) 指明一個任務正在啟動中,它提供要顯示的名稱以及用於進度欄的期望步驟數 worked(int numberOfStepsCompleted) 通過提供步驟數來遞增進度欄 done() 指明任務已完成
完成測試
測試是通過調用 testComplete(WMQTestResult[]) 並向其傳遞一組測試結果對象來完成的。正如前面所示的,testComplete 方法需要啟動測試運行的測試引擎的一個句柄,如果在調用 testComplete 之前沒有先調用 runTest 的缺省實現,則該方法無法工作。
除了在測試運行期間使用前面提到的 returnResult 來返回測試結果外,您還可以在測試完成時使用此方法來返回結果,或者將其作為前者的替代方法。然而,任何結果返回兩次都會顯示兩次。
即使測試使用 WMQTestEngine 方法 returnResult 來返回其所有結果,它仍然必須在完成時調用 testComplete 才能完成測試過程。如果沒有其他結果要返回,則可以在 testComplete 方法中提供 WMQTestResult 對象的空數組。
取消處理
用戶可以在測試運行時取消單個測試,或者取消整個測試運行。可以使用方法 isCancelled() 來檢查是否應該停止一個測試。好的測試應該定期進行檢查,查看是否應該將其取消以避免不必要地延遲用戶。
如果您試圖取消一個測試,但該測試在一定時間內返回失敗,則測試引擎會通過終止運行測試的線程來強制停止該測試。但是不要依賴於此方法——更好的方法是按時返回測試,使它能夠清除任何資源並返回生成的任何測試結果。
報告錯誤
測試運行過程中遇到的錯誤可以如下進行報告:
Status internal_error = new Status(IStatus.ERROR,
"com.ibm.mq.explorer.healthcheck.coretests",
0,
"Error encountered while doing something",
event.getException());
HealthcheckPlugin.getPlugin().getLog().log(internal_error);
錯誤將被寫入 Eclipse Errors View 中,包括在 Java 異常中包含的棧跟蹤(如果提供)。運行測試導致引發的未捕獲異常和錯誤將被 Healthcheck 測試引擎捕獲並按照這種方式寫入 Errors View 中。因此,在開發新測試時最好定期檢查 Errors View。
用戶首選項
測試應該符合使用 Eclipse Preferences 對話框提供的用戶首選項。使用以下方法來訪問首選項:
首選項 如果出現下列情況則返回 TRUE 如果出現下列情況則返回 FALSE PreferenceStoreManager.getIncludeHiddenQmgrsPreference() 應該在測試中包含對 WebSphere MQ Explorer 隱藏的隊列管理器 應該在測試中排除對 WebSphere MQ Explorer 隱藏的隊列管理器 PreferenceStoreManager.getIncludeSysObjsPreference() 系統對象(名稱以 SYSTEM 開頭的對象)應該包含在測試中 系統對象(名稱以 SYSTEM 開頭的對象)應該從測試中排除復雜測試
測試結構
正如前面提到的,WMQTest 方法 runTest 定義了測試的主體,並且可以調用該方法來啟動測試運行。
runTest 方法結束並不意味著測試結束(需要使用 testComplete 來顯式指明),測試開發人員可以隨意使用異步方法實現測試以獲取要分析的數據。
例如,runTest 可以提交獲取 WebSphere MQ 對象的有關數據的請求。測試執行可以通過接收回應的 listener 方法繼續。這樣基本上可以使測試等待數據,而不需要由開發人員實現線程等待。下面的偽代碼示例演示了如何實現這種方法:
package com.ibm.mq.explorer.healthcheck.samples;
import java.util.ArrayList;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IProgressMonitor;
import com.ibm.mq.explorer.healthcheck.HealthcheckPlugin;
import com.ibm.mq.explorer.healthcheck.PreferenceStoreManager;
import com.ibm.mq.explorer.healthcheck.actions.WMQTestEngine;
import com.ibm.mq.explorer.healthcheck.objects.WMQTestResult;
import com.ibm.mq.pcf.CMQC;
/**
* Pseudo-code sample demonstrating an asynchronous approach to implementing a
* Healthcheck test.
*
* @author Dale Lane
*/
public class QueuesTest extends WMQTest implements SomeListener {
/** Used to store test results. */
private ArrayList testresults = new ArrayList();
/**
* Used to start the test.
*
* @param callback handle to the test engine running the test
* @param guimonitor handle to the object monitoring the test,
* provided to allow the test to periodically check
* if the user has tried to cancel the test running
*/
public void runTest(WMQTestEngine callback, IProgressMonitor guimonitor) {
super.runTest(callback, guimonitor);
// reset all test stores
testresults = new ArrayList();
// initialise the progress bar part of the GUI used to show progress of
// this test
guimonitor.beginTask(getTestName(), numqmgrs);
// start the test!
// send query
PseudoQueueManager qmgrHandle = pseudoGetQueueManager();
submitQmgrQuery(qmgrHandle, this, query);
// note that the runTest method is now finished, but the test is not over!
}
/**
* Used to process results received in response to query submitted by runTest.
*
* @param objects data received
*/
public void dataReponseReceived(ArrayList objects) {
// analyse each of the replies in the collection received in the reply
for ( int i = 0; i < objects.size(); i++ ) {
PseudoQueue nxtQueue = (PseudoQueue) objects.get(i);
analyseQueue(nxtQueue);
// increment GUI progress bar used to show progress of this test
getGUIMonitor().worked(1);
}
// now that we have got the data that we were waiting for, and have
// finished processing it, the test has really finished - we are
// nearly ready to call testComplete to mark the test finished
// return the completed results
WMQTestResult[] finalresults =
(WMQTestResult[]) testresults.toArray(new WMQTestResult[0]);
testComplete(finalresults);
}
/**
* Analyse the given queue. If any potential problems are found, a problem
* marker is added to the testresults collection.
*
* @param queue queue to analyse
*/
private void analyseQueue(PseudoQueue queue) {
// do something
// add a problem marker to the collection
if (problemFound) {
testresults.add(new WMQTestResult(IMarker.SEVERITY_WARNING,
"A problem was found with "
+ queueName,
getQueueManagerName(queue),
"Queues"));
}
}
}
如果測試需要手動等待/睡眠,則當想要使用 Java wait/notify 方法時,可以使用測試對象的對象監視器。Healthcheck 測試引擎的線程沒有使用各個測試對象的對象監視器來實現。
結束語
本文向您介紹如何通過用 Java 編寫 Eclipse 插件來擴展 WebSphere MQ Explorer 的功能。文中描述了編寫擴展功能的步驟,該擴展功能使 WebSphere MQ Explorer 能夠使用預定義的前綴集來驗證 MQ 對象的名稱。
文中描述的整個 Eclipse 項目可以通過下面的鏈接下載,並將其作為開發自己的自定義測試的起點。請將該文件解壓縮,並通過選擇 Import Existing Project into Workspace 來將其內容導入到 Package Explorer 中,以代替文中描述的創建新項目。