利用 Eclipse Modeling Framework 加强 JAX-RPC 类型映射的功能
2009-12-17 00:00:00 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻鐔兼⒒鐎靛壊妲紒鐐劤缂嶅﹪寮婚悢鍏尖拻閻庨潧澹婂Σ顔剧磼閻愵剙鍔ょ紓宥咃躬瀵鎮㈤崗灏栨嫽闁诲酣娼ф竟濠偽i鍓х<闁绘劦鍓欓崝銈囩磽瀹ュ拑韬€殿喖顭烽幃銏ゅ礂鐏忔牗瀚介梺璇查叄濞佳勭珶婵犲伣锝夘敊閸撗咃紲闂佺粯鍔﹂崜娆撳礉閵堝洨纾界€广儱鎷戦煬顒傗偓娈垮枛椤兘骞冮姀銈呯閻忓繑鐗楃€氫粙姊虹拠鏌ュ弰婵炰匠鍕彾濠电姴浼i敐澶樻晩闁告挆鍜冪床闂備胶绮崝锕傚礈濞嗘挸绀夐柕鍫濇川绾剧晫鈧箍鍎遍幏鎴︾叕椤掑倵鍋撳▓鍨灈妞ゎ厾鍏橀獮鍐閵堝懐顦ч柣蹇撶箲閻楁鈧矮绮欏铏规嫚閺屻儱寮板┑鐐板尃閸曨厾褰炬繝鐢靛Т娴硷綁鏁愭径妯绘櫓闂佸憡鎸嗛崪鍐簥闂傚倷鑳剁划顖炲礉閿曞倸绀堟繛鍡樻尭缁€澶愭煏閸繃宸濈痪鍓ф櫕閳ь剙绠嶉崕閬嶅箯閹达妇鍙曟い鎺戝€甸崑鎾斥枔閸喗鐏堝銈庡幘閸忔﹢鐛崘顔碱潊闁靛牆鎳愰ˇ褔鏌h箛鎾剁闁绘顨堥埀顒佺煯缁瑥顫忛搹瑙勫珰闁哄被鍎卞鏉库攽閻愭澘灏冮柛鏇ㄥ幘瑜扮偓绻濋悽闈浶㈠ù纭风秮閺佹劖寰勫Ο缁樻珦闂備礁鎲¢幐鍡涘椽閸愵亜绨ラ梻鍌氬€峰ù鍥敋閺嶎厼鍨傞幖娣妼缁€鍐煥濠靛棙顥滈柣锕備憾濮婂宕掑▎鎺戝帯濡炪們鍨归敃銈夊煝瀹ュ鍗抽柕蹇曞Х椤斿姊洪幖鐐插姶闁告挻鐟╅幃姗€骞庨懞銉у幐闂佸憡鍔戦崝搴㈡櫠閺囩姷纾奸柍褜鍓熷畷姗€鍩炴径鍝ョ泿闂傚⿴鍋勫ú銈吤归悜鍓垮洭鏁冮埀顒勬箒濠电姴锕ら悧蹇涙偩濞差亝鐓涢悘鐐额嚙婵″ジ鏌嶇憴鍕伌鐎规洖宕埢搴ょ疀閹惧妲楃紓鍌氬€搁崐鐑芥⒔瀹ュ绀夐幖杈剧到閸ㄦ繃銇勯弽顐粶濡楀懘姊洪崨濠冨闁搞劍澹嗙划濠氬箮閼恒儱鈧敻鏌ㄥ┑鍡欏嚬缂併劏妫勯湁闁绘ǹ宕甸悾鐑樻叏婵犲啯銇濇俊顐㈠暙閳藉鈻庨幇顓炩偓鐑芥⒑鐠囨彃顒㈤柣顓у櫍瀹曪繝骞庨懞銉ヤ粧濡炪倖娲嶉崑鎾垛偓瑙勬礀閻栧ジ銆佸Δ浣哥窞閻庯綆鍋呴悵顐⑩攽閻樻剚鍟忛柛锝庡灣瀵板﹪宕滆閸嬫挾绮☉妯绘悙缂佺姵鐓¢弻娑㈠Ψ椤旂厧顫╅梺钘夊暟閸犳牠寮婚敐澶婃闁圭ǹ瀛╅崰鎰版⒑閼姐倕鏋庣紓宥咃躬瀵鈽夐埗鈹惧亾閿曞倸绠f繝闈涙川娴滎亝淇婇悙顏勨偓銈夊礈濞嗘挻鍋嬮柛鈩冪▓閳ь剚妫冨畷姗€顢欓崲澹洤绠圭紒顔煎帨閸嬫捇鎳犻鈧崵顒傜磽閸屾艾鈧娆㈤敓鐘茬獥婵°倕鎳庣粻浼存煙闂傚鍔嶉柛瀣ф櫊閺岋綁骞嬮敐鍡╂缂佺虎鍘搁崑鎾绘⒒娴h櫣甯涢柛鏃€娲滅划鏃堟濞磋櫕鐩畷姗€顢欓崗鍏夹氶梻渚€鈧偛鑻晶顖炴煏閸パ冾伃妤犵偞甯¢獮瀣攽閹邦亞纾婚梺璇叉唉椤骞愭搴g焼濞撴埃鍋撻柛鈺冨仱楠炲鏁傞挊澶夋睏闂備礁婀辩划顖滄暜閳哄倸顕遍柍褜鍓涚槐鎾存媴閻熸澘濮㈤悷婊勫閸嬬喖宕氶幒鎴旀瀻闁规儳鐤囬幗鏇炩攽閻愭潙鐏﹂柣顓у枛閳讳粙顢旈崼鐔哄幍闁荤喐鐟ョ€氼剚鎱ㄩ崶銊d簻闁靛濡囩粻鐐存叏婵犲啯銇濋柡灞芥嚇閹瑩鎳犵捄渚純濠电姭鎷冮崒姘ギ闂佸搫鐬奸崰鏍箹瑜版帩鏁冮柨婵嗘噽閿涙捇姊绘担鐟邦嚋缂佽瀚板畷鎴濃槈閵忕姷鍘撮梺鐟邦嚟婵參宕戦幘缁樻櫜閹煎瓨锚娴滅偓銇勯幘瀵糕姇婵炲懎锕弻锛勪沪閻e睗锝嗙箾绾板彉閭鐐茬箳娴狅箓鎸婃径濠呭帿闂傚倸鍊烽悞锕傛儑瑜版帒纾归柡鍥ュ灩缁犵娀鏌熼柇锕€鏋熸い顐f礋閺岀喖骞嗚閹界姴鈹戦娑欏唉闁哄本鐩獮姗€寮堕幋鐘点偡闂備礁鎲¢幐绋跨暦椤掑嫧鈧棃宕橀鍢壯囨煕閳╁喚娈樺ù鐘虫倐濮婃椽鎳¢妶鍛瘣闂佸搫鎳忛惄顖炲箖妤e啯鍊婚柦妯猴級閵娧勫枑濠㈣埖鍔曠壕濠氭煙閸撗呭笡闁哄懏鐓¢獮鏍垝閻熸澘鈷夐梺璇茬箰缁夌懓顫忛搹鍦<婵☆垵顕ч棄宥呪攽閻愭彃绾ч柨鏇樺灪娣囧﹪鎮界粙璺槹濡炪倖鐗楀銊╂偪閳ь剟姊婚崒姘偓鎼佹偋婵犲嫮鐭欓柟閭﹀枦婵娊鏌ゅù瀣珖缁炬崘妫勯湁闁挎繂鐗婇ˉ澶愭煟閹炬潙濮堥柟渚垮妼铻g紒瀣仢椤鈹戦垾鍐茬骇闁告梹鐟╅悰顔嘉熼崗鐓庣彴闂佽偐鈷堥崜锕€危娴煎瓨鈷掑ù锝嚽归弳閬嶆煙绾板崬浜扮€规洘鍔栫换婵喰掔粙鎸庡枠鐎殿喛鍩栭幆鏃堝箻鐎涙ɑ婢戝┑锛勫亼閸婃牕顫忔繝姘ラ悗锝庝憾閸熷懘鏌曟径娑滅濞存粍绮嶉妵鍕箻鐠鸿桨绮跺┑鈩冨絻椤兘寮婚敐澶嬫櫜闁搞儜鍐ㄧ婵°倗濮烽崑鐐垫暜閿熺姷宓侀悗锝庡枛缁秹鏌嶈閸撶喖骞冨Δ浣虹瘈婵﹩鍘搁幏娲煟閻斿摜鎳冮悗姘煎弮瀹曟洖螖閸涱喚鍘卞┑鈽嗗灥閵嗏偓闁稿鎹囬幃銏ゅ箵閹烘垹闃€婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繘鏌i幋锝嗩棄闁哄绶氶弻娑樷槈濮楀牊鏁鹃梺鍛婄懃缁绘垿濡甸崟顖氱闁告鍋熸禒鑲╃磼閻愵剙鍔ゆい顓犲厴瀵鎮㈤悡搴n槶閻熸粌绻掗弫顔尖槈閵忥紕鍘撻梻浣哥仢椤戝懘鎮橀敃鍌涚厪闁搞儜鍐句純濡ょ姷鍋炵敮鈥崇暦閸楃儐娓婚柟顖嗗本顥$紓鍌氬€搁崐鎼佸磹妞嬪海鐭嗗〒姘e亾閽樻繈姊洪鈧粔鎾几娴g硶鏀介柣妯挎珪閻ㄦ垹鈧鎸风欢姘跺蓟濞戙垹鐒洪柛鎰典簴婵洭姊虹粙鍖″姛闁稿繑锕㈠璇测槈濡攱鏂€闂佺硶鍓濋〃蹇斿閳ь剚淇婇悙顏勨偓鏍ь潖瑜版帒绀夐柡鍥ュ灩閻撴﹢鏌熸潏楣冩闁稿﹤顭烽弻娑㈠Ψ閵忊剝鐝栭柡宥忕節濮婄粯鎷呴崨濠傛殘闂佸湱枪椤兘骞冮悜鑺ユ櫆闁伙絽澶囬弨铏節閻㈤潧孝婵炶绠撳畷鐢稿礃椤旂晫鍘撻梺鍛婄箓鐎氼剟寮抽悢鍏肩叆婵炴垶鐟ч惌鎺撴叏婵犲洨绱伴柕鍥ㄥ姍楠炴帡骞嬪⿰鍐╃€抽梻鍌欑閹诧繝鎮烽妷锔绘闁归棿绀侀悡婵嬫煙閻愵剚鐏遍柛顐邯閺屾盯顢曢妶鍛亖闂佸憡蓱閹倿寮婚敐鍫㈢杸闁哄洨鍋橀幋椋庣磼缂併垹骞栭柣鏍帶閻g兘骞嬮敃鈧粻濠氭偣閸ヮ亜鐨洪柣銈傚亾婵犵數鍋犻幓顏嗗緤娴犲绠熼柨鐔哄Т绾捐銇勯弽顐沪闁抽攱鍨归惀顏堫敇閻愭潙娅f繛瀛樼矊缂嶅﹪骞冪捄琛℃闁哄诞鍐ㄐ曢梻浣虹《閺備線宕戦幘鎰佹富闁靛牆妫楃粭鎺楁煕閻曚礁浜伴柟顖氬暙鐓ゆい蹇撴噽閸樺憡绻涙潏鍓у埌婵犫偓鏉堛劍娅犳い蹇撶墛閻撳啴鎮峰▎蹇擃仼闁诲繑鎸抽弻鐔碱敊閻e本鍣伴悗娈垮枛閻栧ジ鐛€n喗鍋愰弶鍫厛閺佸洭姊婚崒姘偓椋庣矆娴i潻鑰块弶鍫涘妿娴犳岸姊绘担渚敯濠殿喓鍊楅崚鎺撴償閵娿儳顦梺鍦劋椤ㄥ懐鐚惧澶嬬厱妞ゆ劑鍊曢弸搴∶归悩鐑橆仩缂佽鲸鎸婚幏鍛村礈閹绘帒澹嶆俊鐐€栧ú妯荤箾婵犲洤鏋侀柛鎰靛枛绾惧吋绻涢幋鐐跺妤犵偛鐗撳缁樻媴閸涘﹥鍎撳┑鐐茬湴閸ㄨ棄鐣峰┑鍡欐殕闁告洦鍓欓埀顒€鐖奸弻锝呂熼懖鈺佺闂佺粯鎸诲ú鐔煎蓟閻斿吋鍤嬫い鎺嗗亾濠碉紕鍘ч湁婵犲﹤瀚崝銈夋煃鐟欏嫬鐏撮柡浣哥Ч瀹曠喖顢曢埄鍐╃窔闂傚倷鑳舵灙闁挎洏鍎甸幃褔鎮╅懠顒佹濠电娀娼ч鍡涘疾濠靛鐓冪憸婊堝礈閻旂厧鐏抽柨鏇炲€搁柨銈嗕繆閵堝倸浜鹃梺缁樺笒閻忔岸濡甸崟顖氱鐎广儱鐗嗛崢锛勭磽娴e搫孝濠⒀傜矙閸┾偓妞ゆ巻鍋撻柛妯荤矒瀹曟垿骞橀弬銉︽杸闂佺粯枪娴滎剛绮i弮鍫熺厱閻庯綆鍋掑▓鏃堟煃鐟欏嫬鐏存い銏$懅濞戠敻鎮滈悾灞藉冀濠电姷鏁搁崑娑㈠箯閹寸姴绶ら柛顭戝暎閿濆绠涢柡澶庢硶椤斿﹪姊洪悷鏉挎毐缁剧虎鍙冨畷浼村箻鐠囪尙顔嗛梺缁樶缚缁垶宕甸幋锔界厾缂佸娉曟禒娑欐叏閿濆棗濮嶆慨濠傤煼瀹曟帒顫濋钘変壕闁绘垼濮ら崵鍕煠閸濄儲鏆╁ù鐘崇缁绘繈鎮介棃娑楃捕濡炪倖娲﹂崣鍐ㄧ暦濡も偓铻e〒姘煎灠濞堛劌顪冮妶鍡楀闁稿﹥鐗滈埀顒佺濮樸劑鍩€椤掑倹鍤€濠㈢懓锕畷浼村冀瑜夐弸鏃堟煏婵犲繐顩紒鈾€鍋撻梻浣圭湽閸ㄨ棄岣胯閻楀海绱撴担鍝勪壕婵犮垺岣跨划鏃堟偡闁箑娈ㄩ梺鍝勮閸庤京绮婚悽鍛婄厵闁绘垶岣跨粻姗€鏌涢悙鍨毈闁哄矉缍侀幃鈺呮倻濮楀棔鍝楅梺璇茬箰缁诲牓宕濆畝鍕垫晩闊洦绋戝敮閻熸粌顦靛畷鎴﹀箻閼搁潧鏋傞梺鍛婃处閸撴瑧鍠婂鍛斀闁宠棄妫楁禍婵堢磼鐠囨彃鈧潡鏁愰悙鍓佺杸婵炴垶鐟﹂崕顏堟⒑闂堚晛鐦滈柛姗€绠栭弫宥呪堪閸愶絾鏂€闂佸疇妫勫Λ妤呮倶閻樼粯鐓欑痪鏉垮船娴滀即鏌ㄥ┑鍫濅粶妞ゆ挸銈稿畷鍫曞煛閸愯法闂繝鐢靛仩閹活亞绱炴笟鈧棢闁规崘顕х粈澶屸偓骞垮劚椤︿即鎮″▎鎴犵<閻庯綆浜炴禒銏ゆ煛閸℃稐鎲鹃柡宀嬬秮閺佹劙宕惰楠炲螖閻橀潧浠滄い鎴濐樀瀵偊宕橀鑲╁姦濡炪倖甯掗崐缁樼▔瀹ュ應鏀介柣妯虹-椤f煡鏌涚€e墎绉柡灞剧洴婵$兘骞嬪┑鍡樻婵°倗濮村ú顓㈠箖濡ゅ啯鍠嗛柛鏇ㄥ墮绾板秶绱撴担鍓叉Ч闁瑰憡濞婇崹楣冨籍閸繄顦ㄥ銈嗘煥濡插牐顦归柡灞剧洴閸╁嫰宕楅悪鈧禍顏勎涢崟顐悑闁搞儮鏅濋敍婵囩箾鏉堝墽鍒板鐟帮躬瀹曟洟骞囬悧鍫㈠幈闂侀潧枪閸庨亶銆傚畷鍥╃<妞ゆ梻鈷堥崕蹇斻亜閹惧啿鎮戠€垫澘瀚埀顒婄秵娴滄牠宕戦幘缁樼叆閻庯絻鍔嬬花濠氭⒑閻熺増鎯堢紒澶婄埣钘濋柨鏃堟暜閸嬫挸鈻撻崹顔界亪闂佽绻戠换鍫ュ春閻愬搫绠i柨鏇楀亾闁绘搫绻濋弻娑㈠焺閸愮偓鐣兼繛瀵稿閸ㄨ泛顫忓ú顏勫窛濠电姴娴烽崝鍫曟⒑閸涘﹥澶勯柛娆忛鐓ら柛娑橈梗缁诲棝鏌曢崼婵堢闁告帊鍗抽弻娑㈡偆娴e摜浠搁悗瑙勬礃閸旀瑥鐣疯ぐ鎺濇晝闁挎繂鎳庢导搴㈢節绾版ɑ顫婇柛銊﹀▕瀹曘垼顦崇紒鍌氱У閵堬綁宕橀埡浣插亾閸偅鍙忔俊顖滃帶娴滈箖鎮楀鐐

