Skip to Content

Thanks to Richard Hirsch for his blog Guided Procedures Explorations: Process Runtime Dashboard   (The specified item was not found.). The code was very helpful in writing this application.

A Generic Tool for Process Monitoring:

This blog explains a generic WebDynpro Application and a generic iView which can be adapted to all GP applications. End users are more concerned about the applications they are responsible for. End users can monitor application specific runtime instances and step by step status of each action. This application gives an easy view to In Process and Completed instances.

The application looks as

image

1) Create WebDynpro Application in NWDS:

– Create a WebDynpro project and application in NWDS.

– Create the following context in Component Controller and map it to View Controller.

image

– Create the layout as below:

image

The following is the code in Component Controller:

// –


// This file has been generated partially by the Web Dynpro Code Generator.

// MODIFY CODE ONLY IN SECTIONS ENCLOSED BY @@begin AND @@end.

// ALL OTHER CHANGES WILL BE LOST IF THE FILE IS REGENERATED.

// –


package com.capgemini.gp.monitor;

//

// IMPORTANT NOTE:

// ALL IMPORT STATEMENTS MUST BE PLACED IN THE FOLLOWING SECTION ENCLOSED

// BY @@begin imports AND @@end. FURTHERMORE, THIS SECTION MUST ALWAYS CONTAIN

// AT LEAST ONE IMPORT STATEMENT (E.G. THAT FOR IPrivateGPMonitorApps).

// OTHERWISE, USING THE ECLIPSE FUNCTION “Organize Imports” FOLLOWED BY

// A WEB DYNPRO CODE GENERATION (E.G. PROJECT BUILD) WILL RESULT IN THE LOSS

// OF IMPORT STATEMENTS.

//

//@@begin imports

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.PrintStream;

import java.sql.Time;

import java.text.NumberFormat;

import java.util.Calendar;

import java.util.Date;

import java.util.Enumeration;

import java.util.GregorianCalendar;

import java.util.StringTokenizer;

import java.util.Vector;

import com.capgemini.gp.monitor.wdp.IMessageGPMonitorApps;

import com.capgemini.gp.monitor.wdp.IPrivateGPMonitorApps;

import com.capgemini.gp.monitor.wdp.IPublicGPMonitorApps;

import com.sap.caf.eu.gp.base.api.IGPVersionNumber;

import com.sap.caf.eu.gp.context.api.GPContextFactory;

import com.sap.caf.eu.gp.context.api.IGPUserContext;

import com.sap.caf.eu.gp.exception.api.GPEngineException;

import com.sap.caf.eu.gp.exception.api.GPInvocationException;

import com.sap.caf.eu.gp.process.api.GPActionInstanceStatus;

import com.sap.caf.eu.gp.process.api.GPProcessFactory;

import com.sap.caf.eu.gp.process.api.GPSearchRole;

import com.sap.caf.eu.gp.process.api.IGPActionInstance;

import com.sap.caf.eu.gp.process.api.IGPActivity;

import com.sap.caf.eu.gp.process.api.IGPActivityInstance;

import com.sap.caf.eu.gp.process.api.IGPBlockInstance;

import com.sap.caf.eu.gp.process.api.IGPCategory;

import com.sap.caf.eu.gp.process.api.IGPProcess;

import com.sap.caf.eu.gp.process.api.IGPProcessInfo;

import com.sap.caf.eu.gp.process.api.IGPProcessInstance;

import com.sap.caf.eu.gp.process.api.IGPProcessInstanceInfo;

import com.sap.caf.eu.gp.process.api.IGPProcessRoleInstance;

import com.sap.caf.eu.gp.process.dt.api.IGPDesigntimeManager;

import com.sap.caf.eu.gp.process.rt.api.IGPProcessRoleInstanceList;

import com.sap.caf.eu.gp.process.rt.api.IGPRuntimeManager;

import com.sap.security.api.IUser;

import com.sap.security.api.UMException;

import com.sap.security.api.UMFactory;

import com.sap.tc.webdynpro.progmodel.api.IWDMessageManager;

import com.sap.tc.webdynpro.services.sal.adapter.api.WDProtocolAdapter;

import com.sap.tc.webdynpro.services.sal.um.api.IWDClientUser;

import com.sap.tc.webdynpro.services.sal.um.api.WDClientUser;

