最近有個項目,需要研究一下Oracle的E-Business Sutie(EBS),對於以前沒接觸此套件的我來說,簡直太痛苦了。在網上找了一堆資料,試着進行Form二次開發,也遇到各類奇葩問題。目前遇到最大的一個問題是,如何在本地 Form Builder中進行窗體構建,並調用后台的JavaBean和窗體進行交互?網上也有不少的解決方案,但是都存在一些差異,試了很多次,終於實現了我預期的效果。
為了防止以后再遇到類似的問題,先做一個記錄,以備后查。
1、環境搭建說明
服務器:Oracle EBS服務端(包括Oracle數據庫)部署在RedHat5
客戶端:XP系統上安裝Oracle Development Suite(其中有Form Builder 10g )
2、JavaBean編寫和編譯
在Forms Builder中,Item中有個屬性叫"Implementation Class",這個用來指定一個Item到底繼承自上表的哪個Java類。標准的Item,其Implementation Class都放空,無須我們明確指定,因為Oracle內置了對應關系。但如果要在Forms 中使用非標准的Class,比如我們自行擴展的,則必須明確指出Item的"Implementation Class",並且是帶包名的全稱,如oracle.forms.fd.JavaHost。一個類要在Forms中使用,其必須符合Oracle Forms的設計規范,簡單說,就是要實現oracle.forms.ui.IView接口。Oracle還提供了實現IView接口的VBean類,如果欲創建的類不需要從其他類繼承,則可以直接extends VBean,省了實現IView的麻煩。

