2015年8月6日 星期四

Custom Component 簡介

Custom Component 簡介

hychen39@gmail.com

Steps to create a custom component[1]:

Step 1: 建立一個javax.faces.component.UIComponent 的子類別。使用 @FacesComponent  annotation 註冊此元件。
Step 2: 若要將元件顯示的工作委由另一個 Render class 處理,則建立一個 javax.faces.render.Renderer 子類別。此為選項步驟。使用 @FacesRenderer annotation 註冊此 Renderer
Step 3: 建立一個 Tag Library Descriptor,宣告使用客製元件時所使用的custom tag。在TLD 檔中宣告客製元件的 namespace, tag name, component type,  attribute (optional)等。使用 @FacesComponent 註冊元件只能宣告元件的 namespace, tag name, component type,不能宣告元件的屬性,元件的屬性需在 TLD 檔中宣告。在 JSF2.2 以後,若使用 @FacesComponent( createTag=true) 時,若不需要標籤屬性可以不要建立 TLD 檔。TLD 檔名稱結尾需為 taglib.xml,檔案必須位置 [context_root]/WEB-INF下。此外,需在 web.xml 註冊此 TLD 檔,註冊的方式為使用 param
>,如下:
<context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/your_tag.taglib.xml</param-value>

param>

Step 4: JSF 頁面中引入客製標籤的 name space 並使用 custom tag.

建立一個javax.faces.component.UIComponent 的子類別。

custom tag 都會對應到一個 UIComponent 的子類別。實務上會建立 javax.faces.component.UIComponentBase 子類別,該子類別已實作 UIComponent class 中的抽象方法。也可以直接建立 UIOutputUIInput、或者 UICommand 子類別,視元件的用途而定。


覆寫 UIComponentBase 的方法

當建立 UIComponentBase 子類別時,還必須覆寫其 getFamily():String 方法,傳回元件所屬的元件族群(Component Family)JSF 會利元件所屬的元件族群及 Renderer type 來選擇適合元件使用的 Render[2]
若要元件本身要負責 Renderer 的工作,則必須負責decode encode 兩個階段的工作。在decode 階段需將請求中的參數取出放到元件的 submittedValue  屬性。接著再進行轉換及驗證的動作,成功後才會放到元件中的 value 屬性中(或稱 Local Value)。在 decode 階段需覆寫以下的方法:
·         decode()
encode 階段,要將元件中的 value 屬性的取出,並輸出成 HTML 元件。此時需覆寫以下三個方法:
·         encodeBegin()
·         encodeChildren()
·         encodeEnd()

委任 Renderer 工作給 javax.faces.render.Renderer class

若客製元件要將 Render 工作,則需將工作委外給 javax.faces.render.Renderer 類別。Renderer 類別的工作內容就是執行 decode encode 兩個階段的工作。

Renderer class 的建立步驟如下:
1.       建立 javax.faces.render.Renderer子類別並覆寫 decode encode 階段會被呼叫的方法,包括:
·         decode()
·         encodeBegin()
·         encodeChildren()
·         encodeEnd()
2.       JSF 中註冊 Renderer
可以使用 @FacesRender annotation 或者在 faces-config.xml [3]中進行註冊

3.       UIComponent 子類別中:
·         覆寫 getFamily():String 方法,傳回的字串需和註冊時使用的 標籤內容一致。
·         設定其 rendererType 屬性,其值需和 Step 2 所註冊的 Readerer Renderer Type 一致。使用 UIComponent setRenderType() 設定 renderType 屬性。或者直接覆寫元件的 getRenderType():String 使其傳回註冊的 Render Type
完成上述設定後,JSF 會自動由 Render Kit 中找到指定的 Family 下的 render type 類別並自動建立物件實體讓我們使用。



Annotation 和其在 faces-config.xml 中的對應的 XML



Tag Library Descriptor


Decoding 階段會做的事及使用到的類別及方法

取得請求的 client id

facesContext.getExternalContext.getRequestParameterMap() 方法取得存放請求參數的Requests Map
取得 Request Map 中的參數requestMap.get(Object Key) 或者 requestMap.containsKey(Object Key):boolean

UIComponent  相關的操作

取得 client id

uIComponent.getClientID(FacesContext) 取得 UIComponent client id (Return a client-side identifier for this component)
例如,下圖中的 UIComponent Client id monthSpinner


取得UIComponent 中的屬性

取得 UIComponent 中的屬性 uIComponent.getAttributes().get(Object Key)
uIComponent.getAttributes() 會傳回存放 attributes map 物件。

