正如我在兩部分系列的 第一部分所討論的,Java 平台金融服務的擴展(J/XFS)是一個國際標准,它可用於為表示一塊銀行業硬件的眾多組件定義一個清楚的接口。這些組件被稱為 設備服務,並可以插入 J/XFS 系統。以 J/XFS 內核表示的 J/XFS 環境將設備服務作為獨立的、內部可變的部分來對待。
在本文中,您將學到在 J/XFS 下開發銀行業的設備服務的關鍵部分。到討論結束時,您將會理解:
在 J/XFS 下開發設備服務的基本概念和要求
參考實現(面向 J/XFS 的金融設備接口)軟件包和文檔是如何安排的
在開發來自 Java 平台的設備服務時,FDI for J/XFS 可以如何為您提供支持
如果您還沒有看過這個系列的第一篇文章,我建議您在開始讀本文前先去讀一下第一篇文章。
開發設備服務:基本概念
J/XFS 中的設備服務是控制特定的硬件設備的 Java 對象。應用程序不是直接的將消息發送到設備服務對象。取而代之,它們將操作請求消息發送到 J/XFS 內核,內核確保消息依次到達目的地。從圖 1 中您可以看到,通常都是由內核來調用設備服務對象上的方法的。
圖 1. J/XFS 設備服務消息流:從應用程序到硬件
響應發送回應用程序的方式也是一樣的。設備服務對象從不把消息直接發送給應用程序。取而代之的是設備服務對象將消息發送給內核,然後由內核將消息發送給適當的接收器。圖 2 說明了設備服務是如何向應用程序報告硬件已經改變了狀態的。
圖 2. J/XFS 設備服務消息流:從硬件到應用程序
這個系統可以很好的服務於 J/XFS 設備服務開發者。因為通常設備服務對象都是與 J/XFS 內核通信的,您所要做的全部事情就是遵照一些基本概念並實現恰當的設備服務接口。在下面的幾節中,我將概述在 J/XFS 下開發設備服務時所必須理解和遵照的基本概念。
J/XFS 設備服務接口
J/XFS 接口由兩部分構成。第一部分定義了所有的設備服務共有的基本行為;第 2 部分是一個特定於每種類型的設備服務的 Java 接口的集合。每個設備服務都根據類型來分組的,並且已經為每種類型的設備服務定義好了一個接口集合。在每個集合中都有一個或多個特定於每個設備服務的接口。設備服務僅實現那些符合它們的規范的接口。例如,一個用於 ATM 的設備服務不會去實現存折打印機的接口,因為這兩個服務沒有被分組在同一類型中。
J/XFS 設備服務封裝了特定設備邏輯和行為,實現方法是對 J/XFS 環境隱藏所有的設備特性,僅使其可見由 J/XFS 標准定義的操作。
回調注冊和反注冊
應用程序通過向 J/XFS 內核發送相應的消息來表明它們願意與某個設備服務通信。內核通過注冊一個帶有設備服務對象的回調對象來對這個請求做出響應。設備服務為每一個回調對象分配一個唯一的標識數字。然後內核為所有來自該應用程序的請求都添加上這個標識(ID)。該標識數字被稱為 控制 ID;每個設備服務都有唯一的控制 ID。
進來的操作請求消息(消息請求您的設備服務器執行一個操作)就是用這個 ID 來區分的。這要求您記住控制 ID 和事件回調對象間的關聯。
這些回調對象是設備服務對象所通信的 J/XFS 內核的一部分。它們的唯一目的就是使您能發送事件來報告當前所執行的操作的進展和結果。一旦應用程序不再需要您的設備服務,它通知 J/XFS 內核反注冊它的回調對象。
操作的執行和取消
幾乎所有的在 J/XFS 設備服務上執行的操作都是以異步的方式執行的。當您的設備服務接收到需要在該設備上執行某一操作的請求時,必須接受該請求,並為其分配一個唯一的標識數字。該 ID 數字(被稱為 標識 ID)然後被發送到請求者,所請求的操作在一個單獨的線程中被執行。
將控制 ID 和標識 ID 區分開是很重要的。標識 ID 唯一的命名了應用程序在硬件上執行一個操作的單一請求。 例如,如果一個應用程序需要在打印設備上打印一些信息並把打印出的那張紙吐出來,那麼它需要通過內核向設備服務發送兩個請求消息,一個用於打印,一個用於吐紙。每個請求都通過設備服務分配給它的標識 ID 來區分。相反,控制 ID 將唯一的命名產生請求的應用程序。
一個操作一結束,就會通過發送一個操作完成事件來將結果報告回來,操作完成事件包含操作結果和以前分配的 ID。如果設備服務在忙於執行前面接收到的操作請求時又收到了多個操作請求,每個請求都被放在隊列中並且會按照到達的順序被執行。這條規則的極少的特例在 J/XFS 規范中有清楚的描述(請參閱 參考資料)。
如果操作請求被取消,請求的應用程序將向 J/XFS 內核發送一個請求來取消這個操作。然後內核向設備服務傳送包含取消請求和被取消的操作的標識 ID 的消息。設備服務必須有一個機制,這個機制可以盡量的停止執行操作並把設備設為操作開始前的狀態,盡管這並不總是可以實現的。
狀態管理
設備服務在運行時會呈現不同的狀態。 大多數狀態間的轉換在相應的事件中會被報告給單獨的或是所有的回調對象。在任何時候 J/XFS 內核都可以向設備服務發送消息請求它當前的狀態。
打開和關閉設備服務
在應用程序建立了它自身、J/XFS 和 設備服務間的通信基礎架構後,應用程序就已經准備好與設備服務一起工作了。但在它可以請求任何相關設備的操作之前,它必須通過請求內核打開設備服務的方式來正式的表達它要這樣做的意圖。在這一請求中內嵌了唯一的控制 ID。內核向設備服務發送一個請求為了操作而打開的消息。如果連接的硬件是可操作的,就通過發送一個相應的 操作完成事件來回答該請求。在這一點,設備服務對象的狀態改變了;現在它“打開”來接收相關設備的操作請求。
應用程序一完成與設備服務的工作,並且在它請求內核反注冊它的回調對象之前,它必須請求內核發送一個消息到設備服務,該消息包含為那個控制 ID 正式關閉設備服務的請求。此後,設備服務就不能再接受任何其它的關於該控制 ID 的相關設備的請求消息。
排它的訪問請求
如你到目前為止所看到的,很多應用程序都可以請求內核為它們注冊回調對象。操作請求可以以任何可能的順序到達設備服務。多數情況下,按照接收的順序來執行操作請求。
但有時候,一個應用程序必須確保它的請求在被執行時不受其它應用程序的干擾。在這種情況下,應用程序將通過 J/XFS 內核向設備服務發送一個要求排它訪問的請求。設備服務必須有一種機制來管理來自內核的排它訪問的請求。它必須能夠確保在給定的一段時間中僅有一個以控制 ID 來標識的應用程序被授權了排它訪問的權限。一旦設備服務成功的將排它訪問和控制 ID 關聯起來,僅有控制 ID 所標識的操作請求消息可以被執行。所有的其它請求都被放在隊列中。
在請求排它訪問的任務完成後,內核代表應用程序發送一個請求除去排它訪問狀態的消息。
設備服務 API
既然已經對在 J/XFS 下開發設備服務的基本要求有了些認識,我們再來熟悉一下 API 規范。這一節 首先來關注一下 API 的實用編程技巧。所有的說明指的是標准版本 1.0 和它所伴有的內核實現。在 FDI for J/XFS 這節中有對軟件包層次結構的解釋。
狀態管理
如我們前面所討論的,設備服務對象在它的整個生命周期中呈現出不同的狀態。所有可能的狀態在所謂的狀態類中都有規范進行定義。
JxfsStatus 類將每個設備服務可能呈現的布爾狀態也歸組進來。狀態如下:
打開(Open):設備已經為應用程序打開。
聲明(Claimed):對此設備服務對象的排它訪問已經授權給一個應用程序。
聲明暫掛(Claim pending):至少有一個應用程序請求對設備服務對象進行排它訪問,但排它訪問還沒有被授權。
忙(Busy):設備服務對象當前正在處理一個操作。其後的操作請求將被放在隊列中。
硬件錯誤(Hardware error):設備服務正在控制的硬件指出出現了一個只有服務工作人員才可以修復的錯誤。
用戶行為錯誤(User action error):設備服務正在控制的硬件指出出現了一個可以由系統管理員來解決的錯誤。
工作中(Working):設備服務為應用程序而打開了,並且沒有出現錯誤。
節能(Power save):硬件處於低能量消耗狀態(less-power-consuming)時就要恢復可用性。
您需要注意設備服務對象所控制的硬件的情況(硬件所提供的所有信息)。在任何時間都必須可以從設備服務對象得到狀態信息。大多數狀態是彼此獨立的,但也存在一些依賴。例如,設備服務對象一定要在被授權排它訪問之前開放。狀態間相互依賴以至於在 JxfsStatus 實例中的信息總是前後一致的,為了這些狀態就必須使用某些種類的同步。
一些設備類型規范定義了 JxfsStatus 的子類來包入甚至更多的狀態信息。例如,打印機設備的規范定義了 JxfsStatus 的子類: JxfsPtrStatus 類的子類,它可以提供額外的關於打印機調色劑和供紙單元的狀態信息。
一些設備規范所使用的有兩個更普遍的狀態類: JxfsMediaStatus 收集了硬件單元在處理的介質時可能呈現的狀態。例如,在打印機中,介質將是“紙”,紙張供應單元可能呈現的一種狀態是“卡紙”。另一個類是 JxfsThresholdStatus ,用於監測可測量單元的級別。例如,在打印機中的供紙情況可以是“滿”、“高”、“低”或者“空”。請參見 J/XFS 規范以對狀態管理類有更多的了解。
事件
事件是實現設備服務發送信息給應用程序從而向 J/XFS 內核傳遞信息的唯一途徑,這樣,就很有必要理解事件是怎樣工作的。J/XFS 把事件分為三類: 操作完成事件、中間事件和 狀態事件。這些分別表示為 OperationCompleteEvent 類、IntermediateEvent 類和 StatusEvent 類。
所有的事件為 J/XFS 內核標識事件源(設備服務對象)。這一引用必須作為第一個參數給予所有的事件類型。J/XFS 設備服務的每個異步的操作導致一個 操作完成事件,該事件報告操作的結果。一些特殊設備的操作使用操作完成事件的子類,但不幸的是大多數的設備規范的設計者並沒有利用它們。規范為每個操作定義了表示為整數常量的可能結果。另外,為每個操作定義了表示為整數常量的一個 操作標識,以免應用程序記不起它所調用的操作。
中間事件在操作執行時報告操作的進展,其報告的方式與操作完成事件報告結果的方式相同。象上面描述的,當設備服務呈現一個新的狀態時, 狀態事件就會被發送。不是所有的狀態改變都作為狀態事件而被報告。設備服務的新狀態是用一個整數常量來描述的。例如,如果一個打印機沒有紙了,這一事實是通過狀態事件來告之應用程序的。
異常
異常機制是 J/XFS 的一個薄弱點,因為僅有一種異常類型: JxfsException 。異常被拋出的原因不是由於它的類型定義部分,而是用一個在接口 JxfsConst 中定義的整數常量來表示的。清單 1 說明了一個所請求的操作不能被支持時被拋出的異常。
清單 1. JxfsException
/* ... */
throw new JxfsException(JxfsConst.JXFS_E_NOT_SUPPORTED);
/* ... */
基本的服務操作
所有的設備服務都要求支持一個主要的接口: IJxfsBaseService 。它聲明了所有類型的設備服務共同的所有的方法。在接下來的幾節中我們將來研究每個基本的服務方法。
初始化消息
當 J/XFS 內核啟動設備服務時,J/XFS 向設備服務發送一個初始化消息,該消息包含了一個 JxfsLocalDeviceInformation 類型的對象。這個對象攜帶著關於設備服務和它所附著的 J/XFS 客戶機的一般信息。它為設備服務提供對在 J/XFS 服務器上的虛擬空間的訪問,這一點與那些信息至少是一樣重要的。任何持久的數據都可以存儲在 J/XFS 服務器上,這就提供了一個存儲配置信息的好地方。 初始化消息一到,設備服務就第一次與真正的硬件設備聯系。
設備關閉在 J/XFS 客戶機關閉過程中,J/XFS 內核向所有的設備服務發送一個關閉消息,如清單 2 所示。這是清理也可能是關閉硬件的好時機。
清單 2. 設備關閉消息
public void initialize(JxfsLocalDeviceInformation deviceInformation)
throws JxfsException
public void shutdown() throws JxfsException
回調對象和控制 ID
J/XFS 內核向設備服務發送一個包含 IJxfsEventNotification 類型的回調對象的消息。設備服務用這個回調對象來向內核發回事件消息。為每個需要與設備服務交互的應用程序發送這種類型的對象。如清單 3 所示,為對象分配一個控制 ID 並返回該控制 ID。
清單 3. 分配一個控制 ID
public int registerControl(String deviceType, IJxfsEventNotification
callback) throws JxfsException
public int deregisterControl(int controlID) throws JxfsException
一旦內核除去了回調對象,就不能再用該回調對象了。
參數 deviceType
參數 deviceType 包含了設備的類型(假使設備服務支持不止一種的類型),但這是高級的設備服務開發,所以這裡我們就不深入了。(詳見規范)
“打開(open)” 消息
J/XFS 內核發送的消息 open 通知設備服務:很可能操作請求將在給定的控制 ID 後面傳入。 參數 controlID 一定要是在一個 IJxfsEventNotification 的實例的 registerControl 方法中分配的一個有效的控制 ID,從而設備服務可以將操作結果報告回來。清單 4 給出了方法的用法:必須在設備服務中實現它以便接收來自內核的 open 消息。
清單 4. 內核為進來的請求准備了設備服務。
public int open(int controlID) throws JxfsException
“關閉(close)” 消息
在內核發送 deregisterControl 到設備服務前(因為 open 請求的一個 IJxfsEventNotification 實例已經被成功地處理了),內核必須發送一個 close 消息以表明沒有需要那個控制 ID 的操作請求了,如清單 5 所示。
清單 5. 內核表示不再需要設備服務。
public int close(int controlID) throws JxfsException
方法的聲明(claim)和發布(release)
為了獲得或返回對設備服務的排它訪問, claim 和 release 消息被發送到設備服務。 這些方法是少數的在 J/XFS 中不遵守異步操作的規則的方法中的兩個方法。直到排它訪問被成功的授權或是在參數 timeout 給定的時間裡返回了,方法的調用才返回值,如清單 6 所示。
清單 6. 聲明和發布排它訪問
public boolean claim(int timeout, int controlID) throws JxfsException
public boolean release(int timeout, int controlID) throws JxfsException
當然,排它訪問必須在可被返回前授權,並且消息 open 必須在一個 claim 請求前被發送到設備服務而且被成功的處理了。
取消(cancel)請求
內核發送消息 cancel 到設備服務(如果操作是以 identificationID 來標識的話),由回調控制根據 controlID 來啟動的操作就要被停止。如果可能的話,設備服務將把硬件置回操作開始之前的狀態。取消請求的控制 ID 必須與要取消的操作的控制 ID 相同。沒有標識 ID 分配給 cancel 請求,這就意味著 cancel 請求是不能被取消的(這有些不可思議吧)。清單 7 表示了一個取消(cancel)請求。
清單 7. 一個取消(cancel)請求
public void cancel(int identificationID, int controlID) throws JxfsException
getStatus 操作
getStatus 操作是非常重要的,因為它把設備的當前狀態通知 J/XFS 系統中所有相關的對象。如清單 8 所示,方法返回一個 JxfsStatus 的實例,因此這個方法是在 J/XFS 設備服務中異步處理規則的另一個例外。
清單 8. getStatus 操作
public JxfsStatus getStatus(int controlID) throws JxfsException
關於該方法您需要理解兩點。如前面所概述的, JxfsStatus 和它的子類包含關於一些不同狀態的信息。 第一點要求是相互依賴的狀態必須一直前後一致。例如,狀態“claimed”依賴狀態“open”:設備服務必須在被聲明前打開。當收集狀態信息供給 JxfsStatus 的一個新的實例時,必須同步的訪問那些狀態。
第二點與 JxfsStatus 類的設計有關。 JxfsStatus 的實例是值對象,這意味著值對象的唯一作用是攜帶不提供任何邏輯的信息。這些對象的內容可以被任何其他的對其引用的對象更改。結果,設備服務必須為 getStatus 方法的每一個調用返回一個新的 JxfsStatus 實例,從而確保設備服務擁有一個對對象的引用,而其他對象都不能更改它的內容。
getStatus 操作的簡單易懂的實現與清單 9 很相似。假定設備服務有一個內部的監視對象來同步訪問方法 getStateMonitor() 返回的所有的狀態信息。每個狀態可以被相應的方法(例如, isClosed() )查詢。實現必須確保當任何對象鎖定了由 getStateMonitor() 返回的對象時,狀態信息不可改變。所以,您必須檢查設備服務是處於“打開”狀態,並且如果不是的話就拋出定義的異常。請閱讀關於每個方法的 J/XFS 規范來找出您必須檢查什麼條件。然後,創建一個新的 JxfsStatus 實例,設置所有的狀態信息,並返回給訪問者。
清單 9. getStatus 的實現
public JxfsStatus getStatus(int controlID) throws JxfsException
{
synchronized (getStateMonitor())
{
if (isClosed())
throw new JxfsException(JxfsConst.JXFS_E_CLOSED,
"The device service is in state 'closed'.");
final JxfsStatus state = new JxfsStatus();
state.setBusy(isBusy());
state.setClaimed(isClaimed());
state.setClaimPending(isClaimPending());
state.setHardwareError(isHardwareError());
state.setOpen(isOpen());
state.setPowerSave(isPowerSave());
state.setUserActionError(isUserActionError());
return state;
}
}
設備服務信息
設備服務必須提供一些自身的版本信息和所控制硬件的描述。 getDeviceServiceVersion 操作在 JxfsVersion 的一個實例中提供當前安裝的設備服務的版本。
清單 10 中所示的其他兩個方法返回了與設備服務相連的硬件的類型和硬件的更詳盡的描述。如果設備服務支持多種機器(例如相同類型的不同型號),這裡設備服務應該給出實際上的配置。
清單 10. 獲得關於設備服務的信息的三個操作
public JxfsVersion getDeviceServiceVersion(int controlID) throws JxfsException
public String getPhysicalDeviceName(int controlID) throws JxfsException
public String getPhysicalDeviceDescription(int controlID) throws JxfsException
固件管理支持
J/XFS 提供有限的固件管理支持。在 getDeviceFirmwareVersion 操作中,如清單 11 所示,設備服務返回 JxfsVersion 的一個實例來說明當前安裝的硬件的版本。
另外,可以在 J/XFS 服務器上永久的存儲固件。 getRepositoryFirmwareVersion 的結果是 J/XFS 服務器的對象庫中的可用固件的版本。設備服務可以通過發送消息 getValueForKey 和 setValueForKey 到 JxfsLocalDeviceInformation 實例來讀出和寫入 J/XFS 服務器,該實例是設備服務在 initialize 方法中接收的。
如果設備服務不支持固件管理,設備服務一定要拋出 JxfsException 異常,錯誤代碼是 JxfsConst.JXFS_E_NOT_SUPPORTED 。
getFirmwareStatus 操作比較這兩個版本並且以一個整數常量來報告哪一個比較新和硬件的固件的更新是否可能使用 J/XFS 服務器上的那個版本。如果設備服務不支持固件的更新,設備服務必須返回 JxfsConst.NO_SUPPORT 。
如果選擇為設備服務的用戶提供固件更新的方便,實際的更新就在 updateFirmware 方法中處理。注意盡管這個操作不返回標識 ID ,它仍然是異步的。因為 J/XFS 服務器可被 J/XFS 環境中的許多對象使用,所以需要清楚的用文檔說明為了固件管理在 J/XFS 服務器上使用了哪些密鑰,以使數據不會被意外的重寫。
清單 11 表示了 J/XFS 中與固件管理相關的四個方法。如果想讓應用程序在與設備服務的結合體中使用 J/XFS 固件管理特性,就需要實現這些方法。
清單 11. 與固件管理相關的方法
public JxfsVersion getDeviceFirmwareVersion(int controlID) throws JxfsException
public JxfsVersion getRepositoryFirmwareVersion(int controlID) throws
JxfsException
public int getFirmwareStatus(int controlID) throws JxfsException
public boolean updateFirmware(int controlID) throws JxfsException
節能模式
如果硬件支持操作方式消耗較少的能量,那麼通過在 isPowerSaveModeSupported 方法中返回 true 來表明這一點。處於這種方式是設備服務在 JxfsStatus 實例中報告的狀態之一,象前面所說的,狀態可以通過發送 getStatus 消息到設備服務來獲得。
為了把硬件置回完全操作的方式,J/XFS 內核發送 wakeUpFromPowerSave 消息到設備服務,如清單 12 所示。
清單 12. 設置節能模式
public boolean isPowerSaveModeSupported(int controlID) throws JxfsException
public int wakeUpFromPowerSave(int controlID) throws JxfsException
處理一個丟失的連接
假使與一個回調對象的連接由於某種原因而丟失了,J/XFS 內核就發送給設備服務一個包含回調對象的控制 ID 的消息。一收到那個消息,設備服務必須能夠除去對給定的控制 ID 的排它訪問,把對於那個 ID 的狀態設為“關閉”,並且反注冊回調對象。清單 13 表示了連接失敗消息。
清單 13. 連接失敗消息
public void connectionFailure(int controlID)
directIO 操作
directIO() 操作是 IJxfsBaseService 接口中唯一使用硬件的操作功能的操作。但與其他的在特定設備 J/XFS 接口中定義的操作相比它也是一個例外。如果硬件(您正為其開發設備服務)提供沒有被包含在 J/XFS 標准中的功能,您可以使用這個操作包含被請求的信息。
從選擇一個比 JxfsConst.JXFSDIRECTIO_OFFSET 大的整數值開始來標識特定硬件的功能。設備服務在硬件上執行必要步驟所需的所有信息一定要隱藏在一個 JxfsType 類型的對象中。子類 JxfsType 創建一個新的類來包含設備服務所需的所有信息。
理想情況,您決不需要支持 directIO 。因為使用 directIO 的代碼還沒有被標准化,所以如果要使用該代碼就要損失可移植性。在多數情況下,您應該通過拋出 JxfsException 異常(錯誤代碼 JxfsConst.JXFS_E_NOT_SUPPORTED )來實現 directIO ,如清單 14 所示。
清單 14.directIO 的典型實現
public int directIO(int command, JxfsType serializable, int
controlID) throws JxfsException
{
throw new JxfsException(JxfsConst.JXFS_E_NOT_SUPPORTED);
}
]
特定設備操作
獨立的 Java 接口用於聲明 J/XFS 所支持的不同的硬件類型的功能。每種類型的硬件至少有一個接口。如果您想為給定的硬件類型建一個新的設備服務,您只需在實現上面所概述的 IJxfsBaseService 時同時實現針對於那種類型的硬件的適當的接口即可。
如果您不想支持在接口定義中所描述的某一特殊函數,在多數情況下,您可以通過拋出 JxfsException 異常(錯誤代碼是 JxfsConst.JXFS_E_NOT_SUPPORTED )來表明這一點。
例如,描述打印機功能的接口之一是 IJxfsPrinterService 。它與其它的接口都包含的操作之一是用於復位打印機硬件的 resetPrinter 操作。如果您要寫一個提供可復位硬件的打印機設備服務,那麼您就要寫一個新的類來實現 IJxfsBaseService 和 IJxfsPrinterService ,並把復位硬件的必要代碼放在 resetPrinter 方法中。
FDI for J/XFS
面向 J/XFS 的金融設備接口是 J/XFS 內核的實現。您可以從 J/XFS 論壇主頁上免費下載該接口(請參閱 參考資料)。除了實現標准的規范以外,FDI for J/XFS 還包括許多旨在方便在 J/XFS 環境中的軟件開發的有用的條款。我們將在接下來的幾節中研究這份文檔。
文檔
在包含 FDI for J/XFS 的 ZIP 壓縮文檔中,您將看到描述框架的信息的五種來源:
對於開發者來說也許最重要的進入點是 HTML 格式的完整的 API 文檔。標准中所沒有涵蓋的每個細節在該文檔中都可以找到。
對於想要成為設備服務開發者的人來說第二個最重要的文檔是 《Device Service Programming Guide》。它包含了幾乎與本文相同的主題,然而本文中還提供了一些那份文檔中所沒有的信息。
如果您想熟悉 FDI for J/XFS 的全部概念,請參閱 《System Overview》。當然,也許您想看看 這個系列的第一篇文章。
FDI for J/XFS 的安裝和配置在 《Administration Guide》中介紹。
《Application Programming Guide》沒有包含很多的用於開發設備服務的有用的信息。
數據包概述
與設備服務開發相關的數據包層次結構如下:
com.jxfs.control.cdr
com.jxfs.control.msd
com.jxfs.control.pin
com.jxfs.control.ptr
com.jxfs.control.tio
設備操作所需的所有的類都在與這些數據包一起的 J/XFS 標准中定義。下面的是一些附加的數據包:
com.jxfs.events 數據包包含了所有的 J/XFS 事件類,當然差勁的 JxfsException 類也在其中。
com.jxfs.forum.support 數據包包含用於提供方便的額外的輔助類。
com.jxfs.general 數據包將 J/XFS 的核心的類和接口分組。包括
JxfsConst
JxfsLocalDeviceInformation
JxfsMediaStatus
JxfsStatus
JxfsThresholdStatus
JxfsType
JxfsVersion
com.jxfs.service 數據包很重要。它包含 IJxfsBaseService 接口和所有的設備服務接口。
下面的數據包為每種 J/XFS 所支持的設備類型包含一個抽象的超類:
com.jxfs.service.alm
com.jxfs.service.cdr
com.jxfs.service.msd
com.jxfs.service.pin
com.jxfs.service.ptr
com.jxfs.service.tio
日志和跟蹤支持
J/XFS 定義了內置的日志和跟蹤支持。當涉及到跟蹤代碼,尤其是一旦對於產品時,這就會很方便。發送所有的日志和跟蹤信息給核心的 JxfsLogger 類型的對象,通過調用類的 getReference 方法來獲得對對象的引用。
日志和跟蹤入口是用唯一的 origin字符串來標識的。選擇日志和跟蹤信息所需的所有 origin(確信您可以在生成的日志和跟蹤文件中容易的識別出每個 origin)。在可以使用日志和跟蹤工具前,必須通過發送 registerModule 消息給 JxfsLogger 對象,讓該對象知道 origin 的存在。在停止對一個給定的 origin 進行日志和跟蹤前,不要忘記用 deregisterModule 消息反注冊。
可以用不同的級別來按優先順序處理跟蹤入口。100 以下的整數值是為 J/XFS 內核保留的,但可以用所有的比 100 大的值。
日志信息隨 writeErrorLog 消息被發送到日志記錄器(logger)。需要為每個日志入口提供日志模塊的 origin 字符串、錯誤代碼以及擴展的錯誤代碼。除了日志字符串外,您還可以提供關於如何解決通到日志入口的問題的附加信息和一個可以檢索到附加信息的 URL。
writeLog 消息發送跟蹤信息給日志記錄器(logger)。因為跟蹤應該是被廣泛使用的,但是通常在運行時是禁用的,所以跟蹤字符串的准備在計算能力方面就很昂貴了。節約計算能力還有找出對 origin 和級別的跟蹤是否已被激活的一種方式是發送 isLogActive 消息給 J/XFS 日志記錄器(logger)對象。
日志和跟蹤消息都包含對入口生成的對象的一個引用。對於設備服務,這是個對設備服務對象的引用。清單 15 說明了 J/XFS 的日志性能是如何被使用的。
清單 15. 設備服務類的實現
// ...
final String origin = "developerWorksDeviceService";
JxfsLogger.getReference().registerModule(origin,
"J/XFS device service for IBM developerWorks.");
// ...
// log
JxfsLogger.getReference().writeErrorLog(this, origin, 0 /* error code */,
0 /* extended error code */,
"This is an error log entry.",
"Hint to solve the problem.",
"Find more information at http://www.ibm.com/java.");
// ...
// trace
if (JxfsLogger.getReference().isLogActive(origin, 101))
JxfsLogger.getReference().writeLog(this, origin, 101, "J/XFS
trace entry.");
// ...
JxfsLogger.getReference().deregisterModule(origin);
// ...
接口和抽象類
J/XFS 在標准的規范文檔中定義了設備接口。但對於現實的編程需要可以在代碼中使用的 Java 類文件。FDI for J/XFS 產生必要的類。
除接口外,FDI for J/XFS 為 J/XFS 詳細說明的每種設備類型提供抽象超類。您最好把抽象類建立適當的子類,從而適應設備服務的實現。這可以確保如果一個設備規范被擴展了,那麼相應的方法會被包含進內核的一個新版本中。方法然後就可以在那些類中以這樣的方式來實現:它們僅拋出 JxfsException 異常,出錯代碼是 JXFS_E_NOT_SUPPORTED 。
把根據舊的規范開發的抽象類上建立子類的設備服務繼承了附加的方法而且繼續與新版本的內核一起工作。對新性能的支持可以通過重寫繼承方法簡便的加到設備服務上。
清單 16,作為一個示例說明了用於日志打印機的設備服務類。這個類用了抽象超類 com.jxfs.service.ptr.AJxfsJournalPrinterService 。
清單 16. 設備服務類的實現
import com.jxfs.service.*;
import com.jxfs.service.ptr.*;
// ... import any packages needed
public class DeveloperWorksJournalPrinter extends AJxfsJournalPrinterService
implements IJxfsBaseService, IJxfsPrinterService
{
// implementation of the device service ...
}
支持類
FDI for J/XFS 為設備服務的開發提供為數不多的類。這些類分組在數據包 com.jxfs.forum.support 中。
最重要的支持類是 QueueControl 。該類定義了一個隊列,你可以使用該隊列來實現設備服務中的操作請求的異步執行。思路是把所有的代碼為一個設備操作而分解成一個獨立的類。這樣的類實現 IJxfsServiceJob 接口,因為這些“作業”對象可被加到隊列控制對象。隊列控制對象可被用在主動方式或被動方式中。不同之處是主動方式中隊列控制使用它自己的控制線程來連續的執行隊列中的作業,但在被動方式中您需自己創建一個控制線程並發送 getNextJob 消息給隊列控制對象,從而獲得並執行隊列中的下一個作業。
支持數據包還包括操作請求的實現,操作請求請求的操作有 open 、close 、claim 和 release ,它們分別在 OpenJob 類、CloseJob 類、ClaimJob 類和 ReleaseJob 類中。請閱讀有關這些類的文檔以了解如何使用它們。
另一個有用的類: IDFactory 。這種類型的對象產生數字 ID,這些數字 ID 有些用於內核在設備服務注冊時區分回調對象(控制 ID),另一些用於標識操作請求(標識 ID)。
總結
我希望這個系列能夠作為 J/XFS 平台和它的參考實現(即 FDI for J/XFS)的一個好的介紹。通常,一旦您理解了設備服務開發中的基本概念,實現它們就不太困難了。借助這個系列,我的目標是准備和鼓勵您開發自己的 J/XFS 設備服務,從而滿足來自銀行業應用供應商的要求並擴展 J/XFS 和 Java 平台的使用。