Monday, November 15, 2010

troubleshooting procedure for Spring + Hessian

1) How to get HttpServletRequest object so as to call getRemoteAddr()


There is a request from client to restrict a limit of machines' IPs to access the web service developed by spring and hessian.
Definitely, There is no out-of-the-box function for Spring or Hessian to open HttpServletRequest to use.
Some smart guys have found some ways to resolve this problem.


Solution 1) modify the Hessian source code
refer to http://www.blogjava.net/Caixiaopig/archive/2007/08/03/134287.aspx


Solution 2) develop a customized HessianExporter
refer to http://wesee.javaeye.com/blog/663876


I prefer the second solution.


// HessianContext.java
package com.spring.hessian.test.exporter;

import javax.servlet.ServletRequest;

public class HessianContext {
    private ServletRequest _request;
    private static final ThreadLocal<HessianContext> _localContext = new ThreadLocal<HessianContext>() {

        public HessianContext initialValue() {
            return new HessianContext();
        }
    };

    private HessianContext() {
    }

    public static void setRequest(ServletRequest request) {
        _localContext.get()._request = request;
    }

    public static ServletRequest getRequest() {
        return _localContext.get()._request;
    }

    public static void clear() {
        _localContext.get()._request = null;
    }
}


// customized Hessian Exporter
package com.spring.hessian.test.exporter;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.remoting.caucho.HessianExporter;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.util.NestedServletException;

public class MyExporter extends HessianExporter implements HttpRequestHandler {

    @Override
    public void handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        if (!"POST".equals(request.getMethod())) {
            throw new HttpRequestMethodNotSupportedException(request
                    .getMethod(), new String[] { "POST" },
                    "HessianServiceExporter only supports POST requests");
        }

        response.setContentType(CONTENT_TYPE_HESSIAN);
        try {
           
            String clientIp = request.getRemoteAddr();
            System.out.println("----------->>> "+clientIp);
           
            if (!clientIp.equalsIgnoreCase("10.12.103.118")){
                throw new Exception("Invalid IP-----------------------");
            }
           
            HessianContext.setRequest(request);
            invoke(request.getInputStream(), response.getOutputStream());
        } catch (Throwable ex) {
             throw e;
        } finally {
            HessianContext.clear();
        }

    }
}
// your <servlet-name>-servlet.xml
 take note the class name in red, should put your customized hessian exporter class,not standard one
<bean name="/onepassService"
        class="com.spring.hessian.test.exporter.MyExporter">
        <property name="service" ref="accountInfoImpl" />
        <property name="serviceInterface" value="com.spring.hessian.test.IAccountInfo" />
 </bean>


I wonder how this guy worked it out !  :-(


2) can not get Spring Bean if using auto classpath scan

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
      http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="order" value="1" />
    </bean>

    <bean
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="defaultHandler" ref="httpRequestHandlerAdapter" />
        <property name="order" value="2" />
    </bean>

    <bean id="httpRequestHandlerAdapter"
        class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />

    <context:component-scan base-package="com.spring.hessian.test" />

</beans>

The three beans definition are required, otherwise, NullPointerException will occur due to system can not find the spring beans if adopting annotation to define spring bean.

3) setup SSL connection

3.1 generate keystore


keytool -genkeypair -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -validity 36000 -storepass changeit -alias myalias -keystore my.keystore -dname "CN=localhost,OU=mycomp,O=mycomp,L=SG,ST=SG,C=SG"


TAKE NOTE: set the value of CN carefully. if set CN=myhost, the URL of hessian servlet would be
https://myhost:port/xxxxxxxx


3.2 configure SSL connection in tomcat


edit %tomcat%/conf/server.xml and add following configuration


<Connector port="8843" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="C:/tmp/my.keystore" keystorePass="changeit" />


3.3 export cert for client side


keytool -exportcert -alias myalias -keystore my.keystore -file my.pem -rfc -storepass changeit


3.4 import cert to client's trust store


keytool -import -trustcacerts  -alias mycert_tomcat -file c:\tmp\my.pem  -keystore  cacerts


3.5 client caller source code


package com.spring.hessian.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.caucho.hessian.client.HessianProxyFactory;

public class HessianTester {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() throws Exception {
        System.setProperty("java.protocol.handler.pkgs", "javax.net.ssl");
        System.setProperty("javax.net.ssl.trustStore", "C:\\tmp\\cacerts");
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
     
         String url = "https://localhost:8843/springhessian/remote/myService";
        HessianProxyFactory factory = new HessianProxyFactory();
        IAccountInfo accountInfo = (IAccountInfo) factory.create(
                IAccountInfo.class, url);

        accountInfo.changeEmail(126, "def@email.com");
        accountInfo.deleteAccount(129);
    }
}


take note the property in red, previously, I set it as keyStore and always got the exception as follows.


Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    ... 38 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 44 more

Monday, November 8, 2010

Spring v3.0.2 Learning Note 16 (Cont.)- Resolve NullPointerException on weblogic v10.3

In this article http://wangxiangblog.blogspot.com/2010/10/spring-v302-learning-note-16-integrate.html, I mentioned that NullPointerException occured if deployed hessian project to weblogic v10.3

After seach oracle website, found the info as follows
---------------------------------------------------------------------------------------------------
After some research on the stack trace, I found the reason for this error is Hession Spring servlet closes the input stream explicitly. While when WLS' reclaiming the connection for reuse(keep-alive) purpose, it tries to read the input stream to clear unread chunks. NPE happens here as input stream has been closed.