1 package oracle.forms.fd; 2
3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.util.StringTokenizer; 7 import oracle.forms.handler.IHandler; 8 import oracle.forms.ui.VBean; 9 import oracle.forms.properties.ID; 10 import oracle.forms.ui.CustomEvent; 11
12 //Form整合JavaBean要實現IView接口, 13 //若創建的類不需要繼承其他類,則可以直接extends VBean
14 public class JavaHost extends VBean 15 { 16 private static final ID SetProg = ID.registerProperty("SET_PROG"); 17 private static final ID MSGSTND = ID.registerProperty("MSGSTND"); 18 private static final ID MSGERROR = ID.registerProperty("MSGERROR"); 19 private static final ID MSGTEXT = ID.registerProperty("MSGTEXT"); 20 private IHandler m_handler; 21 Process p = null ; 22
23 public JavaHost() 24 { 25 } 26
27 public void init(IHandler handler) 28 { 29 m_handler = handler; 30 super.init(handler); 31 } 32
33 /************************* 34 * Set some properties * 35 ************************/
36 public boolean setProperty(ID property, Object value) 37 { 38 /*
39 * Start the process * 40 */
41 if (property == SetProg) 42 { 43 String s= value.toString(), s2="" ; 44 String[] sTabParams = null ; 45 int iNbParams = 0, iPos=-1 ; 46 iPos = s.indexOf(",") ; 47 if(iPos > -1) 48 { 49 StringTokenizer st = new StringTokenizer(s,","); 50 // get the total number of parameters
51 while (st.hasMoreTokens()) 52 { 53 s2 = st.nextToken() ; 54 iNbParams++; 55 } 56 sTabParams = new String[iNbParams]; 57 st = new StringTokenizer(s,","); 58 for( int i=0; i<iNbParams; i++ ) sTabParams[i] = st.nextToken() ; 59 } 60 // launch the programme
61 try { 62 if(iPos > -1) p = Runtime.getRuntime().exec(sTabParams); 63 else p = Runtime.getRuntime().exec(s); 64
65 new Thread() 66 { 67 public void run() 68 { 69 try
70 { 71 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); 72 String line = null; 73 try { 74 while((line = br.readLine()) != null) 75 { 76 // Send standard output to Forms
77 SendProperties(MSGSTND,line); 78 } 79 } 80 finally
81 { 82 br.close(); 83 } 84 } 85 catch(IOException ioe) 86 { 87 ioe.printStackTrace(); 88 SendProperties(MSGERROR,ioe.getMessage()); 89 } 90 } 91 }.start(); 92 // Error output
93 new Thread() 94 { 95 public void run() 96 { 97 try
98 { 99 BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream())); 100 String line = null; 101 try
102 { 103 while((line = br.readLine()) != null) 104 { 105 // Send error output to Forms
106 SendProperties(MSGERROR,line); 107 } 108 } 109 finally
110 { 111 br.close(); 112 } 113 } 114 catch(IOException ioe) 115 { 116 ioe.printStackTrace(); 117 SendProperties(MSGERROR,ioe.getMessage()); 118 } 119 } 120 }.start(); 121 } 122 catch(IOException ioe) { ioe.printStackTrace(); SendProperties(MSGERROR,ioe.getMessage());} 123
124 return true ; 125 } 126 else
127 { 128 return super.setProperty(property, value); 129 } 130 } 131
132 // send standard/error output back to Forms
133 private void SendProperties(ID id, String sMessage) 134 { 135 try{ 136 CustomEvent ce = new CustomEvent(m_handler, id); 137 m_handler.setProperty( MSGTEXT, sMessage ); 138 dispatchCustomEvent(ce); 139 } 140 catch (Exception e) 141 { 142 e.printStackTrace(); 143 } 144 } 145
146 }
用java1.3的版本編譯此JavaHost.java,打包成javahost.jar放於客戶端xp 系統的C:\DevSuiteHome_1\forms\java位置(我的安裝在C盤),其實服務器上也有一個此目錄
3、formsweb.cfg配置
服務器和客戶端都存在這樣的配置文件,如果在本地進行窗體調試,必須配置本地的formsweb.cfg(網上很多都並未提出是服務器端還是客戶端,我折騰了很久)。在C:\DevSuiteHome_1\forms\server文件下打開formsweb.cfg,將javahost.jar追加到archive_jini上,如archive_jini=frmall_jinit.jar,javahost.jar(注意是逗號分隔,不是分號)
4、Form創建和配置
在Form Builder創建JAVA_HOST.fmb的窗體,在Form上添加一個Bean區域控件,它的實施類為oracle.forms.fd.JavaHost。
5、運行窗體(單擊運行表單按鈕)
單據FormBuilder上的運行表單按鈕,稍等一會(其實也挺慢的...),會出現下面的界面:
在Command文本框中輸入 cmd /c dir /b c:\*.jpg ,然后單擊Execute按鈕運行命令。如果調用JavaBean成功的話,會搜索本地C盤下的.jpg文件,並列出到Result中,如下圖:
本次測試正確。發布到服務器還需要對服務器相關文件進行配置。客戶端的路徑問題,可搜索注冊表("_PATH") 來查看FORMS_PATH和ORACLE_HOME的路徑情況。
6、關於FormBuilder導入pll庫和java包的若干說明
有的時候你的窗體需要用到其他的庫文件,默認不在FormBuilder的搜索路徑中,必須手動進行引入。例如我碰到一個fnd_message.debug未聲明的錯誤,網上說是要導入一個FNDSQF.pll庫,但是都沒說如何導入。最后摸索出來是這樣的,首先需要把服務器forms(包含很多系統和開發的窗體,如果待開發的窗體需要調用這些,必須要拷貝到開發環境下)和resource(FNDSQF.pll庫就在此目錄下)文件夾拷貝到本地。
導入pll庫的方法如下圖:
如果需要導入java類,可以首先編輯注冊表項目FORMS_BUILDER_CLASSPATH,在此項目后追加待導入庫的完整路徑,如下圖:
然后就可以在FormBuilder看見javahost.jar中的java類:oracle.forms.fd.javahost
另外就是在運行Form時,首先必須確保開啟本地Start OC4J Instance,如下圖:
另外就是把窗體上傳到服務器端后,注意編譯的路徑和菜單使用的路徑(和掛接的模塊有關系,不同的模塊在不同的文件夾下)是不同的,否則會報無法加載XXX.fmx的情況。
編譯命令:frmcmp_batch module=/u01/oracle/VIS/apps/apps_st/appl/ozf/12.0.0/forms/ZHS/FRM_WM_JAVABEAN.fmb userid=apps/apps@VIS output_file=/u01/oracle/VIS/apps/apps_st/appl/ozf/12.0.0/forms/ZHS/FRM_WM_JAVABEAN.fmx
服務器常用的路徑:
/u01/oracle/VIS/apps/apps_st/appl/au/12.0.0/resource
/u01/oracle/VIS/apps/apps_st/comn/java/classes
/u01/oracle/VIS/apps/apps_st/appl/ozf/12.0.0/forms/ZHS
/u01/oracle/VIS/apps/tech_st/10.1.2/forms/server
/u01/oracle/VIS/apps/tech_st/10.1.2/forms/java