import com.sap.tc.webdynpro.services.sal.um.api.WDUMException;

//import com.sap.caf.eu.gp.model.process.info.impl.SearchRolesInformation;

//@@end

//@@begin documentation

//@@end

public class GPMonitorApps

{

  /**

  • Logging location.

   */

  private static final com.sap.tc.logging.Location logger =

    com.sap.tc.logging.Location.getLocation(GPMonitorApps.class);

  static

  {

    //@@begin id

          String id = “$Id$”;

    //@@end

    com.sap.tc.logging.Location.getLocation(“ID.com.sap.tc.webdynpro”).infoT(id);

  }

  /**

  • Private access to the generated Web Dynpro counterpart

  • for this controller class.  </p>

   *

  • Use <code>wdThis</code> to gain typed access to the context,

  • to trigger navigation via outbound plugs, to get and enable/disable

  • actions, fire declared events, and access used controllers and/or

  • component usages.

   *

  • @see com.capgemini.gp.monitor.wdp.IPrivateGPMonitorApps for more details

   */

  private final IPrivateGPMonitorApps wdThis;

  /**

  • Root node of this controller’s context. </p>

   *

  • Provides typed access not only to the elements of the root node

  • but also to all nodes in the context (methods nodeXYZ())

  • and their currently selected element (methods currentXYZElement()).

  • It also facilitates the creation of new elements for all nodes

  • (methods createXYZElement()). </p>

   *

  • @see com.capgemini.gp.monitor.wdp.IPrivateGPMonitorApps.IContextNode for more details.

   */

  private final IPrivateGPMonitorApps.IContextNode wdContext;

  /**

  • A shortcut for <code>wdThis.wdGetAPI()</code>. </p>

  • Represents the generic API of the generic Web Dynpro counterpart

  • for this controller. </p>

   */

  private final com.sap.tc.webdynpro.progmodel.api.IWDComponent wdControllerAPI;

  /**

  • A shortcut for <code>wdThis.wdGetAPI().getComponent()</code>. </p>

  • Represents the generic API of the Web Dynpro component this controller

  • belongs to. Can be used to access the message manager, the window manager,

  • to add/remove event handlers and so on. </p>

   */

  private final com.sap.tc.webdynpro.progmodel.api.IWDComponent wdComponentAPI;

  public GPMonitorApps(IPrivateGPMonitorApps wdThis)

  {

    this.wdThis = wdThis;

    this.wdContext = wdThis.wdGetContext();

    this.wdControllerAPI = wdThis.wdGetAPI();

    this.wdComponentAPI = wdThis.wdGetAPI().getComponent();

  }

  //@@begin javadoc:wdDoInit()

     /** Hook method called to initialize controller. */

  //@@end

  public void wdDoInit()

  {

    //@@begin wdDoInit()

          msgManager = wdComponentAPI.getMessageManager();

          PROCESS_PATH           = WDProtocolAdapter.getProtocolAdapter().getRequestObject().getParameter(“PROCESS_PATH”);

          MONITORING_USER_ID     = WDProtocolAdapter.getProtocolAdapter().getRequestObject().getParameter(“USER_ID”);

          if(PROCESS_PATH==null || PROCESS_PATH.trim().length()<=0)

          {

               wdContext.currentContextElement().setEnable_getdetails(false);

               msgManager.reportMessage(IMessageGPMonitorApps.INVALID__PROCESS__TEMPLATE__PATH,null,true);               

          }

          wdContext.currentContextElement().setEnable_getdetails(true);     

          Calendar calendar = Calendar.getInstance();

          wdContext.currentContextElement().setSearch_EndTime(new java.sql.Date(calendar.getTimeInMillis()));

          wdContext.currentContextElement().setSearch_StartTime(new java.sql.Date(calendar.getTimeInMillis()));

          initialize();

    //@@end

  }

  //@@begin javadoc:wdDoExit()

     /** Hook method called to clean up controller. */

  //@@end

  public void wdDoExit()

  {

    //@@begin wdDoExit()

    //@@end

  }

  //@@begin javadoc:wdDoPostProcessing()

