Unmanaged Thread Problem - WebSphere Compliant Spring Task Schedulers - (JNDI Context problems)

Problems Summary
  1. Spring creates a separate threads to handle schedulers , but most of J2EE container vendors like websphere , weblogic ..etc doesn't support the threads created outside of containers. (These are threads called unmanaged threads)
  2. Following exception was thrown when we try to lookup the objects directly using javax.naming.initialContext . (We have JAX-RPC webservices client code that is generated by RAD using WSDL , which is auto generated code has the direct initial context lookups)

Exception Occured
  javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component.  This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request.  Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application.  Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name "com/env/url/testrouce"

Explanation and solution

IBM clearly states that don't create unmanaged threads (this is true with most of J2EE container vendors), for the following reasons:
  1. The application server does not recognize unmanaged threads.
  2. Unmanaged threads do not have access to Java EE contextual information.
  3. Unmanaged threads can use resources without being monitored by the application server.
  4. Unmanaged threads can adversely affect application server functions such as shutting down gracefully or recovering resources from failure.
  5. An administrator cannot control the number of unmanaged threads or their use of resources.



Spring Framework Support
Spring framework does provide a package with scheduling classes based on CommonJ WorkManager/TimerManager that supported by IBM Websphere 6.0+ and BEA weblogic 9.0+.  Spring Commonj classes link is provided in references section.


Steps to create websphere compliant task scheduler
  1. Create a task (That implements the runnable interface)
  2. Add the Websphere timer Manager reference in the web.xml and ibm-web-bnd.xmi
  3. Configure task at specific intervals in the SpringContext.xml


Step1: Create task
public class TestTask implements Runnable {
public void run() {
//your work to be executed        
}
}

Step 2: add websphere timer manager references in project

In Web.xml
<resource-ref>
<description>TimerManager</description >
<res-ref-name>timerManager</res-ref-name >
<res-type>commonj.timers.TimerManager</res-type >
<res-auth>Container</res-auth >
<res-sharing-scope>Unshareable</res-sharing-scope >
</resource-ref>

in ibm-web-bnd.xml
<resource-ref name="timerManager" binding-name="tm/default" ></resource-ref>

Step 3: configure scheduler

<bean id="testTask" class="com.sivavaka.test.spring.scheduler.TestTask">
</bean>        

<bean id= "timerScheduler" class="org.springframework.scheduling.commonj.TimerManagerTaskScheduler" >
      <property name="resourceRef" value="true"/>
      <property name="timerManagerName" value="timerManager"/>
</bean>

<!-- To schedule job for every one hour then cron will be "0 0 0/1 * * ?" -->
<!-- Websphere Compliant Thread :: Runs for every 5 mins -->         
<task:scheduled-tasks scheduler="timerScheduler" >
      <task:scheduled ref="testTask" method="run" cron="0 0/5 * * * ?" />
</task:scheduled-tasks >


If you create the scheduler like above , you can see the WebSphere Runtime available to thread that executes this task , basically it is WebSphere managed thread
  

But if you use the Spring's task scheduler directly (I mean without using the websphere timemanager), thread that executes this task doesn't have access the Websphere Runtime causing the J2EE container services are not available.




References
  1. http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/info/ae/ae/cspr_design.html
  2. Workmanagers (http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/info/ae/asyncbns/concepts/casb_workmgr.html)
  3. http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/scheduling/commonj/package-summary.html


