Skip to Content

Introduction


In my first blog I have described how to utilize TimeoutService to schedule a periodical task running on WAS in a background. The unit responsible for initializing of TimeoutService was a J2EE servlet.

In this blog I will show how TimeoutService can help to resolve very common issue – exchange structured parameters between different components (WD-J2EE, WD-WD etc.). The problem is that there is no other scope in WD world rather than scope of WD component. So, you can store state of your component only in context (you can store it in class variables of controllers but it is bad practice which should be avoided). After some investigation of SDN forum, I have figured out that there is still no solution how to pass structured objects between components except using non-public WD API:

I will try to build a custom SAP J2EE WAS service which would be responsible for storing and fetching structured objects. Some remarks:

Building of custom services is described not really detailed on help.sap.com: Developing Services . I will try to describe procedure step-by-step using different useful features like properties loading, server event subscription, using of other services.

According to execute java code when server starts?:
Custom services development is not supported on Web AS (see SAP Note 822542).
From Note 822542:
+
Solution
     SAP Web AS Java does not support custom development of services. Should you need to do so, which is in general not recommended by SAP, contact SAP for consulting services.
+
May be SAP employee can do free “consulting service” at the end of this blog by comments 🙂

And as result of SDN RSS Feeds spider using WAS Timeout Service I got a link to document Timeout Service saying that
This service is only used internally by the J2EE Engine. (BTW, it is not saying anything about that we can not use it for our purposes 🙂 ).

In spite of all those warnings and disclaimers I will try to build a custom service and use a TimeoutService inside. TimoutService will run periodically and delete expired object from service. Service is responsible for object storing, generating of unique object key and fetching previously stored object by key. We will implement loading of properties describing service behavior like synchronization period and expiration time of object, handling events occurring on server when properties are changed.


Structure and DC`s


For the solution we will create 6 DC`s:

    1. icp/javabean – JavaDC. Contains a class for JavaBean (structured object). Have 2 public parts: api (Purpose – compilation), package (Purpose – assembly) which contain only one java class – com.sap.sdn.icp.bean.Employee;
    2. icp/serviceimpl – Java DC. Contains custom service implementation. Have 2 public parts: api (Purpose – compilation) contains only one service interface (com.sap.sdn.icp.service.InterComponentParameterService), serviceimpl (Purpose – assembly) contains service implementation itself (package com.sap.sdn.icp.service.*);
    3. icp/wd – Web Dynpro DC. Contains WD component, model and application which store structured data (JavaBean model object based on com.sap.sdn.icp.bean.Employee class) in service layer. Uses icp/javabean->api and icp/serviceimpl->api public parts;
    4. icp/web – Web Module DC. Contains a servlet implementation which is acting as consumer of stored structured object. Have 1 public part: war (Purpose – assembly). Uses icp/javabean->api and icp/serviceimpl->api public parts;
    5. icp/ear – Enterprise Application DC. Uses icp/web->war and icp/javabean->package public parts;
    6. icp/service – J2EE Service Component Service DC. Contains service descriptors. Uses icp/ serviceimpl-> serviceimpl public part.


Java DC icp/javabean