     /**

  • Hook called to handle data retrieval errors before rendering.

      *

  • After doModifyView(), the Web Dynpro Framework gets all context data needed

  • for rendering by validating the contexts (which in turn calls the supply

  • functions and supplying relation roles). In this hook, the application

  • should handle the errors which occurred during validation of the contexts.

  • Using preorder depth-first traversal, this hook is called for all component

  • controllers starting with the current root component.

      *

  • Permitted operations:

  • – Flushing model queue

  • – Creating messages

  • – Reading context and model data

      *

  • Forbidden operations:

  • – Invalidating model data

  • – Manipulating the context

  • – Firing outbound plugs

  • – Creating components

  • – …  

      *

  • @param isCurrentRoot true if this is the root of the current request

      */

  //@@end

  public void wdDoPostProcessing(boolean isCurrentRoot)

  {

    //@@begin wdDoPostProcessing()

    //@@end

  }

  //@@begin javadoc:wdDoBeforeNavigation()

     /**

  • Hook before the navigation phase starts.

      *

  • This hook allows you to flush the model queue and handle any

  • errors that occur. Firing outbound plugs is allowed in this hook.

      *

  • Using preorder depth-first traversal, this hook is called for all component

  • controllers starting with the current root component.

      *

  • @param isCurrentRoot true if this is the root of the current request

      */

  //@@end

  public void wdDoBeforeNavigation(boolean isCurrentRoot)

  {

    //@@begin wdDoBeforeNavigation()

    //@@end

  }

  //@@begin javadoc:wdDoApplicationStateChange()

     /**

  • Hook that informs the application about a state change.

  • <p>

  • This hook is called e.g. to tell the application that will be

  • <ul>

  • <li>left via a suspend plug and therefore should go into a suspend/sleep

  •      mode with minimal need of resources. errors that occur. Firing

  •      outbound plugs is allowed in this hook.

  • <li>left due to a timeout and could write it’s state to a data base if the

  •      user comes back later on

  • </ul>

      *

  • The concrete reason is available via IWDApplicationStateChangeInfo

  • <p>

  • <b>Important</b>: This hook is called for the top level component only!

      *

  • @param stateChangeInfo contains the information about the nature of the state change

  • @param stateChangeReturn allows the application to ask for a different state change.

  •        The framework is allowed to ignore it considering i.e. the current resources situation.

      */

  //@@end

  public void wdDoApplicationStateChange(com.sap.tc.webdynpro.progmodel.api.IWDApplicationStateChangeInfo stateChangeInfo, com.sap.tc.webdynpro.progmodel.api.IWDApplicationStateChangeReturn stateChangeReturn)

  {

    //@@begin wdDoApplicationStateChange()

    //@@end

  }

  //@@begin javadoc:getProcessInstDetails()

  /** Declared method. */

  //@@end

  public void getProcessInstDetails( )