Download/Browse the Sample Code

  1. To download sample code war file  (https://sourceforge.net/projects/blog-sivavaka-com-code-samples/files/WebSphere%20Compliant%20Spring%20Task%20Scheduler/)
  2. To browser the sample code (https://code.google.com/p/blog-sivavaka-com-code-samples/source/browse/#svn%2Ftrunk%2FSivaTestSpringScheduler)

Multiple RAD workspaces - using single WAS profile vs multiple profiles

Sharing the Same WAS profile across the multiple RAD workspaces

Same WAS profile can be shared across the multiple RAD workspaces because profile is part of the WebSphere Application Server (or WAS Test Environment ). Sharing of the same WAS profile between the different workspaces is not recommended unless there is only one active workspace at any time.

Following things need to consider when sharing the profile
  1. Avoid making the changes to same application in different workspaces
  2. Only one workspace is allowed to debug at a given time

It always better to create different WAS profile for each workspace if you are working on same applications (e.g. same code base but parallel development branches or streams). Followings steps makes easy to bring your new workspace with all configurations from your old workspace (workspace preferences and profile configurations).

  1. Restoring the workspace preferences
    1. Export the workspace preferences, i.e any custom workspace preferences that you have configured (like console limit, validations …etc)
From the RAD File Menu --> Export --> Preferences




  1. From the new workspace, import the workspace preferences that you have exported in previous step
From the RAD File Menu --> Import --> Preferences

  1. Restoring the profile configurations
    1. Export the server profile configuration from the old workspace
give workspace folder location to save configuration car file

  1. This car file contains all configurations like Datasources, Security related config (JAAS auth ..etc) , JVM properties , shared libraries, deployed applications …etc. Its basically snapshot of all config for that profile.
  2. In the new workspace,
    1. create new WAS profile (for 32-bit Operating systems you can use the Profile Management Tool in the RAD and for 64-bit operating systems you can use the "interactive profile management tool" as described in this article)
    2. Once the profile is created , add that profile to new workspace
      1. Click "new" in servers view
      2. Select "Server Type" and "Server Runtime" and click next
      3. Select new profile that is created in above step
  1. click next to add any applications in workspace to server.
  1. Once the profile is added to workspace , right click on the server profile and restore the old profile configuration (you may need to copy the .car file that exported from the old profile to this workspace folder ).

  1. Start the server after successful restore, Now you should see all configuration from old profile here.
Ref:
http://blog.sivavaka.com/2013/10/using-manage-profiles-interactive-tool.html

Using the "Manage Profiles Interactive" tool to manage websphere profiles in 64-bit operating systems

IBM doesn't support the manageprofiles (Profile Management) GUI or wizard in 64-bit operating systems but recently IBM has posted "Manage Profiles Interactive" tool to simplify profile creation process in 64-bit operating systems.

You can download the manageprofilesInteractive.zip from the following link (it also has flash demonstration on how to execute it)

  1. Extract  manageprofilesInteractive.zip to /AppServer/bin
  1. Execute the command "WebSphere\AppServer\bin>run_manageprofilesInteractive.bat"


  1. It created the "AppSrv01" profile successfully.





Reference

JSR286 Spring Portlet Sample Code (Skeleton)

1. Create the portlet project using the RAD (by selecting the JSR 286 with empty portlet)
2. Add spring framework jars to /WEB-INF/lib directory

log4j-1.2.16.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context.support-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.orm-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web.portlet-3.0.5.RELEASE.jar
org.springframework.web.servlet-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar

3. In web.xml , Add Spring context listner

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/SivaTestSpringPortlet-Context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>

4.  In portlet.xml, update the portlet classname, contextConfigLocation

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" id="com.sivavaka.test.springportlet.SivaTestSpringPortlet.58abb9cd14">
<portlet>
<portlet-name>SivaTestSpringPortlet</portlet-name>
<display-name xml:lang="en">SivaTestSpringPortlet</display-name>
<display-name>SivaTestSpringPortlet</display-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/SivaTestSpringPortlet-Portlet.xml</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
<portlet-mode>help</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>com.sivavaka.test.springportlet.nl.SivaTestSpringPortletResource</resource-bundle>
<portlet-info>
<title>SivaTestSpringPortlet</title>
<short-title>SivaTestSpringPortlet</short-title>
<keywords>SivaTestSpringPortlet</keywords>
</portlet-info>
</portlet>
<default-namespace>http://SivaTestSpringPortlet/</default-namespace>
</portlet-app>

NOTE:  Spring portlet framework looks for [Portlet-Name]-Portlet.xml by default for if we don't specify "contextConfigLocation" in the initparam.


5. Add the SivaTestReport-Portlet.xml file with following

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="

<context:annotation-config />

<!-- Controller -->
<context:component-scan base-package="com.sivavaka.test.springportlet"/>

</beans>

6. Add the SivaTestReport-Cotext.xml file with following

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="

<context:annotation-config/>

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="false" />
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>com.sivavaka.test.springportlet.nl.SivaTestSpringPortletResource</value>
</property>
</bean>

</beans>

7. Write controller to handle the view requests

package com.sivavaka.test.springportlet.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("VIEW")
public class SivaTestSpringPortletController {

@RequestMapping
public String displayView(){
return "view";
}
}

8. write view jsp

<%@page
       language="java" contentType= "text/html; charset=ISO-8859-1"
       pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %><portlet:defineObjects />
<p> View JSP.</p >

Sample code

  1. Browse Code ::: https://code.google.com/p/blog-sivavaka-com-code-samples/source/browse/#svn%2Ftrunk%2FSivaTestSpringPortlet
  2. Download War File ::: http://sourceforge.net/projects/blog-sivavaka-com-code-samples/files/Spring%20JSR%20Portlet/