引言
JAX-RPC,也称为 JSR-101,是完成标准编程模型的一个重要步骤,该标准编程模型简化了 Java™ 平台上可互操作的 Web 服务的构建。由 XML 向 Java 类型映射模型的转换是 JAX-RPC 的关键,该转换是 Web 服务产品提供者的一个实现标准。没有这样的模型,Web 服务产品提供者会陷入定义专用类型映射的陷阱中,从而严重影响 Java 的互操作性问题。
虽然 JAX-RPC 在支持 XML 数据类型方面做了大量的工作,但是还有很多地方需要改进。而且,JAX-RPC 需要将任何不被支持的 XML 数据类型映射到 javax.xml.soap.SOAPElement 接口。javax.xml.soap.SOAPElement 接口没有为用户提供强类型的 Java 模型,也就是说用户必须编写自定义代码,然后通过 SOAPElement 实例来解析。这对初学者来说比较难,特别是当处理大的 XML 片段的时候。本文演示了如何使用 EMF 来支持没有标准 JAX-RPC 类型映射的 XML 数据类型。使用不支持 XML 数据类型的 JAX-RPC 生成 Web 服务并非易事,但是本文把 Web 服务工具和 IBM® WebSphere® Studio Application 以及 Site Developer V5.1.2 (Application and Site Developer) 中的 EMF 工具结合起来使用,提供了一个有效的解决方案。
创建供应链 Web 服务
要实现本文所介绍的方法,必须安装 WebSphere Application 和 Site Developer V5.1.2。如果需要的话,可以下载一个 60 天的试用版。
创建一个 Web 项目。单击菜单File>New>Project...>Web > Dynamic Web Project>Next,打开 New Dynamic Web Project wizard。
输入SupplyChainWeb作为 Web 项目的名称,选中Configure advance options复选框,然后单击Next。
输入SupplyChainEAR作为 EAR 项目的名称,然后单击Finish。
单击本文顶部的Code图标,下载 SupplyChainService.wsdl 和 SupplyChainSchema.xsd 到本地文件系统中。
将 SupplyChainService.wsdl 和 SupplyChainSchema.xsd 导入或复制到 SupplyChainWeb 项目的根目录下。
在 navigator 视图中,右键单击SupplyChainService.wsdl>Web Services>Generate Java bean skeleton打开图 1所示的 WSDL to Java Bean Skeleton wizard。该向导生成一个基于 WSDL 文档中定义的信息的 Java 架构代码实现。接受所有的默认设置,然后单击Finish。
图 1.WSDL to Java Bean Skeleton wizard
向导完成之后,您会在 tasks 视图中看见一些 WSDL 验证错误,这是由于 XML 模式文件 (SupplyChainSchema.xsd) 没有被复制到正确的地方。要更正这些错误,将 SupplyChainSchema.xsd 从 SupplyChainWeb 项目的根目录下复制到 /SupplyChainWeb/WebContent/WEB-INF/wsdl/ 和 /SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/ 这两个目录中。右键单击SupplyChainService.wsdl>Run validation,再次运行验证。
创建供应链 EMF 模型
WSDL to Java Bean Skeleton wizard 生成带一个或多个映射到 SOAPElement (具体的,PurchaseOrderType.java、PurchaseReferenceType.java 以及 ShippingNoticeType.java)属性的 JavaBean。在本部分中,将生成一个供应链 Web 服务的 EMF 模型来支持映射到 SOAPElement 的 XML 数据类型。
创建一个 EMF 项目。单击菜单File>New>Project...>Eclipse Modeling Framework>EMF Project>Next,打开 New EMF Project wizard。
输入SupplyChainEMF作为项目的名称,然后单击Next。
选择Load from an XML schema,然后单击Next。
单击Browse Workspace...打开文件选择对话框。查找并选择SupplyChainSchema.xsd,然后单击OK。单击Next。
选择supplychain包,然后单击Finish。参阅图 2。
图 2.New EMF Project wizard
New EMF Project wizard 完成后,系统将打开 EMF Generator Editor。在这个编辑器中,右键单击SupplyChainSchema节点,选择Generate Model Code。您已经成功生成了供应链 EMF 模型。在下一部分中,将学习如何将 EMF 代码集成到供应链 Web 服务中。
集成供应链 Web 服务与 EMF 模型
为 SupplyChainWeb 项目设置所有的依赖关系。将 SupplyChainEMF 项目添加到 SupplyChainEAR 作为一个实用的 JAR 文件,并指定从 SupplyChainWeb 项目到该实用 JAR 文件的 JAR 文件依赖性。
在应用程序部署描述编辑器 (Application Deployment Descriptor Editor) 中打开 /SupplyChainEAR/META-INF/application.xml。单击Module选项卡。
在 Project Utility JARs 栏中,单击Add...,选择SupplyChainEMF,然后单击Finish。保存并关闭应用程序部署描述编辑器。
在 JAR Dependency Editor 中打开 /SupplyChainWeb/WebContent/META-INF/MANIFEST.MF。在 Dependencies 栏中选择SupplyChainEMF.jar。保存并关闭应用程序部署描述编辑器。
将 EMF 库添加到 SupplyChainWeb 项目的 Java 构建路径中。右键单击SupplyChainWebproject >Properties>Java Build Path。单击Libraries选项卡,选择Add Variable...。
选择EMF_COMMON、EMF_ECORE 以及 EMF_ECORE_XMI。单击OK>OK。
清单 1显示了用到的所有导入语句。在 Java 编辑器中打开 /SupplyChainWeb/JavaSource/com/example/supplychain/www/SupplyChainBindingImpl.java 并添加这些导入语句。
清单 1.导入语句import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import com.example.supplychain.ItemType;
import com.example.supplychain.PaymentMethodType;
import com.example.supplychain.ProcessingType;
import com.example.supplychain.ShippingItemType;
import com.example.supplychain.StatusType;
import com.example.supplychain.SupplychainFactory;
import com.example.supplychain.SupplychainPackage;
import com.example.supplychain.impl.SupplychainPackageImpl;
import com.example.supplychain.util.SupplychainResourceFactoryImpl;
使用生成的供应链 EMF 模型之前必须先初始化。初始化过程在 XML 模式 (SupplyChainSchema.xsd) 中声明的元素和 EMF 代码生成器创建的 Java 类之间建立了一个映射。该映射用于 XML 片段与相应的基于 EMF 的 Java 类之间的相互转换。要初始化供应链 EMF 模型,将下面的静态代码块添加到 SupplyChainBindingImpl.java 中。
清单 2.初始化 EMF 包static
{
SupplychainPackageImpl.init();
}
接下来,在 SupplyChainBindingImpl.java 中添加 4 个方法,这些方法将 SOAPElement 转换为 DOMElement,然后再转换为相应的基于 EMF 的 Java 类,也可以反过来转换。清单3、4、5以及6 显示了这些方法。 soapElement2DOMElement(SOAPElement soapElement) 方法和 domElement2SOAPElement(Element e) 方法利用两个特定于应用程序和站点开发者实现的方法: getAsDOM() 和 setAlternateContent(e) ,来负责 SOAPElement 到 DOMElement 的转换。要从特定于提供商的代码中清除这些方法,可以手动的遍历 SOAPElement 并构造相应的 DOMElement。
在本文中,可以使用现成的方法,也就是说,可以使用应用程序和站点开发者实现提供的方法。事实上,如果 SOAP 附带了 Java V1.2 (SAAJ)- 兼容实现的附加 API 函数,那么就不再需要将 SOAPElement 转换为 DOMElement,这是因为 SAAJ V1.2 需要 SOAPElement 以直接扩展 DOMElement。
清单 3.将 SOAPElement 转换为 DOMElementpublic Element soapElement2DOMElement(SOAPElement soapElement)
throws Exception
{
return ((com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapElement).getAsDOM();
}
清单 4.将 DOMElement 转换为 EMF 对象public EObject domElement2EObject(Element e)
throws TransformerConfigurationException, TransformerException, IOException
{
DOMSource domSource = new DOMSource(e);
Transformer serializer = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.transform(domSource, new StreamResult(baos));
byte[] b = baos.toByteArray();
System.out.println(new String(b));
URI uri = URI.createURI(SupplychainPackage.eNS_URI);
SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl();
Resource res = factory.createResource(uri);
ByteArrayInputStream bais = new ByteArrayInputStream(b);
res.load(bais, null);
List contents = res.getContents();
return (!contents.isEmpty()) ? (EObject)contents.get(0) : null;
}
清单 5.将 EMF 对象转换为 DOMElementpublic Element eObject2DOMElement(EObject eObject)
throws IOException, ParserConfigurationException, SAXException
{
URI uri = URI.createURI(SupplychainPackage.eNS_URI);
SupplychainResourceFactoryImpl factory = new SupplychainResourceFactoryImpl();
Resource res = factory.createResource(uri);
res.getContents().add(eObject);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
res.save(baos, null);
byte[] b = baos.toByteArray();
System.out.println(new String(b));
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new ByteArrayInputStream(b));
return doc.getDocumentElement();
}
清单 6.将 DOMElement 转换为 SOAPElementpublic SOAPElement domElement2SOAPElement(Element e)
throws SOAPException
{
SOAPFactory soapFactory = SOAPFactory.newInstance();
com.ibm.ws.webservices.engine.xmlsoap.SOAPElement soapElement =
(com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapFactory.createElement(
"temp");
soapElement.setAlternateContent(e);
return soapElement;
}
全局元素和局部元素
正如前面所提到的,供应链 EMF 模型依靠映射到 Java 的元素将 XML 片段转换为相应的基于 EMF 的 Java 类。但是,默认的情况是,EMF 代码生成器只为全局元素生成映射条目,而不为局部元素生成。全局元素是 XML 模式文档中作为模式元素的子元素来声明的元素,而局部元素却不是。默认的映射清单不包括局部元素,因此,供应链 EMF 模型不能转换描述局部元素实例的 XML 片段。研究一下清单 7中的示例 XML 模式。相应的 EMF 模型识别清单 8中的全局元素实例。相反,清单 9中的局部元素实例却导致异常。要支持局部元素的转换,必须在 Java 映射中添加自定义元素。
清单 7.XML 模式示例<schema>
<element name="GlobalElement">
<complexType>
<sequence>
<element name="LocalElement" type="xsd:string"/>
</sequence>
</complexType>
</element>
</schema>
清单 8.全局元素实例<GlobalElement>
<LocalElement>Some String</LocalElement>
</GlobalElement>
清单 9.局部元素实例<LocalElement>Some String</LocalElement>
考虑 SupplyChainSchema.xsd 文档和 WSDL to Java Bean Skeleton wizard 生成的 JavaBean 时,您将看见有三个局部元素被映射到 SOAPElement:
来自 <PurchaseOrderType> 复杂类型的 <paymentMethod> 元素
来自 <PurchaseOrderType> 复杂类型的 <item> 元素
来自 <ShippingNoticeType> 复杂类型的 <item> 元素
要在 <paymentMethod> 这个局部元素和 com.example.supplychain.PaymentMethodType 这个 Java 类之间建立自定义映射,请在 SupplyChainEMF 项目中打开 /SupplyChainEMF/src/com/example/supplychain/impl /SupplychainPackageImpl.java。将清单 10 中的代码片段添加到 initializePackageContents() 方法的尾部。该方法将作为初始化的一部分被调用。
清单 10.添加一个局部元素映射initEClass(paymentMethodTypeEClass, PaymentMethodType.class,
"paymentMethod", !IS_ABSTRACT, !IS_INTERFACE);
接下来,将为两个 <item> 局部元素建立自定义映射。和 <paymentMethod> 元素不同的是,不能在 initializePackageContents() 方法中添加静态映射条目,这是因为 EMF 模型对每个局部元素名称只允许一个映射。要克服这个缺点,可以象使用映射那样动态注册并移除必要的映射。清单 11 显示了 4 个方法,这 4 个方法允许您从 <PurchaseOrderType> 复杂类型中注册和移除 <item> 元素映射,以及从 <ShippingNoticeType> 复杂类型中注册和移除 <item> 元素映射。在 SupplyChainEMF 项目中,打开 SupplychainPackageImpl.java 并添加清单 11所示的代码片段。
清单 11.添加一个局部元素映射private EClass purchaseItem;
public void initPurchaseItem()
{
purchaseItem = initEClass(createEClass(ITEM_TYPE),
ItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE);
}
public void removePurchaseItem()
{
if (purchaseItem != null)
this.eClassifiers.remove(purchaseItem);
}
private EClass shippingItem;
public void initShippingItem()
{
shippingItem = initEClass(createEClass(SHIPPING_ITEM_TYPE),
ShippingItemType.class, "item", !IS_ABSTRACT, !IS_INTERFACE);
}
public void removeShippingItem()
{
if (shippingItem != null)
this.eClassifiers.remove(shippingItem);
}
最后,如清单 12 所示,执行 SupplyChainBindingImpl.java 中的 submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder) 方法。该清单演示了如何使用前面创建的方法。
清单 12.执行 submitPurchaseOrder 方法示例public com.example.supplychain.www.PurchaseReferenceType
submitPurchaseOrder(com.example.supplychain.www.PurchaseOrderType purchaseOrder)
throws java.rmi.RemoteException
{
try
{
String customerReference = purchaseOrder.getCustomerReference();
/*
* Converting SOAPElement to PaymentMethodType. The local element
* mapping for paymentMethod is statically registered in the
* initializePackageContents() method of SupplychainPackageImpl.java
*/
PaymentMethodType paymentMethod =
(PaymentMethodType)domElement2EObject(soapElement2DOMElement((
SOAPElement)purchaseOrder.getPaymentMethod()));
/*
* Converting SOAPElement to ItemType. The local element mapping
* for item is dynamically registered and removed using the
* initPurchaseItem() and removePurchaseItem() methods.
*/
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initPurchaseItem();
ItemType item = (ItemType)domElement2EObject(soapElement2DOMElement((
SOAPElement)purchaseOrder.getItem()));
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removePurchaseItem();
ShippingNoticeType shippingNotice = purchaseOrder.getShippingNotice();
String recipient = shippingNotice.getRecipient();
String address = shippingNotice.getAddress();
/*
* Converting SOAPElement to ShippingItemType.
*/
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initShippingItem();
ShippingItemType shippingItem =
(ShippingItemType)domElement2EObject(soapElement2DOMElement((
SOAPElement)shippingNotice.getItem()));
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removeShippingItem();
float height = shippingItem.getHeight();
float length = shippingItem.getLength();
float width = shippingItem.getWidth();
float weight = shippingItem.getWeight();
boolean fragile = shippingItem.isFragile();
float total = 0;
total += item.getQuantity() * item.getPrice();
total += weight;
if (fragile)
total += 100;
ProcessingType processingType =
SupplychainFactory.eINSTANCE.createProcessingType();
StatusType status = SupplychainFactory.eINSTANCE.createStatusType();
status.setProcessing(processingType);
PurchaseReferenceType purchaseReference = new PurchaseReferenceType();
purchaseReference.setReferenceNumber(String.valueOf(Math.abs((
new Random()).nextInt())));
/*
* Converting StatusType to SOAPElement.
*/
purchaseReference.setStatus(domElement2SOAPElement(eObject2DOMElement(status)));
purchaseReference.setTotal(total);
return purchaseReference;
}
catch (Throwable t)
{
t.printStackTrace();
}
return null;
}
测试供应链 Web 服务
您已经完成了供应链 Web 服务。现在使用 Web Services Explorer 对其进行测试。
启动部署了供应链 Web 服务的服务器。打开 server 视图。单击菜单Window > Show View>Other...。展开Server文件夹,然后单击Servers>OK。
在 Servers 视图中,右键单击WebSphere v5.1 Test Environment>Start。
右键单击/SupplyChainWeb/WebContent/wsdl/com/example/supplychain/www/SupplyChainService.wsdl > Web Services>Test with Web Services Explorer启动 Web Services Explorer。
在操作栏中,单击submitPurchaseOrder链接。
输入如表 1 所示的参数值。
表 1.参数值 | |
参数 | 值 |
customerReference | John Doe |
paymentMethod | tns:creditCard |
creditCardType | VISA |
creditCardNumber | 12345-67890 |
expiration | 2004-06-17 |
id | Plasma TV |
description | 42-inch |
quantity | 1 |
price | 3000 |
recipient | John Doe |
address | 123 Fake street |
height | 40 |
width | 25 |
length | 10 |
weight | 60 |
fragile | true |
单击Go调用 submitPurchaseOrder 操作。图 3 显示了调用结果。
图 3.调用 submitPurchaseOrder 操作的结果
查看原图(大图)
结束语
JAX-RPC 定义了一个 XML 到 Java 类型映射的标准模型,但是,该模型还需要为所有的 XML 数据类型提供标准映射。本文演示了如何联合 EMF 和 JAX-RPC 的功能来支持没有标准映射的 XML 数据类型。虽然 EMF 提供了一个解决方案,但是该方法需要用户同时使用两种不同的编程模型。以后,新兴技术服务数据对象 (Service Data Objects) 将会针对该问题提供更好的解决方案。
获取本文中所使用的产品和工具
如果您是一个 developerWorks 订阅者,那么您将具有一个单用户许可证,可以使用 WebSphere Studio Application and Site Developer 和其他的 DB2®、Lotus®、Rational®、Tivoli®,以及 WebSphere® 产品 —— 其中包括基于 Eclipse 的 WebSphere Studio IDE 来开发、测试、评估和演示您的应用程序。
本文示例源代码或素材下载
赞助商链接