ESMF_WebServ.F90 Source File


Source Code

! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2023, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the University of Illinois-NCSA License.
!
!==============================================================================
#define ESMF_FILENAME "ESMF_WebServ.F90"
!==============================================================================
!
! ESMF Component module
module ESMF_WebServMod
!
!==============================================================================
! A blank line to keep protex happy because there are no public entry
! points in this file, only internal ones.
!BOP

!EOP
!
! This file contains the Web Services routines.
!
!------------------------------------------------------------------------------
! INCLUDES

#include "ESMF.h"

!------------------------------------------------------------------------------
!BOPI
! !MODULE: ESMF_WebServMod - Web Services routines.
!
! !DESCRIPTION:
!
! The code in this file implements the Fortran interfaces to the
! ESMF Web Services.
!
!
! !USES:
  use ESMF_CompMod
  use ESMF_GridCompMod
  use ESMF_CplCompMod
  use ESMF_StateTypesMod
  use ESMF_StateMod
  use ESMF_ClockMod
  use ESMF_UtilTypesMod
  use ESMF_VMMod
  use ESMF_LogErrMod
    
  implicit none

  private

  public ESMF_WebServProcessRequest, ESMF_WebServWaitForRequest
  public ESMF_WebServCplCompProcessRqst, ESMF_WebServCplCompWaitForRqst
  public ESMF_WebServicesLoop
  public ESMF_WebServicesCplCompLoop
  public ESMF_WebServAddOutputData

contains

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServProcessRequest()"
!BOPI
! !IROUTINE: ESMF_WebServProcessRequest 
!
! !INTERFACE:
  subroutine ESMF_WebServProcessRequest(comp, importState, exportState, &
                                        clock, phase, procType, rc)

!
! !ARGUMENTS:
    type(ESMF_GridComp)  :: comp
    type(ESMF_State)     :: importState
    type(ESMF_State)     :: exportState
    type(ESMF_Clock)     :: clock
    integer              :: phase
    character            :: procType
    integer, intent(out) :: rc

!
!
! !DESCRIPTION:
!   If this is the root process, send messages to all of the other processes
!   to run the specified routine.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_GridComp} object that represents the Grid Component for which
!   the service is created.
! \item[{[impstate]}]
!   {\tt ESMF\_State} containing import data for coupling. 
! \item[{[expstate]}]
!   {\tt ESMF\_State} containing export data for coupling. 
! \item[{[clock]}]
!   External {\tt ESMF\_Clock} for passing in time information.
! \item[{[phase]}]
!   Indicates whether routines are {\em single-phase} or {\em multi-phase}.
! \item[{[procType]}]
!   Specifies which routine to run: 'I' for initialization, 'R' for run, and
!   'F' for finalization.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    ! Local variables
    integer        :: localrc
    type(ESMF_VM)  :: vm
    integer        :: localPet, petCount
    integer        :: thread_cntr
    character      :: outmsg(2)

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    print *, "Processing request"

    call ESMF_GridCompGet(comp, vm=vm)
    call ESMF_VMGet(vm, localPet=localPet, petCount=petCount)

    if (localPet == 0) then

       outmsg(1) = procType

       ! Loop through the other, non-root processes, sending each of them 
       ! the message to process the request
       do thread_cntr = 1, petCount - 1, 1

          print *, "In do loop: ", thread_cntr
          print *, "Before MPI Send: ", procType
          call ESMF_VMSend(vm, sendData=outmsg, count=1, dstPet=thread_cntr, &
                           rc=localrc)

          ! Check return code to make sure send went out ok
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while sending message to non-root pet", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)
          endif

       enddo

    endif

    rc = localrc

  end subroutine
!-------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServCplCompProcessRqst()"
!BOPI
! !IROUTINE: ESMF_WebServCplCompProcessRqst 
!
! !INTERFACE:
  subroutine ESMF_WebServCplCompProcessRqst(comp, importState, exportState, &
                                               clock, phase, procType, rc)