  {

    //@@begin getProcessInstDetails()

     wdContext.nodeInstanceLowlevelDetails().invalidate();

     IPublicGPMonitorApps.IInstanceLowlevelDetailsElement detailsEle = null;

     try

     {

          IGPProcessInstance processInstance = runtimeManager.getProcessInstance(wdContext.currentProcessInstanceSummaryElement().getInstaceID(),userContext);

          if(processInstance != null)

          {

               IGPActivityInstance[] activityInstances = processInstance.getChildrenInformation();     

               Vector blcokStack = new Vector();                                         

               for (int blockIndex=0;blockIndexGPInvocationException ” + e.getMessage(), false);

     }

    //@@end

  }

  //@@begin javadoc:getProcessInstanceSummary()

  /** Declared method. */

  //@@end

  public void getProcessInstanceSummary( )

  {

    //@@begin getProcessInstanceSummary()

     wdContext.nodeProcessInstanceSummary().invalidate();

     wdContext.nodeInstanceLowlevelDetails().invalidate();

     getProcessTimes();

    //@@end

  }

  /*

  • The following code section can be used for any Java code that is

  • not to be visible to other controllers/views or that contains constructs

  • currently not supported directly by Web Dynpro (such as inner classes or

  • member variables etc.). </p>

   *

  • Note: The content of this section is in no way managed/controlled

  • by the Web Dynpro Designtime or the Web Dynpro Runtime.

   */

  //@@begin others

       public String PROCESS_PATH                = “”;

       public String MONITORING_USER_ID      = “”;

       public static final double MILLISECONDS_2_DAY_CONSTANT           = 1.15740740740741E-08;

       public static final double MILLISECONDS_2_HOURS_CONSTANT      = 2.77777777777778E-07;

     private IGPDesigntimeManager      designtimeManager;

     private IGPUserContext                userContext;

     private IGPRuntimeManager           runtimeManager;

     private IWDMessageManager           msgManager;

     private void initialize()

     {

          try

          {          

               designtimeManager           = GPProcessFactory.getDesigntimeManager();

               runtimeManager                = GPProcessFactory.getRuntimeManager();

               IUser user                    = null;

               if(MONITORING_USER_ID != null && MONITORING_USER_ID.trim().length()>0)

               {

                    user = UMFactory.getUserFactory().getUserByLogonID(MONITORING_USER_ID);     

               }

               else

               {

                    IWDClientUser wdUser      = WDClientUser.getCurrentUser();          

                     user                          = wdUser.getSAPUser();

               }

               if(user != null)               

               {

                    userContext = GPContextFactory.getContextManager().createUserContext(user);

               }

               else

               {

                    msgManager.reportMessage(IMessageGPMonitorApps.NOT__A__VALID__USER,null,true);     

               }

          }

          catch (GPEngineException e)

          {

               msgManager.reportException(“UMException ” + e.getMessage(), false);

          }

     }

     private void updateProgressPercentage()

     {          

          if(wdContext.currentContextElement().getProcessStatus().equals(“INPROCESS”))

          {          

               int totalProcessSteps           = wdContext.nodeInstanceLowlevelDetails().size();

               int completedProcessSteps      = 0;

               for(int index=0;index<totalProcessSteps;index++)

               {

                    if(wdContext.nodeInstanceLowlevelDetails().getInstanceLowlevelDetailsElementAt(index).getStatus().equals(“COMPLETED”))

                    {

                         completedProcessSteps++;

                    }

               }

               double value = (int)completedProcessSteps/totalProcessSteps;

               wdContext.currentProcessInstanceSummaryElement().setProgessPercentage(“”+value*100);               

          }

     }

     private String getActivityStatusDescription(GPActionInstanceStatus status)

     {

          if(status != null)

          {

               int code = status.getCode();

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_ACTIVE.getCode())

               {

                    return “ACTIVE”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_CANCELLED.getCode())

               {

                    return “CANCELLED”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_COMPLETED.getCode())

               {

                    return “COMPLETED”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_ERROR.getCode())

               {

                    return “ERROR”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_FUTURE.getCode())

               {

                    return “FUTURE”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_IN_PROCESS.getCode())

               {

                    return “IN_PROCESS”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_INVALID.getCode())

               {

                    return “INVALID”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_RUNNING.getCode())

               {

                    return “RUNNING”;                    

               }

               else

               if(code == GPActionInstanceStatus.ACTION_INSTANCE_STATUS_SKIPPED.getCode())

               {

                    return “SKIPPED”;                    

               }

          }

          return “UN_KNOWN”;

     }

     public void getProcessTimes()