icp/javabean DC is very simple and contains only one JavaBean class with 2 properties (firstName and lastName). We will use this class to generate JavaBean model for our WD DC and to cast fetched object from service in Web Module DC. The reason to have structured object in a separate DC is just to decouple a UI DC`s (wd and web) from data DC (javabean). In your project you can easily include description of structured object in any other DC. The only critical point here is that all components involved to an integration scenario should have a reference to the component which contains description of structured object (except same components which are packaged together).


Java DC for JavaBean
 


Java DC icp/serviceimpl


It is the most important part of our infrastructure. To use TimeoutManager and TimeoutListener interfaces we need to add public part from appropriate DC. It is

”SAP-J2E”->”com.sap.engine.client.lib”</b>.</p>


Service implementation DC 
 

Service implementation component consists of:

    1. Service interface which contains all service methods:

      public interface InterComponentParameterService {
      public abstract Object getObject(final String key);
      public abstract String setObject(final Object value);
      }

       

      This is an entry point to the service and therefore it is exposed via api public part (Purpose – compilation).

    2. Implementation of service InterComponentParameterServiceImpl and implementation of service frame InterComponentParameterServiceFrame which is responsible for interaction with J2EE server.
      Implementation of service registers a timeout event listener for removing expired data objects and initializes data container for objects. TimeoutListener iterates periodically through a data container and removes expired objects:

      public class ParameterTimeoutListsner implements TimeoutListener {
      public void timeout() {
      Collection values = _values.entrySet();
      for (Iterator iter = values.iterator(); iter.hasNext();) {
      Map.Entry entry = (Map.Entry) iter.next();
      DataContainer dataContainer = (DataContainer) entry.getValue();
      if( (System.currentTimeMillis() - dataContainer.getCreated())> _lifeTime ) {
      iter.remove();
      }
      }
      }

      public boolean check() {
      return true;
      }
      }

       

      To store object in data container setObject method is used. It generates a unique key and stores object using a generated key. Key is returned back to reuse it for object fetching using method getObject:


      public String setObject(final Object value) {
      final String key = new UID().toString();
      _values.put(key, new DataContainer(System.currentTimeMillis(), value));
      return key;
      }

      public Object getObject(final String key) {
      final DataContainer dataContainer = (DataContainer)_values.get(key);
      return null!=dataContainer ? dataContainer.getValue() : null ;
      }

       

      Behavior of service is described by 2 property – timeout (how often timeout event is occurred) and lifetime (what is the length of object life cycle). To set properties following methods are used:


public boolean setLifeTime(String lifeTime) {
try {
  _lifeTime = Long.parseLong( lifeTime);
  return true;
} catch (NumberFormatException e) {
  return false;
}
}


public boolean  setTimeout(String timeout) {
try {
  long newTimeout = Long.parseLong(timeout);
  timeManager.changeRepeatTime(timeoutListener, newTimeout);
  return true;
} catch (NumberFormatException e) {
  return false;
}
}

 

To allow iteration with SAP J2EE Engine we need to implement service frames (com.sap.engine.frame.ApplicationServiceFrame and com.sap.engine.frame.CommunicationServiceFrame) for dispatcher (communication) and server (application) J2EE Engine elements. In start() method we make initialization steps for our service implementation and register it in J2EE Engine:


public void start(ApplicationServiceContext serviceContext) {
try {
TimeoutManager timeManager =((TimeoutManager) serviceContext.getContainerContext().
getObjectRegistry().getServiceInterface("timeout"));
Properties properties = serviceContext.getServiceState().getProperties();

long timeout = readLongProperty(properties, "timeout", "10000");
long lifeTime = readLongProperty(properties, "lifeTime", "300000");

_remoteInterface = new InterComponentParameterServiceImpl(
timeManager, timeout, lifeTime);

serviceContext.
getContainerContext().
getObjectRegistry().
registerInterface( _remoteInterface );

serviceContext.
getServiceState().
registerContainerEventListener( new PropertyChangedEventListener() );
} catch (Exception e) {
location.traceThrowableT(300, "The remote interface can not be registered", e);
}
}

 

As we said we are using 2 properties to describe behavior of our service. So, we need a way how to notify service implementation that property values are changed. For such purposes we can use server events. We implement com.sap.engine.frame.container.event.ContainerEventListener interface:


public class PropertyChangedEventListener implements ContainerEventListener {
public boolean setServiceProperty(String key, String value) {
if("timeout".equals(key)) {
return _remoteInterface.setTimeout(value);
} else if("lifeTime".equals(key)) {
return _remoteInterface.setLifeTime(value);
} else {
return true;
}
}

public boolean setServiceProperties(Properties properties) {
boolean retValue = true;

if( properties.containsKey("timeout") ) {
retValue = _remoteInterface.setTimeout( properties.getProperty("timeout") );
}
if( properties.containsKey("lifeTime") ) {
retValue = retValue &&
_remoteInterface.setLifeTime( properties.getProperty("lifeTime") );
}
return retValue;
}
}

 

And register instance of event listener in start() method:


serviceContext.
getServiceState().
registerContainerEventListener( new PropertyChangedEventListener() );

 


Web Dynpro DC icp/wd


WD component in DC is a “publisher” of structured object. It is responsible for storing object in service and pass generated key to the service “consumer”.


Web Dynpro DC 
 

To allow WD DC to uses service and store structured object within it we need to accomplish 2 tasks: add a public parts icp/javabean->api and icp/serviceimpl->api and add service reference to our custom build service. icp/javabean->api public part will let us create a JavaBean model (and access JavaBean class directly) and icp/serviceimpl->api public part will let us use the service. Service reference will enable cross-components class loaders (to prevent class loaders exceptions and errors).

We create simple WD component (com.sap.sdn.icp.wd.components.test.Test) containing only one view (com.sap.sdn.icp.wd.components.test.view. TestCV), application (com.sap.sdn.icp.wd.app.PostParameter) and a JavaBean model based on com.sap.sdn.icp.bean.Employee class from icp/javabean->api. On the view layout we create 2 input fields and one button. Input field properties “value” are mapped to according attributes in a model node.


Web Dynpro DC Content  /icpwebsap.com/servlet/ReadParameterServlet?key=” +
    key,
   “Servlet”,
   true).open();


} catch (Exception e) {
wdComponentAPI.getMessageManager().reportException(new WDNonFatalException(e), false);
}

 


Web Module DC icp/web


Servlet in Web module DC is a “consumer” of structured object. It is responsible for reading object key from servlets parameters and fetching the object from service.


Web Module DC 
 

We need to add same public parts like for WD DC (icp/javabean->api and icp/serviceimpl->api) for same purposes. Service refernce to the the our custom build service we will add in EAR DC because Web Module DC is packeged within it.


Web Module DC structure 
 

In out Web Module DC we create a simple HTTP Servlet (by extending javax.servlet.http.HttpServlet class) and implement doGet() method within it:


protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String objectKey = request.getParameter("key");
InitialContext context = new InitialContext();
InterComponentParameterService icp =
(InterComponentParameterService) context.lookup("InterComponentsParametersService");
Employee employee = (Employee)icp.getObject(objectKey);

response.getOutputStream().print( employee.getFirstName() );
response.getOutputStream().print( " ");
response.getOutputStream().print( employee.getLastName() );
} catch (Exception e) {
e.printStackTrace(new PrintStream(response.getOutputStream()));
}
}

 


Enterprise Application DC icp/ear


We use EAR DC to package Web Module DC into a deployable unit and to specify service references.


EAR DC  sap.comicpweb.war</web-uri>
            <context-root>LocalDevelopmenticpweb~sap.com


J2EE Service Component Service DC icp/service


This DC is used to package our service to deployable unit.


Service DC  sap.comicpserviceimpl~serviceimpl.jar

 

In server/service-provider.xml file we are describing important information about our service: frame implementation class, jar which contains it, references to other services, version etc.


Scenario running


After building and deployment of icp/service (pay attention that by deployment of service J2EE server is restarted automatically), icp/ear and icp/wd we can perform a simple scenario test.

First we can check status of our custom build service using Visual Administrator. We can change properties if necessary.


Service in Visual Administrator 
 

We run our WD application, type some data into input fields and press “Transfer” button. New window appears with the servlet displaying data from WD.


Scenario Running

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Valery Silaev
    Just superb solution!

    However, I’ve never thought it is sooooooo complex 😉

    Btw, add your post here: ;\ New Web Dynpro Weblogs

    Regarding TimeoutService. Actually, any modern J2EE server (SAP WebAS, IBM WebSphere, BEA WebLogic etc) are build using JMX architecture. This is the de-facto standard set first by JBoss 2.0 server. Any JMX “container” (do not remember exact name) must expose Timer service. And SAP WebAS in no exception. So technically it should be possible to re-implement same functionality without TimeoutService.

    Valery Silaev
    EPAM Systems
    http://www.NetWeaverTeam.com

    (0) 

Leave a Reply