萬里歸來年愈少 PB編程新思維10.5:外傳2(PowerPlume下一代解決方案) 前言 今天我們就來盤點一下,PB下一代開發的所有技術可能性。所謂下一代開發技術,就是指脫離或半脫離PBVM的應用開發技術,主要指後端。 後端技術彙總 前端PB+JSON 前端PB+BLOB WEB 後端PBVM P ...
萬里歸來年愈少
PB編程新思維10.5:外傳2(PowerPlume下一代解決方案)
前言
今天我們就來盤點一下,PB下一代開發的所有技術可能性。所謂下一代開發技術,就是指脫離或半脫離PBVM的應用開發技術,主要指後端。
後端技術彙總
前端PB+JSON | 前端PB+BLOB | WEB | |
後端PBVM | PbNode/Pbgo | PbniServ,PowerServer | PbNode |
後端無代碼 | GraphQL | SatRDA/VDN | 無 |
PB轉瀏覽器 | PbXds | VDN | PbXds |
PB轉C# | PowerServer | PowerServer | PowerServer |
其它後端方案 | PbPdd | EXTPB.NET | SatWeb |
SatRDA
SatRDA是遠程數據訪問組件,使用它無需要改動原來的數據訪問代碼就可以支持外網訪問遠程資料庫。
評價:商用方案(由「成都Only」提供)。
SatWeb
SatWeb是遠程數據訪問組件的Web版,使用它可以遠程訪問DW(純Web方案H5DW)。
評價:商用方案(由「成都Only」提供)。這是最接近PowerPlume的方案,包括SatReport都非常好。
VDN
通過Web組件實現PB程式的瀏覽器運行,不用修改主程式代碼,瞬間實現類似B/S的效果。
評價:商用方案(由「煙臺沃森」提供)。
EXTPB.NET
基於.Net開發,採用PBNI和ActiveX技術實現PB程式的瀏覽器運行,充分利用了DataWindow控制項的功能。
評價:商用方案(由「廣州同享」提供)。黃總在群里說會在H5上發力,期待有突破性進展。
PBNIServ
It uses the PBNI to execute functions within a non-visual userobject.
評價:商用方案(由「Topwiz」提供)。
PowerServer
官方的方案。
評價:商用方案(由「appeon」提供)。
GraphQL
利用GraphQL框架搭建後端。
評價:開源方案。不成熟,PB程式轉換跨度大,可行性低
PbGo
是一套PB開發Web服務的後端框架(基於golang的PBNI擴展),可以做為靜態站點伺服器,支持 RESTful 風格API。
評價:開源/商用方案(由「杭州-夕木雙」提供)。
PbNode
Node.js環境插件,可以調用PB代碼,返回Web或JSON。
最初的嘗試,源碼放在群裡面了。單純地在伺服器運行一些PB代碼,已經有相當多的產品支持了。再做一個沒有什麼質的提升。
評價:開源方案(由「PowerPlume」提供)。性能堪憂,PB程式轉換成本高,可行性低
PbPdd
利用多線程訪問PBVM,返回JSON,可以做三層伺服器,算是前端多線程的後端應用。
評價:商用方案(由「PowerPlume」提供)。PB轉換成本較小,性能受限,可行性高
PbXds
PB下一代開發解決方案(neXt-generation Development Solution),分成四個部分
- PbXtc 下一代Trans Compiler編譯器(golang/js)
- PbXdw 下一代DataWindow(js)
- PbXrt 下一代虛擬機介面運行時(c/js)
- PbXsf 下一代Service運行框架(golang)
利用PbXtc編譯器,將PB程式整體轉換為js前端應用。程式也可以在後端(golang)運行,甚至還能在手機上運行。
評價:商用方案(由「PowerPlume」提供)。PB轉換成本較小,但功能複雜,可行性中
技術分析
PbXdw 分析
PbXdw是前端的核心代碼,成都Only的SatWeb已經有成品發佈了,同我的思路還是有區別的
PbXdw的目標是能像素級相容,在列印時無需調整。要嚴絲合縫,這個工作量比較多。
PbXsf 分析
PbXsf 是後端的核心代碼,就是不調用PBVM的情況下,支持數據的增刪改查。靜態解析PBL,生成可運行的後端代碼。首先它要解析PBL,繼而解析DW,再連接資料庫,最後啟動Web服務。有了PbXsf ,我們就可以把DW變成三層架構,可以在互聯網訪問。
PbXrt 分析
PbXrt是前後端共用的PBVM功能API介面,分成前端和後端兩個部分。前端用JS語言,後端用C語言。
PbXtc 分析
PbXts,將Pb程式編譯為Js。
在網上看過關於正陽的傳聞,他們可能是第一個做非官方編譯器的開發者,可惜還是失敗了。說起來,也是生不逢時,在06年搞純JS前端實在太困難了。現在,在無數前端開源項目的鋪墊下,難度降低太多。有了前車之鑒,成功就有可能了。
Q: APB是一個什麼產品? A: APB 是 Appeon for PowerBuilder 的縮寫。 Appeon 公司專註於實現 C/S 架構的 PowerBuilder 應用遷移到 B/S 架構的完整解決方案。Appeon for PowerBuilder 是這個解決方案的核心,是一套平臺型軟體產品。 Q: PB轉換後的程式是Java代碼或JSP嗎? A: 轉換後的文件格式包括: HTML 、 XML 、 JavaScript 、 Image 文件。不是 Java 代碼,也不是 JSP 。 Q: 用APB轉換後的Web應用和JSP開發的Web應用,技術上有什麼區別? A: APB 在客戶端使用的是 ActiveX 技術,伺服器端使用的是 J2EE 技術,包括 Servlet 、 EJB 、 JDBC 。 APB 綜合使用了 ActiveX 技術和 J2EE 技術。 JSP 則主要是伺服器端的技術,給客戶端傳來的是 HTML 標記的文檔,用於表現用戶界面。對於一些要求複雜用戶交互的應用,用 JSP 實現起來很困難。 Q: 前後臺數據是XML傳遞的嗎,可否在其它JSP程式中使用這些XML數據? A: 前後臺之間數據傳遞是二進位格式。前後臺的調用和數據傳輸都是基於 http 的 RPC 。調用格式和傳輸的數據都是二進位的。這樣做主要是出於安全和性能的考慮。 APB 早期的技術里,曾採用過 XML 來傳輸數據,但由於 XML 的解析和裝配需要一定的時間,會影響運行的速度。 Q: 現有控制項是用Javascript實現的嗎? A: PB 中的控制項,如 DataWindow 、 Treeview 、 Tab 等都是用 ATL 技術實現的, Javascript 難以實現這麼複雜的控制項。還有如 Blob 的類型, JavaScript 也難以實現。 Q: 為什麼要採用IE插件的技術?不要插件行嗎? A: 使用 ActiveX 插件是為了最大程度上,支持 PowerBuilder 的各種控制項、對象和功能特性。例如 Datawindow 控制項、 TreeView 控制項、 Dragdrop 等。這些功能在一般的 Web 應用中很難實現。 APB 在遷移 Web 應用時,具有兩種發佈方式,一種是 AX 方式,也就是插件的方式,可以支持 PB 中各種複雜的控制項和對象。另一種方式是 JS 方式,也就是純 JavaScript 方式,這種方式只能支持有限的 PowerBuilder 特性。 Q: ActiveX插件有多大,會不會每次都下載? A: Appeon 的插件有點類似於我們常見的 IE 的 Flash 插件。大約 1M 左右的 Cab 包。 IE 會自動下載,並且只是在頭一次使用的時候去下載。多個 Appeon Web 應用會使用一個插件,不會去下載多個插件,除非其版本不一樣。 Q: 為什麼需要架構調整和性能優化? A: 我們用 Powerbuilder 開發的應用一般是兩層應用,也就是 C/S 架構應用。絕大部分代碼都是在客戶端實現的,用戶界面和業務邏輯基本上是交織在一起。 APB 目前主要是實現語言的自動翻譯工作,也就是 PowerScript 語言到 JavaScript 語言的翻譯,還不能自動分離用戶界面和業務邏輯相關的代碼。 因此,翻譯後的應用如果要運行在 Internet 上,或者低帶寬網路環境下,一般還需要進行一些手工調整,將數據存取密集代碼和業務邏輯代碼轉移到資料庫伺服器或者應用伺服器上。這就是所謂的對 APB Web 應用的架構調整和性能優化。 需要說明的一點是,如果翻譯後的應用運行在帶寬很好的網路環境中,例如帶寬 10/100M 的企業網裡,可以不做或只做少量的架構調整和性能優化工作。正陽APB問答
相比APB無奈選擇的JavaScript/ActiveX/Blob/J2ee技術棧 ,今天選擇JavaScript/React/Json/REST技術棧就順理成章多了。
為了能夠清楚地認識PowerBuilder語法,我專門寫了一個包含所有語法的過程:數鴨子
1 public function integer of_count_ducks (string as_ducks) throws exception; 2 /* for testing of PowerPlume Ps2Js.exe 3 usage: f_count_ducks("黃鴨子,黑鴨子,白鴨子,黃鴨子,麻鴨子,灰鴨子,小黃鴨,唐老鴨,鹽水鴨,南京鴨") 4 5 本過程包括所有PowerScript語法,是編譯器開發的the quick brown fox jumps over a lazy dog。 6 */ 7 8 call nonvisualobject::constructor 9 if super::classname() <> "n_count_ducks" then messagebox("提示", "final類不能被繼承") 10 11 n_count_ducks nvo_test; nvo_test = create n_count_ducks 12 13 string ls_info = "門前大橋下,游過一群鴨,快來快來數一數," 14 15 string errors_arr[7] = { "warn1:灰鴨子已廢棄,請使用麻鴨子","warn2:小黃鴨的規範寫法為黃鴨子","err3:唐老鴨已終止授權",& 16 "err4:不得使用死鴨","err5:南京鴨必須死", "err6:鴨子的數量應不小於八隻", "err7:遠程調用未知錯誤"} 17 18 string numbers_arr[1 to 8] = {'', '二', '', '四', '', '六', '七', '八'} 19 20 string ducks_arr[16, 2], as_ret 21 22 blob{255} data 23 integer color 24 25 int counter=0, index=0, li_begin=1, li_current=1 26 do 27 try 28 li_begin = li_current 29 data=blob(as_ducks, EncodingUTF8!) 30 //Remote Procedure Call 31 color = nvo_test.static trigger function of_get_instance().of_get_duck(data, li_current); 32 catch(exception e) 33 color = 7 34 finally 35 index ++ 36 end try 37 38 choose case color 39 case -1, -2, -3, -4 40 ducks_arr[index, 1]=mid(as_ducks, li_begin, li_current - li_begin -1) 41 ducks_arr[index, 2]="" 42 case 9 43 goto hack ;// 被攻擊暗號 44 case 1 to 2 45 ducks_arr[index, 1]=mid(as_ducks, li_begin, li_current - li_begin -1) 46 ducks_arr[index, 2]=errors_arr[color] 47 case 3 to 5 48 ducks_arr[index, 1]="" 49 ducks_arr[index, 2]=errors_arr[color] 50 continue 51 case 6 52 ducks_arr[index, 1]="" 53 ducks_arr[index, 2]=errors_arr[color] 54 exit //數量小於8 55 case is >= 7 56 ducks_arr[index, 1]="" 57 ducks_arr[index, 2]=errors_arr[color] 58 exit 59 case else 60 goto error 61 end choose 62 counter ++ 63 loop while (counter < 8 and index < 16) 64 65 int i = 1, j = 1 66 int li_warns=0, li_errors=0 67 string ls_ducks = "" 68 do until (j > counter) 69 if (ducks_arr[i, 1]="") then 70 li_errors ++ 71 elseif (ducks_arr[i, 2]="") then 72 ls_info += numbers_arr[j] 73 ls_ducks += ducks_arr[i, 1] + " " 74 j++ 75 else 76 ls_info += numbers_arr[j] 77 ls_ducks += ducks_arr[i, 1] + "* " 78 j++ 79 li_warns ++ 80 end if 81 i ++ 82 loop 83 84 ls_info += ":~r~n"+ls_ducks+"~r~n警告:"+ string(li_warns) +"~t錯誤:" + string(li_errors) + "。~r~n" 85 86 for i = 1 to 16 87 if (ducks_arr[i, 2]<>"") then 88 ls_info += ducks_arr[i, 2] 89 ls_info += ";~r~n" 90 end if 91 next 92 93 date ld_begin, ld_today 94 time lt_begin, lt_now 95 96 ld_begin=date("2021-4-14") //求日期值的寫法 97 lt_begin=19:18:01 98 ld_today = today() 99 lt_now = now() 100 101 longlong seconds 102 Seconds= daysafter(ld_begin, ld_today)*86400 + SecondsAfter(lt_begin, lt_now) 103 ls_info += "數鴨子代碼已發佈:"+string(seconds)+"秒。" 104 messagebox("數鴨子過程包含所有PowerScript語法", ls_info) 105 106 destroy nvo_test 107 return counter 108 109 hack: 110 halt close 111 112 error: 113 destroy nvo_test 114 throw create exception 115 116 end functionView Code
PowerBuilder語法大家都熟悉,JavaScript實際上是語法上最接近PB的語言了,畢竟都是90年代的產品,理念也差不多。
至於類與繼承,也很像,PB是不支持構造函數的,就是單純的克隆。JS實際上也是一樣,通過原型克隆產生的原型鏈控制繼承。
PbXtc(包括PbXrt)開發計劃:
分為六個階段來開發
V0.1.x 編譯函數為JS代碼片斷
V0.2.x 編譯視窗為JSX界面代碼片斷
V0.3.x 編譯數據視窗為DataWeb代碼片斷
V0.4.x 編譯資料庫訪問為Rest訪問
V0.5.x 編譯事件驅動的完整應用
V0.6.x 編譯其它外部代碼
一般問題解答:
1、轉換後,界面的一致性
答:轉換時會有選項:嚴格一致,數據視窗一致,有限彈性,完全彈性四種,一致性由大到小。
2、轉換後,本地DLL介面,ocx控制項如何處理
答:完全可以相容,會在本地運行一個微型Web服務,以Rest介面的形式供Web應用調用。
3、是否需要開發配套後端
答:轉換時會有選項:完全前端,安全性前端,微前端三種,自動生成的後端代碼由少到多,無需開發。
技術升級
上面這個版本的PbXds最終被否定了,所有代碼都推倒重來。
原因是我在開發過程中,一直對這個方案不太滿意,主要問題是前端太過Web化,還需要維護JS/GO兩個框架。
最終我找到了一條完全後端化的道路,具體內容詳見《PowerBuilder現代編程方法X11:PB程式完全跨平臺方案》
<本節完>