kapok

          垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            455 隨筆 :: 0 文章 :: 76 評(píng)論 :: 0 Trackbacks

          簡(jiǎn)介

          盡管WebSphere/WebLogic都是J2EE應(yīng)用服務(wù)器,但是由于J2EE標(biāo)準(zhǔn)本身的原因,以及不同應(yīng)用服務(wù)器提供不盡相同的特性,而程序員在開(kāi)發(fā)應(yīng)用的時(shí)候又沒(méi)有考慮到應(yīng)用要兼容不同應(yīng)用服務(wù)器,這就出現(xiàn)了J2EE應(yīng)用在不同應(yīng)用服務(wù)器上的移植問(wèn)題。

          下面介紹我們?cè)诎袹2EE Web應(yīng)用從WebLogic移植WebSphere應(yīng)用服務(wù)器過(guò)程中遇到的一些問(wèn)題和解決辦法。

          至于更詳細(xì)的系統(tǒng)環(huán)境準(zhǔn)備,移植步驟等細(xì)節(jié),請(qǐng)參考IBM紅皮書(shū),如Migrating WebLogic Applications to WebSphere V5, REDP0448。

          一、Servlet/JSP移植問(wèn)題

          WebSphere 4/5和WebLogic 6.1應(yīng)用服務(wù)器中的JSP編譯器對(duì)于空對(duì)象(null String, null object等)的處理是不同的。

          在Welbogic 6.1當(dāng)中,如果字符串為null,或者對(duì)象為null,那么使用PrintWriter輸出該對(duì)象的時(shí)候,輸出的是長(zhǎng)度為0的字符串"";而在WebSphere 4/5、Tomcat 4.1以及WebLogic 7.0當(dāng)中是輸出了長(zhǎng)度為4的字符串"null"。

          下面servlet/jsp的例子在WebLogic 6.1/WebSphere中的運(yùn)行結(jié)果是截然不同的。

          servlet測(cè)試代碼:

          java.io.PrintWriter out = response.getWriter();
          out.println(null);
          jsp測(cè)試代碼:
          <% String s = null; %>
          <%=s%>
          或者
          <% Integer i = null; %>
          <%=i%>

          解決辦法1:

          所有要在Servlet/JSP輸出的對(duì)象都有初始值,換言之就不會(huì)有輸出空對(duì)象的情況。這樣在servlet/jsp當(dāng)中通過(guò)PrintWriter輸出對(duì)象的時(shí)候就不會(huì)出現(xiàn)"null"字樣。

          解決辦法2:

          如果整個(gè)Web應(yīng)用已經(jīng)編寫(xiě)完畢,沒(méi)有時(shí)間去修改包含業(yè)務(wù)邏輯的代碼,那么可以使用如下的類(lèi)(java class)處理servlet/jsp的輸出。對(duì)于jsp頁(yè)面通常可以通過(guò)手工替換<%=為<%=NullObject.get(,替換%>為)%>。

          package utils;
          public class NullObject {
          public static String get(String o) {
          return (o == null) ? "" : o;
          }
          public static Integer get(Integer o) {
          return (o == null) ? new Integer(0) : o;
          }
          public static Long get(Long o) {
          return (o == null) ? new Long(0) : o;
          }
          public static Object get(Object o) {
          return (o == null) ? "" : o;
          }
          }

          比如jsp代碼片斷<%=s%>可以修改為<%=NullObject.get(s))%>

          注:在Java Language Specification [sec 15.18.1.1 String Conversion]中寫(xiě)到 If the reference is null, it is converted to the string "null" (four ASCII characters n, u, l, l). Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.

          The toString method is defined by the primordial class Object; many classes override it, notably Boolean, Character, Integer, Long, Float, Double, and String.

          二、JNDI移植問(wèn)題

          2.1 上下文工廠(chǎng)

          J2EE程序在訪(fǎng)問(wèn)不同J2EE應(yīng)用服務(wù)器名字空間的時(shí)候,需要指定相應(yīng)服務(wù)器的名字空間上下文的工廠(chǎng)class名稱(chēng),名字空間提供者的URL。

          WebLogic相應(yīng)參數(shù)分別為weblogic.jndi.WLInitialContextFactory和t3://localhost:7001

          WebLogic創(chuàng)建InitialContext的樣例代碼:

          Properties h = new Properties();
          h.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
          h.put(Context.PROVIDER_URL,"t3://localhost:7001");
          InitialContext ctx = new InitialContext(h);

          WebSphere相應(yīng)參數(shù)分別為com.ibm.websphere.naming.WsnInitialContextFactory和iiop://localhost:2809/

          WebSphere創(chuàng)建InitialContext的樣例代碼:

          Properties h = new Properties();
          h.put(Context.INITIAL_CONTEXT_FACTORY,
          " com.ibm.websphere.naming.WsnInitialContextFactory ");
          h.put(Context.PROVIDER_URL,"iiop://localhost:2809/");
          InitialContext ctx = new InitialContext(h);

          如果是訪(fǎng)問(wèn)本地應(yīng)用服務(wù)器,可以采用缺省配置創(chuàng)建名字空間上下文,代碼如下:

          InitialContext ctx = new InitialContext();

          推薦應(yīng)用程序采用共同的類(lèi)訪(fǎng)問(wèn)JNDI名字空間,比如com.xxx.utils.Xxx,該類(lèi)是singleton的,提供static方法來(lái)獲得名字空間上下文。這樣做的好處是

          應(yīng)用中訪(fǎng)問(wèn)名字空間的代碼都在這個(gè)類(lèi)中,應(yīng)用程序的移植性好
          采用singleton設(shè)計(jì)模式和static方法,可以減少對(duì)象的重復(fù)生成,減少JVM的垃圾回收
          2.2 java.user.Transaction

          在WebLogic 6.1中,javax.transaction.UserTransaction是通過(guò)名字javax.transaction.UserTransaction查找到的,而WebSphere 5中是通過(guò)名字jta/usertransaction查找到的。

          WebLogic例子代碼如下:

          import javax.transaction.UserTransaction;
          (UserTransaction)getInitialContext().lookup("javax.transaction.UserTransaction");
          WebSphere例子代碼如下:
          (UserTransaction)getInitialContext().lookup("jta/usertransaction")

          三、EJB訪(fǎng)問(wèn)

          EJB 1.0,java程序使用EJB部署后的JNDI名稱(chēng)訪(fǎng)問(wèn)EJB的例子代碼如下:

          InitialContext ctx = new InitialContext();
          Object home = ctx.lookup("ejb/account");
          AccountHome accountHome =
          (AccountHome) PortableRemoteObject.narrow(home, AccountHome.class);

          EJB 1.1引入了EJB Refrence,java程序訪(fǎng)問(wèn)EJB的例子代碼如下:

          InitialContext ctx = new InitialContext();
          Object home = ctx.lookup("java:comp/env/ejb/account");
          AccountHome accountHome =
          (AccountHome) PortableRemoteObject.narrow(home, AccountHome.class);

          在EJB 2.0,引入了EJB local home interface,從此java客戶(hù)程序可以通過(guò)引用調(diào)用在一個(gè)JVM中的EJB。EJB Refrence,java程序訪(fǎng)問(wèn)EJB的例子代碼如下:

          InitialContext ctx = new InitialContext();
          Object home = ctx.lookup("java:comp/env/ejb/account");
          AccountHome accountHome = (AccountHome) home;

          強(qiáng)烈推薦使用EJB Reference訪(fǎng)問(wèn)EJB,使用EJB Refrence訪(fǎng)問(wèn)EJB有很多好處。在程序移植方面,各種應(yīng)用服務(wù)器對(duì)local home的EJB在名字空間中部署是不一樣的,但是都可以通過(guò)EJB Refrence訪(fǎng)問(wèn)到local home的EJB。

          在WebLogic 6.1中,可以在EJB部署描述文件weblogic-ejb-jar.xml 中定義具有Local Home 的EJB的local jndi name。類(lèi)如下面的部署描述符指定了具有l(wèi)ocal home的EJB Account的local jndi name為ejb/account,具有remote home的EJB AccountAccess的jndi name為ejb/accountaccess。

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN'
          'http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd'>
          <weblogic-ejb-jar>
              <weblogic-enterprise-bean>
                  <ejb-name>Account</ejb-name>
                  <local-jndi-name>ejb/account</local-jndi-name>
          </weblogic-enterprise-bean>
              <weblogic-enterprise-bean>
                  <ejb-name>AccountAccess</ejb-name>
                  <jndi-name>ejb/accountaccess</jndi-name>
              </weblogic-enterprise-bean>
          </weblogic-ejb-jar>

          在WebLogic中,java代碼中使用EJB部署后的JNDI名稱(chēng)訪(fǎng)問(wèn)local home/remote home的EJB例子代碼如下:

          Properties h = new Properties();
          h.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
          h.put(Context.PROVIDER_URL,"t3://localhost:7001");
          InitialContext ctx = new InitialContext(h);
          AccountHome accountHome = (AccountHome) ctx.lookup("ejb/account");
          AccountAccessHome accountAccessHome = (AccountAccessHome) ctx.lookup("ejb/accountaccess");

          在WebSphere 5中,java代碼中使用EJB部署后的JNDI名稱(chēng)訪(fǎng)問(wèn)local home/remote home的EJB例子代碼如下:

          InitialContext ctx = new InitialContext();
          Context ctx_local = (Context) ctx.lookup("local:");
          AccountHome accountHome = (AccountHome) ctx.lookup("ejb/" + "ejb/account");
          AccountAccessHome accountAccessHome = (AccountAccessHome) ctx.lookup("ejb/accountaccess");

          四、安全

          4.1 在Web Application中,用戶(hù)使用Form方式登錄后無(wú)權(quán)訪(fǎng)問(wèn)資源

          如果一個(gè)用戶(hù)經(jīng)過(guò)用戶(hù)身份驗(yàn)證(J2EE form based authentication)為合法用戶(hù),但是該用戶(hù)試圖訪(fǎng)問(wèn)其無(wú)權(quán)訪(fǎng)問(wèn)的Web資源,WebLogic 6.1將返回給客戶(hù)該Web應(yīng)用的登陸頁(yè)面(比如login.jsp),而WebSphere 5.0將返回一個(gè)403的HTTP code給瀏覽器,在IE瀏覽器中將顯示 "You are not authorized to view this page...",或者"Error 403: AuthorizationFailed"(如果IE沒(méi)有打開(kāi)缺省選項(xiàng)"顯示友好HTTP錯(cuò)誤消息")。 J2EE form-based authentication的例子配置(web.xml片斷):

          <login-config>
          <auth-method>FORM</auth-method>
          <realm-name>basicrealm</realm-name>
          <form-login-config>
          <form-login-page>/login.jsp</form-login-page>
          <form-error-page>/failedlogin.jsp</form-error-page>
          </form-login-config>
          </login-config>

          解決辦法:

          在WEB-INF\web.xml文件中加入error-page指令,如果出現(xiàn)403錯(cuò)誤,那么WebSphere將告訴瀏覽器出現(xiàn)403錯(cuò)誤,同時(shí)返回/failedlogin.jsp頁(yè)面給瀏覽器。

          <error-page>
          <error-code>403</error-code>
          <location>/failedlogin.jsp</location>
          </error-page>

          需要注意的是:IE缺省配置中打開(kāi)了"顯示友好HTTP錯(cuò)誤消息",如果web.xml文件中eror-page指定的頁(yè)面的內(nèi)容小于500個(gè)字節(jié),那么IE將忽略服務(wù)器返回的頁(yè)面,而"顯示友好HTTP錯(cuò)誤消息",即顯示"You are not authorized to view this page..."。

          4.2 HttpServletRequest.getRemoteUser()

          在WebLogic 6.1中,用戶(hù)使用J2EE Form方式登陸以后,可以在任何servlet/jsp當(dāng)中使用HttpServletRequest對(duì)象的getRemoteUser()方法獲得登錄用戶(hù)的ID;而在WebSphere 5.0中只能在受保護(hù)的資源(servlet/jsp)當(dāng)中使用這個(gè)Servlet API獲得登錄用戶(hù)的ID,而且要求被授權(quán)訪(fǎng)問(wèn)該資源的安全性角色(J2EE Role)在WebSphere中不能被映射為"每個(gè)用戶(hù)"(everyone)。注:在WebSphere 5中,每個(gè)安全性角色可以被映射為"每個(gè)用戶(hù)"(everyone), "所有已認(rèn)證的用戶(hù)"(all authenticated), "映射的用戶(hù)"(mapped users),"映射的組" (mapped groups)。

          4.3 Webloigic LDAP Realm的移植

          WebLogic提供了Realm API,java程序可以調(diào)用該API進(jìn)行用戶(hù)的管理、組的管理。 SPC LDAP Realm API具有和WebLogic Realm相似的API代碼,在調(diào)用weblogic.security.acl.CachingRealm的java代碼中,把中weblogic.security替換為spc即可。

                        if(WebLogic) {
                           weblogic.security.acl.CachingRealm realm = (weblogic.security.acl.CachingRealm)
                                   weblogic.security.acl.Security.getRealm();
                           weblogic.security.acl.User u = realm.newUser(clientId,password,null);
                           realm.getGroup("AdminGroup").addMember(u);

                           int ret = weblogic.servlet.security.ServletAuthentication.weak
                                    (clientId,password,session);
                           if (ret != weblogic.servlet.security.ServletAuthentication.AUTHENTICATED){
                               System.out.print("Login failed!");
                           }
                       }
                      else {
                          spc.acl.CachingRealm realm = (spc.acl.CachingRealm)
                                   spc.acl.Security.getRealm();
                          spc.acl.User u = realm.newUser(clientId,password,null);
                          realm.getGroup("HauiGroup").addMember(u);
                 try {
          LoginContext lc =
          new LoginContext("WSLogin",
          newcom.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl(clientId,
          "realm", password));
          lc.login();
          lc.logout();
          } catch (LoginException le) {
          System.out.print("Login failed!");
                                  return;
                                  //throw new InvalidClientIdException(le.toString());
          }
                   }

          spc.acl.LdapRealm程序中一些參數(shù)最好在以后的版本當(dāng)中修改為從配置文件中讀取。

          //LDAP服務(wù)器的IP或者HOSTNAME
          String LDAPSERVER = "192.168.1.30";
          //搜索用戶(hù)的開(kāi)始節(jié)點(diǎn)
          String USER_DN_BASE = "cn=users,dc=xxx,dc=com";
          String USER_DN_BASE = "dc=xxx,dc=com";
          //搜索組的開(kāi)始節(jié)點(diǎn)
          String GROUP_DN_BASE = "cn=groups,dc=xxx,dc=com";
          String GROUP_DN_BASE = "dc=xxx,dc=com";
          // com.ibm.jndi.LDAPCtxFactory = IBM SecureWay
          //C:\Program Files\IBM\LDAP\java\ibmjndi.jar
          // com.sun.jndi.ldap.LdapCtxFactory = Any Version 3 compliant LDAP
          String FACTORY_INITIAL = "com.ibm.jndi.LDAPCtxFactory";
          //登陸目錄服務(wù)器的有管理員權(quán)限的用戶(hù)名稱(chēng)
          String SECURITY_PRINCIPAL = "cn=root";
          //登陸目錄服務(wù)器的有管理員權(quán)限的用戶(hù)口令
          String CREDENTIALS = "root";

          4.4 將servlet中使用WebLogic Security API的代碼改為WebSphere Security API。

          注意:WebLogic API weblogic.servlet.security.ServletAuthentication.weak是讓瀏覽器用戶(hù)登陸到WebLogic服務(wù)器上, 而com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl/LoginContext.login是讓用戶(hù)在java程序(包含servlet)中登陸到服務(wù)器上。在下面的代碼中,WebSphere API只是起到了驗(yàn)證增加的用戶(hù)是否能夠登陸到WebSphere應(yīng)用服務(wù)器上。

          4.5 WebSphere 5 User Registry

          WebLogic/WebSphere都支持將LDAP服務(wù)器中的用戶(hù)和J2EE角色之間的綁定,都支持定制用戶(hù)注冊(cè)表,比如兩者在產(chǎn)品中都提供了基于文件的用戶(hù)注冊(cè)表。

          WebLogic提供了RDBMS Realm的example實(shí)現(xiàn),該實(shí)現(xiàn)采用數(shù)據(jù)庫(kù)的兩個(gè)表來(lái)保存用戶(hù)和組的信息,表的定義如下:


          CREATE TABLE aclentries (A_NAME varchar(255), A_PRINCIPAL varchar(255), A_PERMISSION varchar(255));
          CREATE TABLE groupmembers(GM_GROUP varchar(255), GM_MEMBER varchar(255));
          WebSphere 5 Security redbook中提供了基于RDBMS User Registry的實(shí)現(xiàn),表的定義如下:
          create table users(username varchar2(250), password  varchar2(250), description varchar2(250), userid varchar(250));
          create table groups(name varchar2(250), description varchar2(250), gid varchar2(250));
          create table uidgid(gid varchar2(250), userid varchar2(250));

          附件中的WebSphere RDBMS User Registry在兩方面進(jìn)行了修改:

          支持JDBC數(shù)據(jù)庫(kù)連接池。WebSphere Security/User
          Registry是在WebSphere其他服務(wù)啟動(dòng)之前啟動(dòng)的,因此在WebSphere數(shù)據(jù)庫(kù)連接池/名字服務(wù)器啟動(dòng)之前,User Registry不能使用數(shù)據(jù)庫(kù)連接池,但之后就可以使用數(shù)據(jù)庫(kù)連接池了。
          將SQL語(yǔ)句作為static常量定義,便于修改數(shù)據(jù)庫(kù)的表設(shè)計(jì)。
          這個(gè)RDBMS User Registry在部署的時(shí)候需要配置四個(gè)參數(shù):

          DBDRIVER:比如COM.ibm.db2.jdbc.app.DB2Driver
          DBURL:比如java:db2:sample
          DBUSERNAME:比如db2admin
          DBPASSWORD:比如db2admin
          JDBCJNDINAME:比如jdbc/sample


          posted on 2005-03-12 16:14 笨笨 閱讀(1167) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): J2EEALL
          主站蜘蛛池模板: 兴山县| 巴林右旗| 江西省| 保靖县| 旬阳县| 射洪县| 金湖县| 菏泽市| 黄平县| 普洱| 林甸县| 郁南县| 芦山县| 大埔县| 湛江市| 民县| 兰考县| 大庆市| 大厂| 视频| 平果县| 响水县| 乌拉特中旗| 遵义市| 庆安县| 错那县| 汝城县| 富裕县| 类乌齐县| 磐石市| 定结县| 卢龙县| 安仁县| 白玉县| 鄂尔多斯市| 焉耆| 荆州市| 临夏市| 昌宁县| 曲松县| 古蔺县|