     {

          IPublicGPMonitorApps.IProcessInstanceSummaryElement summaryEle = null;

          IUser ownerUser = null;

          try

          {

               Date startDate      = wdContext.currentContextElement().getSearch_StartTime();

               Date endDate      = wdContext.currentContextElement().getSearch_EndTime();

               IGPProcessInstanceInfo[] processInstanceInfo = null;

               String processStatus = wdContext.currentContextElement().getProcessStatus();

               if(processStatus.equalsIgnoreCase(“INPROCESS”))

               {

                    processInstanceInfo = runtimeManager.getRunningInstances(GPSearchRole.SEARCH_ROLE_OWNER, startDate, endDate, userContext);

               }

               else

               if(processStatus.equalsIgnoreCase(“COMPLETE”))

               {

                    processInstanceInfo = runtimeManager.getCompletedInstances(GPSearchRole.SEARCH_ROLE_ADMINISTRATOR, startDate, endDate, userContext);

               }               

               IGPProcessInfo processInfo = getProcessID();

               String processTemplateID = null;

               if(processInfo != null)

               {

                    processTemplateID      = processInfo.getID();                    

                    wdContext.currentContextElement().setProcessTitle(processInfo.getTitle());

               }

               //msgManager.reportException(“processTemplateID=”processTemplateID” processInstanceInfo=”+processInstanceInfo,false);

               if (processTemplateID == null || processInstanceInfo == null) // this means the requested path is incorrect

               {

                    msgManager.reportMessage(IMessageGPMonitorApps.INVALID__PROCESS__TEMPLATE__PATH,null,false);     

                    return;               

               }                

               for (int i = 0; i < processInstanceInfo.length; i++)

               {

                    IGPProcessInstance processInstance = runtimeManager.getProcessInstance(processInstanceInfo[i], userContext);

                    if (processTemplateID.equals(processInstance.getTemplate().getID()))

                    {

                         IGPVersionNumber processVerstionNumber = processInstance.getTemplate().getVersionNumber();

                         Enumeration ownersEnum = processInstance.getOwners();

                         String instanceOwners  = null;

                         while(ownersEnum.hasMoreElements())

                         {

                              ownerUser = (IUser)ownersEnum.nextElement();

                              if(ownerUser != null)

                              {

                                   if(instanceOwners ==null)

                                   {

                                        instanceOwners = ownerUser.getDisplayName();

                                   }

                                   else

                                   {

                                        instanceOwners = “;”ownerUser.getDisplayName();

                                   }                                   

                              }

                         }

                         summaryEle = wdContext.nodeProcessInstanceSummary().createProcessInstanceSummaryElement();

                         Date actualEndDate = processInstance.getActualEndDate();                         

                         if(actualEndDate != null)

                         {

                              summaryEle.setCompletionTime(actualEndDate.toString());

                         }

                         summaryEle.setInitiator(processInstance.getInitiator().getDisplayName());

                         summaryEle.setOwner(instanceOwners);

                         String processName = processInstance.getUserProvidedName();

                         if(processName ==null || processName.trim().length()GPInvocationException ” + e.getMessage(), false);               

          }

     }

     private String getElapsedTimeDescription(long milliSeconds)//Date startDate,Date endDate)

     {

          long days           =  milliSeconds / (10006060*24);

          long hours           = (milliSeconds % (1000606024)) / (100060*60);

          long minutes      = ((milliSeconds % (1000606024))%10006060) / (100060*60);

          long seconds      = (((milliSeconds % (1000606024))%10006060)) % (100060) / 1000;

          return days” Days, “hours” Hours “;//minutes+” Minutes “;

     }

     /**

  • Searches the designtime tree to find the category designated by the path <B>path</B>

  • @param path

  • @return

  • @throws Exception

      */

     private IGPCategory getCategoryFromPath(String path)

     {

          try

          {

               StringTokenizer st      = new StringTokenizer(path, “/”);

               int tokenCount           = st.countTokens();

               IGPCategory rootCategory = designtimeManager.getRootCategory(userContext);

               IGPCategory[] categories = rootCategory.getSubCategories();

               IGPCategory category = null;

               int tokenPos = 0;

               while (st.hasMoreTokens())

               {

                    int i = 0;

                    String token = st.nextToken();

                    while ((i Exclude Root from the folder path. For the above example the process path is: Time Off ProcessProcess Time Off Process

MONITORING_USER_ID should be a valid Portal user id and should be Administrator or Owner of the process. This field is optional, if no value is specified the program will consider the current logged in user. User ID can be configured if the application has single user as Administrator or as Owner.

2) Create generic iView template in Portal for the above WebDynpro Application:

Once the WebDynpro application is ready, create a WebDynpro iView in Portal. Make sure the following properties are set so that the iView can be reused for all GP applications.

!https://weblogs.sdn.sap.com/weblogs/images/13663/GP2A.gif|height=82|alt=image|width=511|src=https://weblogs.sdn.sap.com/weblogs/images/13663/GP2A.gif|border=0!

Now we are ready with Generic Template. It’s time to create Application specific iViews.

3) Create GP Application Specific iViews in Portal using above template.

While creating Application specific iView select the template created in previous step.

image

4) Configure runtime parameters for specific GP application.

Once the application specific iView is created edit the Application Parameters:

!https://weblogs.sdn.sap.com/weblogs/images/13663/GP4A.GIF|height=36|alt=image|width=593|src=https://weblogs.sdn.sap.com/weblogs/images/13663/GP4A.GIF|border=0!</body>

To report this post you need to login first.

4 Comments

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

Leave a Reply