設定 UIComponent submittedValue特性及 local value

request 的值存到 UIInput 元件的 submittedValue property,以準備進行 Validation,使用 uIInput.setSubmittedValue() 執行上述的動作[6]。這個動作是發生在 Apply Request Phase。在 Process Validators Phase,若 UIInput 中的 submittedValue 轉換並驗證通過,使用 uIInput.setValue() 將轉換後的值設定到 UIInput 元件的 Local Value 中。

觀察Request Map 中的值如何產生

以下例子說明 Request Map 中的值的產生
當按下 month spinner > 按鈕時,會 submit formForm id spinnerForm。在spinnerForm 中有2 input field,其 id 分別為 spinnerForm:monthSpinner spinnerForm:yearSpinner

參考下圖,當 submit form 時,以下的參數會被提出
1.       #6 spinnerForm = “SpinnerForm
2.       #14 spinnerForm:monthSpinner = “1”
3.       #14 spinnerForm:monthSpinner.more = “>”
4.       #21 spinner:yearSpinner = “2010”

以下是在 Netbeans 中觀察到的 Request Map 中的值。



Encoding 階段會做的事及使用到的類別及方法

取得 Response Writer

需取得 Response Writer 將回應寫到輸出串流傳給 browser。使用 facesContext.getResponseWriter():ResponseWriter 取得 Writer

取得 UIComponent 中的: client ID,  local values attributes


要取得 UIComponent Client ID,使用 uIComponent.getClientID(facesContext):String
取得 UIComponent 中的 Local value,使用 uIComponent.getValue():Object
取得 UIComponent 中的 attribute,使用 uIComponent.getAttributes.get(Object Key):Object

Render a HTML element

要開使輸出 HTML element,使用 responseWriter.startElement(String name, UIComponent Component):void,其中:
·         Name: HTML Tag 的元素
·         Component 是對應到此元素 UIComponent,該元件中的 pass-through attributes 會被直接寫出到 HTML 元素成為該元素的屬性。
當執行 responseWriter.startElement() 後,便可使用 responseWriter. writeAttribute(String name, Object value, String property) 輸出該元素的屬性,其中:
·         name: HTML 元素中的屬性名稱
·         value: HTML 元素中的屬性值
·         property: UIComponent 中對應到此元素的 property 或者 attribute。若沒有則給 null[7]。在 JSF 2.1 版中此參數好像尚未被使用[8]
結束輸出使用 responseWriter.endElement(String name)




[3] 使用faces-config.xml 註冊component Renderer 的方式在 JSF 2.2 版本中好像行不通。
[4] E. Burns & C. Schalk, JavaServer Faces: The Complete References, McGraw Hill, 2010, p309
[5] E. Burns & C. Schalk, JavaServer Faces: The Complete References, McGraw Hill, 2010, p319
[6] https://docs.oracle.com/javaee/6/api/javax/faces/component/UIInput.html

2015年7月28日 星期二

Composite Component 介紹

Composite Component 介紹
hycyeh39@gmail.com

實作步驟:

1. 在 [context_root/resources 下建立 your_directory/your_component.xhtml。(後續使用時的 name space 為 http://java.sun.com/jsf/composite/[your_directory],tag 的名稱為 your_component。

2. 在 your_component.xhtml 中建立複合元件所需要的: 1) interface 及 2) implementation. Your_component.xhtml 中仍要有 及 。

3. 使用 來宣告複合元件要使用的: attributes, attachable converters, attachable validators。

3(a) 宣告屬性的名字及是否為必要。 的使用參考http://docs.oracle.com/javaee/6/tutorial/doc/gkhwv.html

3(b) 宣要可附加 converter 及 validator 的 UI元件。target 屬性指向在 中要套用的 UI 元件的名稱;name 為在使用複合元件時converter/validator 標籤要附加時的接口介面。

3(c) 另外還可使用 開放 中的元件,讓使用者附加 converter 至該元件。

3(d) 使用 開放 中的元件,該使用者能附加 actionListener 至該元件。

4. 使用 實作複合元件。在 可以放入多個 UIComponent 元件進行實作。

4(a) 要在元件中使用屬性的值,使用#{cc.attr}。#{cc} 是複合元件中的自動變數(implicit variable),先前在 中定義的屬性可以透過 #{cc.attr.yourAttributeName}取得。