There is an existing bug on this: Bug 8183755. Patches are available for bug  8183755:

------------------------------------------
    PATCH REPOSITORY INFORMATION
------------------------------------------
 WLS Version | Patch ID |  Passcode
--------------+----------+----------------
    9.2 GA   |   K75X   | K3EB5V7M
    9.2 MP1  |   H67L   | HZYJQECN
    9.2 MP2  |   T4HG   | MJ95CPML
    9.2 MP3  |   RZCZ   | M3IEQWIP
    10.0MP1  |   2JNU   | HX9YYCA7
    10.3 GA  |   2UZ1   | I74ATQ1X

Fixed in: 10.3.1

To apply one of these patches, download the patch using Smart Update and apply: see Note  885851.1 for step-by-step instructions. If your target system is offline, please refer to Note  876004.1 for additional assistance. All the details about SmartUpdate are available in the SmartUpdate  documentation.

Patches are specifically tied to a particular release and maintenance  pack of WebLogic Server (WLS). A patch for WLS 9.2.2, for example, very  likely would not work on WLS 9.2.3. In a few cases, patches are also specific to particular operating systems. If you think you are experiencing the problem outlined in this note, but your WLS version is not included in the list of patches provided here, please contact support and ask for a version of the patch appropriate for you. Please reference this note as well as this bug number to help speed our service  for you.
----------------------------------------------------------------------------------------------------

The following commands are used to apply the patch on weblogic v10.3.
Before running these commands, need to copy 2UZ1.jar and patch-catalog.xml to folder D:\bea\utils\bsu\cache_dir

//// view the patch info
D:\bea\utils\bsu>bsu -prod_dir=D:\bea\wlserver_10.3 -patch_download_dir=D:\bea\utils\bsu\cache_dir -status=downloaded -view -verbose
ProductName:       WebLogic Server
ProductVersion:    10.3
Components:        WebLogic Server/Core Application Server,WebLogic Server/Admi
                   nistration Console,WebLogic Server/Configuration Wizard and
                   Upgrade Framework,WebLogic Server/Web 2.0 HTTP Pub-Sub Serve
                   r,WebLogic Server/WebLogic JDBC Drivers,WebLogic Server/Thir
                   d Party JDBC Drivers,WebLogic Server/WebLogic Server Clients
                   ,WebLogic Server/WebLogic Web Server Plugins,WebLogic Server
                   /UDDI and Xquery Support,WebLogic Server/Server Examples,Web
                   Logic Server/Evaluation Database,WebLogic Server/Workshop Co
                   de Completion Support
BEAHome:           D:\bea
ProductHome:       D:\bea\wlserver_10.3
PatchSystemDir:    D:\bea\utils\bsu
PatchDir:          D:\bea\patch_wls1030
Profile:           Default
DownloadDir:       D:\bea\utils\bsu\cache_dir
JavaHome:          D:\bea\jdk160_05
JavaVersion:       1.6.0_05
JavaVendor:        Sun


Patch ID:          2UZ1
PatchContainer:    2UZ1.jar
Checksum:          -2128224792
Severity:          optional
Category:          Web App
CR:                CR371433,CR385319
Restart:           true
Description:       Fixed NPE when ServletInputStream is closed explicitly.

//// apply the patch
D:\bea\utils\bsu>bsu -prod_dir=D:\bea\wlserver_10.3 -patchlist=2UZ1 -verbose -install
Checking for conflicts..
No conflict(s) detected

Starting installation of Patch ID: 2UZ1
Installing D:\bea\utils\bsu\cache_dir\2UZ1.jar
Extracting D:\bea\patch_wls1030\patch_jars\CR371433_1030ga.jar
Updating D:\bea\patch_wls1030\profiles\default\sys_manifest_classpath\weblogic_patch.jar
Old manifest value: Class-Path=
New manifest value: Class-Path=../../../patch_jars/CR371433_1030ga.jar
Result: Success

///// verify the patch
D:\bea\utils\bsu>bsu -prod_dir=D:\bea\wlserver_10.3 -status=applied -view -verbose
ProductName:       WebLogic Server
ProductVersion:    10.3
Components:        WebLogic Server/Core Application Server,WebLogic Server/Admi
                   nistration Console,WebLogic Server/Configuration Wizard and
                   Upgrade Framework,WebLogic Server/Web 2.0 HTTP Pub-Sub Serve
                   r,WebLogic Server/WebLogic JDBC Drivers,WebLogic Server/Thir
                   d Party JDBC Drivers,WebLogic Server/WebLogic Server Clients
                   ,WebLogic Server/WebLogic Web Server Plugins,WebLogic Server
                   /UDDI and Xquery Support,WebLogic Server/Server Examples,Web
                   Logic Server/Evaluation Database,WebLogic Server/Workshop Co
                   de Completion Support
BEAHome:           D:\bea
ProductHome:       D:\bea\wlserver_10.3
PatchSystemDir:    D:\bea\utils\bsu
PatchDir:          D:\bea\patch_wls1030
Profile:           Default
DownloadDir:       D:\bea\utils\bsu\cache_dir
JavaHome:          D:\bea\jdk160_05
JavaVersion:       1.6.0_05
JavaVendor:        Sun


Patch ID:          2UZ1
PatchContainer:    2UZ1.jar
Checksum:          -2128224792
Severity:          optional
Category:          Web App
CR:                CR371433,CR385319
Restart:           true
Description:       Fixed NPE when ServletInputStream is closed explicitly.