!
! !ARGUMENTS:
    type(ESMF_CplComp)   :: comp
    type(ESMF_State)     :: importState
    type(ESMF_State)     :: exportState
    type(ESMF_Clock)     :: clock
    integer              :: phase
    character            :: procType
    integer, intent(out) :: rc

!
!
! !DESCRIPTION:
!   If this is the root process, send messages to all of the other processes
!   to run the specified routine.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   the service is created.
! \item[{[impstate]}]
!   {\tt ESMF\_State} containing import data for coupling. 
! \item[{[expstate]}]
!   {\tt ESMF\_State} containing export data for coupling. 
! \item[{[clock]}]
!   External {\tt ESMF\_Clock} for passing in time information.
! \item[{[phase]}]
!   Indicates whether routines are {\em single-phase} or {\em multi-phase}.
! \item[{[procType]}]
!   Specifies which routine to run: 'I' for initialization, 'R' for run, and
!   'F' for finalization.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    ! Local variables
    integer        :: localrc
    type(ESMF_VM)  :: vm
    integer        :: localPet, petCount
    integer        :: thread_cntr
    character      :: outmsg(2)

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    print *, "Processing request"

    call ESMF_CplCompGet(comp, vm=vm)
    call ESMF_VMGet(vm, localPet=localPet, petCount=petCount)

    if (localPet == 0) then

       outmsg(1) = procType

       ! Loop through the other, non-root processes, sending each of them 
       ! the message to process the request
       do thread_cntr = 1, petCount - 1, 1

          print *, "In do loop: ", thread_cntr
          print *, "Before MPI Send: ", procType
          call ESMF_VMSend(vm, sendData=outmsg, count=1, dstPet=thread_cntr, &
                           rc=localrc)

          ! Check return code to make sure send went out ok
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while sending message to non-root pet", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)
          endif

       enddo

    endif

    rc = localrc

  end subroutine
!-------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServWaitForRequest()"
!BOPI
! !IROUTINE: ESMF_WebServWaitForRequest 
!
! !INTERFACE:
  subroutine ESMF_WebServWaitForRequest(comp, importState, exportState, &
                                        clock, syncflag, phase, rc)

!
! !ARGUMENTS:
    type(ESMF_GridComp)                              :: comp
    type(ESMF_State),        intent(inout), optional :: importState
    type(ESMF_State),        intent(inout), optional :: exportState
    type(ESMF_Clock),        intent(inout), optional :: clock
    type(ESMF_Sync_Flag),    intent(in),    optional :: syncflag
    integer,                 intent(in),    optional :: phase
    integer,                 intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   If this is not the root process, waits for a message from the root 