範例說明




 一個 composite component,內有 email 輸入欄位及一個圖示的連結。按下圖示的連結後會驗證 email 格式是否正確,並執行連結指定的方法。

檔案結構


檔案結構如上圖。在[context_root]/resources 下放置複合元件的 xhtml comps/emailBox.xhtml、使用到的 css css/styles.css及圖片檔 images/sendmail.jpg

Composite Component 定義檔 ([context_root]/resources/comps/emaiBox.html)


  • #9 宣告複合元件所需的輸入屬性
  • #10 第一個屬性為 email,是必要的屬性
  • #11 第二個屬性為 image,為圖示連結所要使用到的圖形
  • #12 第三個屬性為 actionMethod,為按下圖示連結後要執行的方法。方法的簽章如 method-signature 屬性中指定,傳回 String,沒有傳入參數。
  • #14 公開位於 #19 Validator Converter 介面
  • #17 Composite Component 實作開始
  • #18 宣告一個 id form
  • #19 宣告一個文字輸入元件  此元件的 value 屬性會 bind 到使用者透過屬性  email 所傳入的 bean property
  • #20 宣告一個 元件,其 action 為使用傳入之方法,方法簽章在#13 已宣告。
  • #21 宣告一個 元件,做為 元件的圖示。該元件的 url 屬性也是由使用者傳入,並透過屬性 image 取得。


使用自訂複合元件


上圖左邊為使用前述複合元件的 index.xhtml 。在 index.xhtml :
  • #7 宣告要引用的複合元件的 name space http://java.sun.com/jsf/composite/comps。注意,url 中的 comps 目錄的實際位置是 [context_root]/resources/comps
  • #11 使用自訂複合元件,該元件有 3 個屬性: email, image, actionMethod。這三個屬性於上圖右手邊的 emailBox.xhtml 檔案中的 #10~#13 中定義。
  • #14 為複合元件中的 的外掛進來的驗證器,使用 for 屬性指定該驗證器要對應的介面接口,該接口位於複合元件介面中的  


參考資料
  1.  EE 6: Develop Web Applications with JSF, Student Guide II, 2014
  2. 來源: Composite Example in lab files for Java EE 6 Training course.
  3. Chapter 12 Composite Components: Advanced Topics and Example, https://docs.oracle.com/javaee/6/tutorial/doc/gkhxa.html, accessed on 7/29/2015.

2015年7月22日 星期三

使用 JDAPI 開發 Oracle Form 程式: 開發環境安裝及設定

hychen39@gmail.com 
7/21/2015 

1. 安裝 Oracle Form Developer 10g (10.1.2)。一定要安裝 form developer,因為 frmjdapi.jar 在執行時會去 [ORACLE _HOME]\bin 下的目錄去呼叫 .dll 程式。ORACLE_HOME 為一環境變數,指向form developer 安裝的目錄。

2. 安裝 Netbeans。 WinXP + Form 10gR2 的環境下,安裝 Netbeans 7.2 + JDK 7u79 比較穩。

3. 在 Netbean 中新增一 Java Application 專案 。

4. 將 frmjdapi.jar 加入專案中。 frmjdapi.jar 的位置在 [ORACLE_HOME]\forms\java。


 若沒安裝 form developer,只有將 frmjdapi.jar 加入到專案中,則執行 jar 檔時會出現錯誤:




JDAPI java doc 載 (10gR2)

Oracle Forms 10g R2 Technical Information

有關 JDAPI 的說明:
Use Java to Access your Forms Files (by JDAPI)
The Oracle Forms Java Design-Time Application Programming Interface (JDAPI) lets Java programmers create, load, edit, save, and compile Forms module files (.fmb, .mmb, .olb, and .pll files) from self-written Java programs. Forms module files are normally created and edited using Forms Developer. JDAPI gives you access to almost all of the Forms Developer functionality. Because it is a programmatic interface and not an interactive development environment, JDAPI is an ideal tool for writing scripts that perform repetitive tasks on large numbers of Forms module files. For example, using JDAPI, you can make global changes to many Forms modules -- build utilities such as batch compilers or difference analyzers, create custom documentation, or perform impact analysis.


2015年7月1日 星期三

在執行 Open_Form 指令打算開啟另一個 Form 時,無法開啟並出現 FRM-40010 Cannot read from XXX 訊息

Q: 在執行 Open_Form 指令打算開啟另一個 Form 時,無法開啟並出現 FRM-40010 Cannot read from XXX 訊息, 要如何處理呢? 


 適用版本: 


  • Oracle Forms 10g