!   process and executes the appropriate routine when the message is received.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[expstate]}]
!   {\tt ESMF\_State} containing export data for coupling. 
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc
    type(ESMF_VM) :: vm
    integer       :: localPet, petCount
    character     :: inmsg(2)
    integer       :: count

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    ! Get the current PET info
    call ESMF_GridCompGet(comp, vm=vm)
    call ESMF_VMGet(vm, localPet=localPet, petCount=petCount)

    ! Loop forever... need to provide clean exit 
    do

       ! Wait for the request to be sent, and once it's received, process
       ! the request based on the incoming message
       print *, "Waiting for request: ", localPet
       inmsg(1) = 'A'

       call ESMF_VMRecv(vm, recvData=inmsg, count=count, srcPet=0, &
                        syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
       if (localrc /= ESMF_SUCCESS) then
           call ESMF_LogSetError( &
                   rcToCheck=ESMF_RC_NOT_VALID, &
                   msg="Error while receiving message from root pet", &
                   ESMF_CONTEXT, &
                   rcToReturn=localrc)

           rc = localrc
           return
       endif

       print *, "    Buffer value: ", inmsg(1), " - ", localPet
       print *, "Leaving MPI_Recv: ", localPet

       ! 'I' = init
       if (inmsg(1) == 'I') then

          print *, "Execute GridCompInitialize: ", localPet
          call ESMF_GridCompInitialize(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Initialize.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute GridCompInitialize: ", localPet

       ! 'R' = run
       else if (inmsg(1) == 'R') then

          print *, "Execute GridCompRun: ", localPet
          call ESMF_GridCompRun(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Run.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute GridCompRun: ", localPet

       ! 'F' = final
       else if (inmsg(1) == 'F') then

          print *, "Execute GridCompFinalize: ", localPet
          call ESMF_GridCompFinalize(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Finalize.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute GridCompFinalize: ", localPet

       ! 'E' = exit
       else if (inmsg(1) == 'E') then

          print *, "Exit Component Service: ", localPet
          rc = ESMF_SUCCESS
          return

       ! Anything else... it's an error
       else 

           localrc = ESMF_FAILURE

           call ESMF_LogSetError( &
                   rcToCheck=ESMF_RC_ARG_BAD, &
                   msg="Error while processing request.", &
                   ESMF_CONTEXT, &
                   rcToReturn=localrc)

           rc = localrc
           return

       endif

    end do

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServCplCompWaitForRqst()"
!BOPI
! !IROUTINE: ESMF_WebServCplCompWaitForRqst 
!
! !INTERFACE:
  subroutine ESMF_WebServCplCompWaitForRqst(comp, importState, exportState, &
                                               clock, syncflag, phase, rc)

!
! !ARGUMENTS:
    type(ESMF_CplComp)                               :: comp
    type(ESMF_State),        intent(inout), optional :: importState
    type(ESMF_State),        intent(inout), optional :: exportState
    type(ESMF_Clock),        intent(inout), optional :: clock
    type(ESMF_Sync_Flag),    intent(in),    optional :: syncflag
    integer,                 intent(in),    optional :: phase
    integer,                 intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   If this is not the root process, waits for a message from the root 
!   process and executes the appropriate routine when the message is received.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[expstate]}]
!   {\tt ESMF\_State} containing export data for coupling. 
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc
    type(ESMF_VM) :: vm
    integer       :: localPet, petCount
    character     :: inmsg(2)
    integer       :: count

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    ! Get the current PET info
    call ESMF_CplCompGet(comp, vm=vm)
    call ESMF_VMGet(vm, localPet=localPet, petCount=petCount)

    ! Loop forever... need to provide clean exit 
    do

       ! Wait for the request to be sent, and once it's received, process
       ! the request based on the incoming message
       print *, "Waiting for request: ", localPet
       inmsg(1) = 'A'

       call ESMF_VMRecv(vm, recvData=inmsg, count=count, srcPet=0, &
                        syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
       if (localrc /= ESMF_SUCCESS) then
           call ESMF_LogSetError( &
                   rcToCheck=ESMF_RC_NOT_VALID, &
                   msg="Error while receiving message from root pet", &
                   ESMF_CONTEXT, &
                   rcToReturn=localrc)

           rc = localrc
           return
       endif

       print *, "    Buffer value: ", inmsg(1), " - ", localPet
       print *, "Leaving MPI_Recv: ", localPet

       ! 'I' = init
       if (inmsg(1) == 'I') then

          print *, "Execute CplCompInitialize: ", localPet
          call ESMF_CplCompInitialize(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Initialize.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute CplCompInitialize: ", localPet

       ! 'R' = run
       else if (inmsg(1) == 'R') then

          print *, "Execute CplCompRun: ", localPet
          call ESMF_CplCompRun(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Run.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute CplCompRun: ", localPet

       ! 'F' = final
       else if (inmsg(1) == 'F') then

          print *, "Execute CplCompFinalize: ", localPet
          call ESMF_CplCompFinalize(comp, rc=localrc)
          if (localrc /= ESMF_SUCCESS) then
              call ESMF_LogSetError( &
                      rcToCheck=ESMF_RC_NOT_VALID, &
                      msg="Error while calling ESMF Finalize.", &
                      ESMF_CONTEXT, &
                      rcToReturn=localrc)

              rc = localrc
              return
          endif
          print *, "Done Execute CplCompFinalize: ", localPet

       ! 'E' = exit
       else if (inmsg(1) == 'E') then

          print *, "Exit Component Service: ", localPet
          rc = ESMF_SUCCESS
          return

       ! Anything else... it's an error
       else 

           localrc = ESMF_FAILURE

           call ESMF_LogSetError( &
                   rcToCheck=ESMF_RC_ARG_BAD, &
                   msg="Error while processing request.", &
                   ESMF_CONTEXT, &
                   rcToReturn=localrc)

           rc = localrc
           return

       endif

    end do

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServRegisterSvc()"
!BOPI
! !IROUTINE: ESMF_WebServRegisterSvc 
!
! !INTERFACE:
  subroutine ESMF_WebServRegisterSvc(comp, portNum, clientId, registrarHost, rc)

!
! !ARGUMENTS:
    type(ESMF_GridComp)          :: comp
    integer, intent(in)          :: portNum
    character(len=*), intent(in) :: clientId
    character(len=*), intent(in) :: registrarHost
    integer, intent(out)         :: rc
!
!
! !DESCRIPTION:
!   Registers this component as a service with the Registrar so that clients
!   can discover that it is available.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_GridComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer                     :: localrc
    character(len=ESMF_MAXSTR)  :: compName
    character(len=ESMF_MAXSTR)  :: compDesc
!    character(len=ESMF_MAXSTR)  :: hostName

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call ESMF_GridCompGet(comp, name=compName, rc=localrc)

    compDesc = ""
!    hostName = "localhost"

    call c_ESMC_RegisterComponent(compName, compDesc, clientId, &
                                  registrarHost, portNum, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServCplCompRegisterSvc()"
!BOPI
! !IROUTINE: ESMF_WebServCplCompRegisterSvc 
!
! !INTERFACE:
  subroutine ESMF_WebServCplCompRegisterSvc(comp, portNum, clientId, registrarHost, rc)


!
! !ARGUMENTS:
    type(ESMF_CplComp)           :: comp
    integer, intent(in)          :: portNum
    character(len=*), intent(in) :: clientId
    character(len=*), intent(in) :: registrarHost
    integer, intent(out)         :: rc
!
!
! !DESCRIPTION:
!   Registers this component as a service with the Registrar so that clients
!   can discover that it is available.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer                     :: localrc
    character(len=ESMF_MAXSTR)  :: compName
    character(len=ESMF_MAXSTR)  :: compDesc
!    character(len=ESMF_MAXSTR)  :: hostName

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call ESMF_CplCompGet(comp, name=compName, rc=localrc)

    compDesc = ""
!    hostName = "localhost"

    call c_ESMC_RegisterComponent(compName, compDesc, clientId, &
                                  registrarHost, portNum, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServUnregisterSvc()"
!BOPI
! !IROUTINE: ESMF_WebServUnregisterSvc 
!
! !INTERFACE:
  subroutine ESMF_WebServUnregisterSvc(clientId, registrarHost, rc)

!
! !ARGUMENTS:
    character(len=*), intent(in) :: clientId
    character(len=*), intent(in) :: registrarHost
    integer, intent(out)         :: rc
!
!
! !DESCRIPTION:
!   Un-registers this component from the Registrar so that it is no longer
!   discoverable as an available service.
!
! The arguments are:
! \begin{description}
! \item[{[clientId]}]
!   The identifier of the client.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer                     :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call c_ESMC_UnregisterComponent(clientId, registrarHost, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServSvcLoop()"
!BOPI
! !IROUTINE: ESMF_WebServSvcLoop 
!
! !INTERFACE:
  subroutine ESMF_WebServSvcLoop(clientId, comp, portNum, importState, &
                                 exportState, clock, syncflag, phase, &
                                 registrarHost, rc)

!
! !ARGUMENTS:
    character(len=*),           intent(in)              :: clientId
    type(ESMF_GridComp)                                 :: comp
    integer,                    intent(in)              :: portNum
    type(ESMF_State),           intent(inout), optional :: importState
    type(ESMF_State),           intent(inout), optional :: exportState
    type(ESMF_Clock),           intent(inout), optional :: clock
    type(ESMF_Sync_Flag),       intent(in),    optional :: syncflag
    integer,                    intent(in),    optional :: phase
    character(len=*),           intent(in),    optional :: registrarHost
    integer,                    intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Enters the service into a process loop that waits for requests from
!   clients using a socket service.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call c_ESMC_ComponentSvcLoop(clientId, registrarHost, &
                                 comp, importState, exportState, &
                                 clock, syncflag, phase, portNum, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServCplCompSvcLoop()"
!BOPI
! !IROUTINE: ESMF_WebServCplCompSvcLoop 
!
! !INTERFACE:
  subroutine ESMF_WebServCplCompSvcLoop(clientId, comp, portNum, importState, &
                                        exportState, clock, syncflag, phase, &
                                        registrarHost, rc)

!
! !ARGUMENTS:
    character(len=*),           intent(in)              :: clientId
    type(ESMF_CplComp)                                  :: comp
    integer,                    intent(in)              :: portNum
    type(ESMF_State),           intent(inout), optional :: importState
    type(ESMF_State),           intent(inout), optional :: exportState
    type(ESMF_Clock),           intent(inout), optional :: clock
    type(ESMF_Sync_Flag),       intent(in),    optional :: syncflag
    integer,                    intent(in),    optional :: phase
    character(len=*),           intent(in),    optional :: registrarHost
    integer,                    intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Enters the service into a process loop that waits for requests from
!   clients using a socket service.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call c_ESMC_CplComponentSvcLoop(clientId, registrarHost, &
                                    comp, importState, exportState, &
                                    clock, syncflag, phase, portNum, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServGetPortNum()"
!BOPI
! !IROUTINE: ESMF_WebServSvcLoop 
!
! !INTERFACE:
  subroutine ESMF_WebServGetPortNum(portNum, rc)

!
! !ARGUMENTS:
    integer,                 intent(out)             :: portNum
    integer,                 intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Finds a suitable port number for the service.
!
! The arguments are:
! \begin{description}
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call c_ESMC_GetPortNum(portNum, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServicesLoop()"
!BOP
! !IROUTINE: ESMF_WebServicesLoop 
!
! !INTERFACE:
  subroutine ESMF_WebServicesLoop(comp, portNum, clientId, registrarHost, rc)

!
! !ARGUMENTS:
    type(ESMF_GridComp)                         :: comp
    integer,            intent(inout), optional :: portNum
    character(len=*),   intent(in),    optional, target :: clientId
    character(len=*),   intent(in),    optional, target :: registrarHost
    integer,            intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Encapsulates all of the functionality necessary to setup a component as
!   a component service.  On the root PET, it registers the
!   component service and then enters into a loop that waits for requests on 
!   a socket.  The loop continues until an "exit" request is received, at 
!   which point it exits the loop and unregisters the service.  On
!   any PET other than the root PET, it sets up a process block that waits
!   for instructions from the root PET.  Instructions will come as requests
!   are received from the socket.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[clientId]}]
!   Identifier of the client responsible for this component service.  If a
!   Process Controller application manages this component service, then the
!   clientId is provided to the component service application in the command
!   line.  Otherwise, the clientId is not necessary.
! \item[{[registrarHost]}]
!   Name of the host on which the Registrar is running.  Needed so the
!   component service can notify the Registrar when it is ready to receive
!   requests from clients.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOP
!------------------------------------------------------------------------------

    integer                    :: localrc

    character, target          :: clientIdDefault = ''
    character, target          :: registrarHostDefault = ''
    integer                    :: clientIdlen, registrarHostlen

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    if (present (clientId)) then
      clientIdlen = len (clientID)
    else
      clientIdlen = len (clientIdDefault)
    end if

    if (present (registrarHost)) then
      registrarHostLen = len (registrarHost)
    else
      registrarHostLen = len (registrarHostDefault)
    end if

    ! Make nested call so we can get character string lengths right
    call ESMF_WebServicesLoop1 (clientIdLen, registrarHostLen)

  contains

  subroutine ESMF_WebServicesLoop1 (clIdlen, regHostlen)
    integer, intent(in) :: clIdlen
    integer, intent(in) :: regHostlen

    character(len=clIdlen), pointer :: clientIdVal
    character(len=regHostLen), pointer :: registrarHostVal

    integer                    :: registrarrc
    integer                    :: localPet, petCount
    type(ESMF_VM)              :: vm
    type(ESMF_State)           :: importState
    type(ESMF_State)           :: exportState
    type(ESMF_Clock)           :: clock
    type(ESMF_Sync_Flag)       :: syncflag
    integer                    :: phase

    if (present(clientId)) then
      clientIdVal => clientId
    else
      clientIdVal => clientIdDefault
    end if

    if (present(registrarHost)) then
      registrarHostVal => registrarHost
    else
      registrarHostVal => registrarHostDefault
    end if

    call ESMF_VMGetGlobal(vm=vm, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, &
      rcToReturn=rc)) return

    call ESMF_VMGet(vm, petCount=petCount, localPet=localPet, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, &
      rcToReturn=rc)) return

    if (localPet == 0)  then

       ! create and initialize data members 
       importState = ESMF_StateCreate(name="Import", &
                                      stateintent=ESMF_STATEINTENT_IMPORT, &
                                      rc=localrc)
       if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
         ESMF_CONTEXT, &
         rcToReturn=rc)) &
          return

       exportState = ESMF_StateCreate(name="Export", &
                                      stateintent=ESMF_STATEINTENT_EXPORT, &
                                      rc=localrc)
       if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
         ESMF_CONTEXT, &
         rcToReturn=rc)) &
         return

       ! Initialize clock in the ComponentInitialize function??  
       ! Will creating the object be sufficient or do I need to initialize 
       ! it with some values using ClockCreate?
       !clock = ESMF_ClockCreate("App Clock", rc=localrc)

       syncflag = ESMF_SYNC_BLOCKING
       phase = 1

       if (portNum <= 0) then
          call ESMF_WebServGetPortNum(portNum=portNum, rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return
       endif

       call ESMF_WebServRegisterSvc(comp, portNum=portNum, &
             clientId=clientIdVal, registrarHost=registrarHostVal, &
             rc=registrarrc)
       if (ESMF_LogFoundError(registrarrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) &
             print *, "Unable to Register Service... continuing"

       print *, "KDS: Starting Service Loop"

       call ESMF_WebServSvcLoop( &
             clientId=clientIdVal, comp=comp, portNum=portNum, &
             importState=importState, exportState=exportState, clock=clock, &
             syncflag=syncflag, phase=phase, registrarHost=registrarHostVal, &
             rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return

       print *, "KDS: Exited Service Loop"

       call ESMF_WebServProcessRequest(comp, &
             importState=importState, exportState=exportState, &
             clock=clock, phase=phase, procType="E", rc=localrc)

       call ESMF_WebServUnregisterSvc(clientId=clientIdVal, &
             registrarHost=registrarHostVal, rc=registrarrc)
       if (ESMF_LogFoundError(registrarrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) &
             print *, "Unable to Unregister Service... continuing"

    else

       call ESMF_WebServWaitForRequest(comp, importState=importState, &
             exportState=exportState, clock=clock, syncflag=syncflag, &
             phase=phase, rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return

    end if

    rc = localrc

   end subroutine

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServicesCplCompLoop()"
!BOP
! !IROUTINE: ESMF_WebServicesCplCompLoop 
!
! !INTERFACE:
  subroutine ESMF_WebServicesCplCompLoop(comp, portNum, clientId, registrarHost, rc)


!
! !ARGUMENTS:
    type(ESMF_CplComp)                         :: comp
    integer,           intent(inout), optional :: portNum
    character(len=*),  intent(in),    optional, target :: clientId
    character(len=*),  intent(in),    optional, target :: registrarHost
    integer,           intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Encapsulates all of the functionality necessary to setup a component as
!   a component service.  On the root PET, it registers the
!   component service and then enters into a loop that waits for requests on 
!   a socket.  The loop continues until an "exit" request is received, at 
!   which point it exits the loop and unregisters the service.  On
!   any PET other than the root PET, it sets up a process block that waits
!   for instructions from the root PET.  Instructions will come as requests
!   are received from the socket.
!
! The arguments are:
! \begin{description}
! \item[{[comp]}]
!   {\tt ESMF\_CplComp} object that represents the Grid Component for which
!   routine is run.
! \item[{[portNum]}]
!   Number of the port on which the component service is listening.
! \item[{[clientId]}]
!   Identifier of the client responsible for this component service.  If a
!   Process Controller application manages this component service, then the
!   clientId is provided to the component service application in the command
!   line.  Otherwise, the clientId is not necessary.
! \item[{[registrarHost]}]
!   Name of the host on which the Registrar is running.  Needed so the
!   component service can notify the Registrar when it is ready to receive
!   requests from clients.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOP
!------------------------------------------------------------------------------

    integer                    :: localrc

    character, target          :: clientIdDefault = ''
    character, target          :: registrarHostDefault = ''
    integer                    :: clientIdlen, registrarHostlen

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    if (present (clientId)) then
      clientIdlen = len (clientID)
    else
      clientIdlen = len (clientIdDefault)
    end if

    if (present (registrarHost)) then
      registrarHostLen = len (registrarHost)
    else
      registrarHostLen = len (registrarHostDefault)
    end if

    ! Make nested call so we can get character string lengths right
    call ESMF_WebServicesCplCompLoop1 (clientIdLen, registrarHostLen)

  contains

    subroutine ESMF_WebServicesCplCompLoop1 (clIdLen, regHostLen)
    integer, intent(in) :: clIdlen
    integer, intent(in) :: regHostlen

    character(len=clIdlen), pointer :: clientIdVal
    character(len=regHostLen), pointer :: registrarHostVal

    integer                    :: registrarrc
    integer                    :: localPet, petCount
    type(ESMF_VM)              :: vm
    type(ESMF_State)           :: importState
    type(ESMF_State)           :: exportState
    type(ESMF_Clock)           :: clock
    type(ESMF_Sync_Flag)       :: syncflag
    integer                    :: phase

    if (present(clientId)) then
      clientIdVal => clientId
    else
      clientIdVal => clientIdDefault
    end if

    if (present(registrarHost)) then
      registrarHostVal => registrarHost
    else
      registrarHostVal => registrarHostDefault
    end if

    call ESMF_VMGetGlobal(vm=vm, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, &
      rcToReturn=rc)) return

    call ESMF_VMGet(vm, petCount=petCount, localPet=localPet, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, &
      rcToReturn=rc)) return

    if (localPet == 0)  then

       ! create and initialize data members 
       importState = ESMF_StateCreate(name="Import", &
                                      stateintent=ESMF_STATEINTENT_IMPORT, &
                                      rc=localrc)
       if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
         ESMF_CONTEXT, &
         rcToReturn=rc)) &
          return

       exportState = ESMF_StateCreate(name="Export", &
                                      stateintent=ESMF_STATEINTENT_EXPORT, &
                                      rc=localrc)
       if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
         ESMF_CONTEXT, &
         rcToReturn=rc)) &
         return

       ! Initialize clock in the ComponentInitialize function??  
       ! Will creating the object be sufficient or do I need to initialize 
       ! it with some values using ClockCreate?
       !clock = ESMF_ClockCreate("App Clock", rc=localrc)

       syncflag = ESMF_SYNC_BLOCKING
       phase = 1

       if (portNum <= 0) then
          call ESMF_WebServGetPortNum(portNum=portNum, rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return
       endif

       call ESMF_WebServCplCompRegisterSvc(comp, portNum=portNum, &
             clientId=clientIdVal, registrarHost=registrarHostVal, &
             rc=registrarrc)
       if (ESMF_LogFoundError(registrarrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) &
             print *, "Unable to Register Service... continuing"

       print *, "KDS: Starting Service Loop"

       call ESMF_WebServCplCompSvcLoop( &
             clientId=clientIdVal, comp=comp, portNum=portNum, &
             importState=importState, exportState=exportState, clock=clock, &
             syncflag=syncflag, phase=phase, registrarHost=registrarHostVal, &
             rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return

       print *, "KDS: Exited Service Loop"

       call ESMF_WebServCplCompProcessRqst(comp, &
             importState=importState, exportState=exportState, &
             clock=clock, phase=phase, procType="E", rc=localrc)

       call ESMF_WebServUnregisterSvc(clientId=clientIdVal, &
             registrarHost=registrarHostVal, rc=registrarrc)
       if (ESMF_LogFoundError(registrarrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) &
             print *, "Unable to Unregister Service... continuing"

    else

       call ESMF_WebServCplCompWaitForRqst(comp, importState=importState, &
             exportState=exportState, clock=clock, syncflag=syncflag, &
             phase=phase, rc=localrc)
       if (ESMF_LogFoundError(localrc, &
             ESMF_ERR_PASSTHRU, &
             ESMF_CONTEXT, &
             rcToReturn=rc)) return

    end if

    rc = localrc

   end subroutine

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServAddOutputFilename()"
!BOPI
! !IROUTINE: ESMF_WebServAddOutputFilename 
!
! !INTERFACE:
  subroutine ESMF_WebServAddOutputFilename(filename, rc)

!
! !ARGUMENTS:
    character(*), intent(in)              :: filename
    integer,      intent(out),   optional :: rc
!
!
! !DESCRIPTION:
!   Adds a filename to the list of output filenames.
!
! The arguments are:
! \begin{description}
! \item[{[filename]}]
!   The name of the file to add to the list of output filenames.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    call c_ESMC_AddOutputFilename(trim(filename), localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServDescOutputData()"
!BOPI
! !IROUTINE: ESMF_WebServDescOutputData 
!
! !INTERFACE:
  subroutine ESMF_WebServDescOutputData(varNames, numLatValues, latValues, numLonValues, lonValues, rc)

!
! !ARGUMENTS:
    character(len=*),   intent(in)            :: varNames
    integer,            intent(in)            :: numLatValues
    real(ESMF_KIND_R8), intent(in)            :: latValues(*)
    integer,            intent(in)            :: numLonValues
    real(ESMF_KIND_R8), intent(in)            :: lonValues(*)
    integer,            intent(out), optional :: rc
!
!
! !DESCRIPTION:
!   Adds a grid of data for the specified variables.
!
! The arguments are:
! \begin{description}
! \item[{[filename]}]
!   The name of the file to add to the list of output filenames.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

!    call c_ESMC_AddOutputFilename(filename, localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_WebServAddOutputData()"
!BOPI
! !IROUTINE: ESMF_WebServAddOutputData 
!
! !INTERFACE:
  subroutine ESMF_WebServAddOutputData(timestamp, varName, data, rc)

!
! !ARGUMENTS:
    real(ESMF_KIND_R8), intent(in)            :: timestamp
    character(len=*),   intent(in)            :: varName
    real(ESMF_KIND_R8), intent(in)            :: data(*)
    integer,            intent(out), optional :: rc
!
!
! !DESCRIPTION:
!   Adds a grid of data for the specified variables.
!
! The arguments are:
! \begin{description}
! \item[{[filename]}]
!   The name of the file to add to the list of output filenames.
! \item[{[rc]}]
!   Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------

    integer       :: localrc

    ! Initialize return code
    rc = ESMF_SUCCESS
    localrc = ESMF_SUCCESS

    !call c_ESMC_AddOutputData(timestamp, varName, data, localrc)
    !call c_ESMC_AddOutputData(localrc)

    rc = localrc

  end subroutine
!------------------------------------------------------------------------------


end module ESMF_WebServMod