text: import json
  
  from python_helper import Constant as c
  from python_helper import ReflectionHelper, ObjectHelper, log, Function, StringHelper
  from python_framework import (
      FlaskManager,
      GlobalException,
      ConverterStatic,
      FlaskUtil,
      Serializer,
      ConfigurationKeyConstant,
      EncapsulateItWithGlobalException,
      OpenApiManager,
      HttpStatus,
      HttpDomain,
      LogConstant
  )
  
  try:
      import MessageConstant
      import AnnotationUtil
      import MessageDto
  except:
      from queue_manager_api.api.src.constant import MessageConstant
      from queue_manager_api.api.src.util import AnnotationUtil
      from queue_manager_api.api.src.dto import MessageDto
  
  
  DEFAULT_TIMEOUT = 2
  
  
  @Function
  def MessageListener(
      *resourceArgs,
      url = c.SLASH,
      timeout = DEFAULT_TIMEOUT,
      responseHeaders = None,
      logRequest = False,
      logResponse = False,
      enabled = None,
      muteLogs = None,
      **resourceKwargs
  ):
      def Wrapper(OuterClass, *outterArgs, **outterKwargs):
          resourceUrl = url
          resourceTimeout = timeout
          resourceLogRequest = logRequest
          resourceLogResponse = logResponse
          resourceEnabled = enabled
          resourceMuteLogs = muteLogs
          resourceInstanceResponseHeaders = responseHeaders
          log.wrapper(MessageListener, f'''wrapping {OuterClass.__name__}(*{outterArgs}, **{outterKwargs})''')
          api = FlaskManager.getApi()
          class InnerClass(OuterClass):
              url = resourceUrl
              responseHeaders = resourceInstanceResponseHeaders
              logRequest = resourceLogRequest
              logResponse = resourceLogResponse
              enabled = resourceEnabled
              muteLogs = resourceMuteLogs
              def __init__(self, *args, **kwargs):
                  log.wrapper(OuterClass, f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})')
                  OuterClass.__init__(self, *args,**kwargs)
                  AnnotationUtil.initializeComunicationLayerResource(
                      resourceInstance = self,
                      api = api,
                      timeout = resourceTimeout,
                      enabled = resourceEnabled,
                      muteLogs = resourceMuteLogs,
                      logRequest = resourceLogRequest,
                      logResponse = resourceLogResponse,
                      resourceEnabledConfigKey = ConfigurationKeyConstant.API_LISTENER_ENABLE,
                      resourceMuteLogsConfigKey = ConfigurationKeyConstant.API_LISTENER_MUTE_LOGS,
                      resourceTimeoutConfigKey = ConfigurationKeyConstant.API_LISTENER_TIMEOUT
                  )
                  self.manager = api.resource.manager.queue
          ReflectionHelper.overrideSignatures(InnerClass, OuterClass)
          return InnerClass
      return Wrapper
  
  
  @Function
  def MessageListenerMethod(
      *methodArgs,
      url = c.SLASH,
      timeout = DEFAULT_TIMEOUT,
      requestHeaderClass = None,
      requestParamClass = None,
      requestClass = None,
      responseClass = None,
      responseHeaders = None,
      roleRequired = None,
      apiKeyRequired = None,
      contextRequired = None,
      consumes = OpenApiManager.DEFAULT_CONTENT_TYPE,
      produces = OpenApiManager.DEFAULT_CONTENT_TYPE,
      logRequest = True,
      logResponse = True,
      enabled = True,
      muteLogs = False,
      muteStacktraceOnBusinessRuleException = True,
      runInAThread = False,
      **methodKwargs
  ):
      def innerMethodWrapper(resourceInstanceMethod, *innerMethodArgs, **innerMethodKwargs):
          resourceInstanceMethodUrl = url
          wrapperManager = AnnotationUtil.InnerMethodWrapperManager(
              wrapperType = MessageListenerMethod,
              resourceInstanceMethod = resourceInstanceMethod,
              timeout = timeout,
              enabled = enabled,
              muteLogs = muteLogs,
              logRequest = logRequest,
              logResponse = logResponse,
              resourceTypeName = FlaskManager.KW_LISTENER_RESOURCE,
              resourceEnabledConfigKey = ConfigurationKeyConstant.API_LISTENER_ENABLE,
              resourceMuteLogsConfigKey = ConfigurationKeyConstant.API_LISTENER_MUTE_LOGS,
              resourceTimeoutConfigKey = ConfigurationKeyConstant.API_LISTENER_TIMEOUT
          )
          resourceInstanceMethodMuteStacktraceOnBusinessRuleException = muteStacktraceOnBusinessRuleException
          resourceInstanceMethodRunInAThread = runInAThread
          listenerUrl = f'{wrapperManager.api.baseUrl}{resourceInstanceMethodUrl}'
          if listenerUrl.endswith(c.SLASH):
              listenerUrl = listenerUrl[:-1]
          @wrapperManager.api.app.route(listenerUrl, methods=[HttpDomain.Verb.POST], endpoint=f'{resourceInstanceMethod.__qualname__}')
          def innerResourceInstanceMethod(*args, **kwargs):
              args = wrapperManager.addResourceInFrontOfArgs(args)
              messageAsJson = FlaskUtil.safellyGetRequestBody()
              completeResponse = None
              if not wrapperManager.muteLogs:
                  requestUrl = FlaskUtil.safellyGetUrl()
                  requestVerb = FlaskUtil.safellyGetVerb()
                  log.info(wrapperManager.resourceInstanceMethod, f'''{LogConstant.LISTENER_SPACE}{requestVerb}{c.SPACE_DASH_SPACE}{requestUrl}''')
                  if wrapperManager.shouldLogRequest():
                      try:
                          messageCreationRequestDto = Serializer.getObjectAsDictionary(Serializer.convertFromJsonToObject(messageAsJson, MessageDto.MessageCreationRequestDto))
                          log.prettyPython(wrapperManager.resourceInstanceMethod, f'{LogConstant.LISTENER_SPACE}Message data', messageCreationRequestDto, logLevel=log.INFO)
                      except Exception as exception:
                          log.failure(innerResourceInstanceMethod, 'Not possible to log message data properly', exception)
              if not wrapperManager.enabled:
                  completeResponse = FlaskManager.getCompleteResponseByException(
                      GlobalException(logMessage='This resource is temporarily disabled', status=HttpStatus.SERVICE_UNAVAILABLE),
                      wrapperManager.resourceInstance,
                      wrapperManager.resourceInstanceMethod,
                      resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
                      context = HttpDomain.LISTENER_CONTEXT
                  )
              elif ObjectHelper.isEmpty(messageAsJson):
                  completeResponse = FlaskManager.getCompleteResponseByException(
                      GlobalException(message='Content cannot be empty', logResponse=f'Content: {messageContent}', status=HttpStatus.BAD_REQUEST),
                      wrapperManager.resourceInstance,
                      wrapperManager.resourceInstanceMethod,
                      resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
                      context = HttpDomain.LISTENER_CONTEXT
                  )
              else:
                  listennerArgs = (
                      args,
                      kwargs,
                      wrapperManager,
                      roleRequired,
                      apiKeyRequired,
                      contextRequired,
                      requestHeaderClass,
                      requestParamClass,
                      requestClass,
                      responseClass,
                      responseHeaders,
                      consumes,
                      resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
  
                      requestUrl,
                      requestVerb,
                      FlaskUtil.safellyGetHeaders(),
                      FlaskUtil.safellyGetArgs(),
                      messageAsJson.get(MessageConstant.MESSAGE_CONTENT_KEY, {})
                  )
  
                  ###- only works if it's declared within a context
                  # from flask import copy_current_request_context
                  # if resourceInstanceMethodRunInAThread:
                  #     ###- https://flask.palletsprojects.com/en/2.1.x/api/#flask.copy_current_request_context
                  #     @copy_current_request_context
                  #     def resolveCallUsingCurrentApiContext(*args, **kwags):
                  #         resolveListenerCall(*args, **kwags)
                  #     wrapperManager.resourceInstance.manager.runInAThread(resolveCallUsingCurrentApiContext, *listennerArgs)
                  # else:
                  #     completeResponse = resolveListenerCall(*listennerArgs)
  
                  if resourceInstanceMethodRunInAThread:
                      wrapperManager.resourceInstance.manager.runInAThread(resolveListenerCallWithinAContext, *listennerArgs)
                  else:
                      completeResponse = resolveListenerCall(*listennerArgs)
                  if ObjectHelper.isEmpty(completeResponse) or HttpStatus.BAD_REQUEST < completeResponse[-1]:
                      completeResponse = [
                          MessageDto.MessageCreationResponseDto(
                              key = messageAsJson.get(MessageConstant.MESSAGE_KEY_KEY),
                              queueKey = messageAsJson.get(MessageConstant.MESSAGE_QUEUE_KEY_KEY),
                              groupKey = messageAsJson.get(MessageConstant.MESSAGE_GROUP_KEY)
                          ),
                          {},
                          HttpStatus.ACCEPTED
                      ]
              httpResponse = FlaskUtil.buildHttpResponse(completeResponse[1], completeResponse[0], completeResponse[-1].enumValue, produces)
              if wrapperManager.shouldLogResponse():
                  try:
                      resourceMethodResponseStatus = completeResponse[-1]
                      log.prettyJson(
                          wrapperManager.resourceInstanceMethod,
                          LogConstant.LISTENER_RESPONSE,
                          {
                              'headers': FlaskUtil.safellyGetResponseHeaders(httpResponse),
                              'body': FlaskUtil.safellyGetFlaskResponseJson(httpResponse),
                              'status': resourceMethodResponseStatus.enumValue
                          },
                          condition = True,
                          logLevel = log.INFO
                      )
                  except Exception as exception:
                      log.failure(innerResourceInstanceMethod, 'Not possible to log response properly', exception)
  
              return httpResponse
          ReflectionHelper.overrideSignatures(innerResourceInstanceMethod, wrapperManager.resourceInstanceMethod)
          innerResourceInstanceMethod.url = url
          innerResourceInstanceMethod.requestHeaderClass = requestHeaderClass
          innerResourceInstanceMethod.requestParamClass = requestParamClass
          innerResourceInstanceMethod.requestClass = requestClass
          innerResourceInstanceMethod.responseClass = responseClass
          innerResourceInstanceMethod.responseHeaders = responseHeaders
          innerResourceInstanceMethod.apiKeyRequired = apiKeyRequired
          innerResourceInstanceMethod.produces = produces
          innerResourceInstanceMethod.consumes = consumes
          innerResourceInstanceMethod.logRequest = logRequest
          innerResourceInstanceMethod.logResponse = logResponse
          innerResourceInstanceMethod.enabled = enabled
          innerResourceInstanceMethod.muteLogs = muteLogs
          innerResourceInstanceMethod.muteStacktraceOnBusinessRuleException = resourceInstanceMethodMuteStacktraceOnBusinessRuleException
          innerResourceInstanceMethod.runInAThread = resourceInstanceMethodRunInAThread
          return innerResourceInstanceMethod
      return innerMethodWrapper
  
  
  def resolveListenerCallWithinAContext(
      args,
      kwargs,
      wrapperManager,
      roleRequired,
      apiKeyRequired,
      contextRequired,
      requestHeaderClass,
      requestParamClass,
      requestClass,
      responseClass,
      defaultResponseHeaders,
      consumes,
      resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
  
      requestUrl,
      requestVerb,
      requestHeaders,
      requestParams,
      requestBody,
  
      logRequestMessage = LogConstant.LISTENER_REQUEST,
      context = HttpDomain.LISTENER_CONTEXT
  ):
      ###- https://flask.palletsprojects.com/en/1.1.x/appcontext/
      # with wrapperManager.api.app.app_context():
      ###- https://flask.palletsprojects.com/en/2.1.x/appcontext/
      ###- https://flask.palletsprojects.com/en/2.1.x/reqcontext/
      ###- https://werkzeug.palletsprojects.com/en/2.1.x/test/#werkzeug.test.EnvironBuilder
      with wrapperManager.api.app.test_request_context(
          path = requestUrl,
          method = requestVerb,
          headers = requestHeaders,
          ###- query_string = requestParams, ###- query string already comes in the url
          json = requestBody
      ):
          resolveListenerCall(
              args,
              kwargs,
              wrapperManager,
              roleRequired,
              apiKeyRequired,
              contextRequired,
              requestHeaderClass,
              requestParamClass,
              requestClass,
              responseClass,
              defaultResponseHeaders,
              consumes,
              resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
  
              requestUrl,
              requestVerb,
              requestHeaders,
              requestParams,
              requestBody,
  
              logRequestMessage = logRequestMessage,
              context = context
          )
  
  
  def resolveListenerCall(
      args,
      kwargs,
      wrapperManager,
      roleRequired,
      apiKeyRequired,
      contextRequired,
      requestHeaderClass,
      requestParamClass,
      requestClass,
      responseClass,
      defaultResponseHeaders,
      consumes,
      resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
  
      requestUrl,
      requestVerb,
      requestHeaders,
      requestParams,
      requestBody,
  
      logRequestMessage = LogConstant.LISTENER_REQUEST,
      context = HttpDomain.LISTENER_CONTEXT
  ):
      completeResponse = None
      try:
          completeResponse = FlaskManager.handleAnyControllerMethodRequest(
              args,
              kwargs,
              consumes,
              wrapperManager.resourceInstance,
              wrapperManager.resourceInstanceMethod,
              contextRequired,
              apiKeyRequired,
              roleRequired,
              requestHeaderClass,
              requestParamClass,
              requestClass,
              wrapperManager.shouldLogRequest(),
              resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
              verb = requestVerb,
              requestHeaders = requestHeaders,
              requestParams = requestParams,
              requestBody = requestBody,
              logRequestMessage = logRequestMessage
          )
          FlaskManager.validateCompleteResponse(responseClass, completeResponse)
      except Exception as exception:
          log.log(resolveListenerCall, 'Failure at controller method execution. Getting complete response as exception', exception=exception, muteStackTrace=True)
          completeResponse = FlaskManager.getCompleteResponseByException(
              exception,
              wrapperManager.resourceInstance,
              wrapperManager.resourceInstanceMethod,
              resourceInstanceMethodMuteStacktraceOnBusinessRuleException,
              context = context
          )
      try:
          status = HttpStatus.map(completeResponse[-1])
          additionalResponseHeaders = completeResponse[1]
          if ObjectHelper.isNotNone(wrapperManager.resourceInstance.responseHeaders):
              additionalResponseHeaders = {**wrapperManager.resourceInstance.responseHeaders, **additionalResponseHeaders}
          if ObjectHelper.isNotNone(defaultResponseHeaders):
              additionalResponseHeaders = {**defaultResponseHeaders, **additionalResponseHeaders}
          responseBody = completeResponse[0] if ObjectHelper.isNotNone(completeResponse[0]) else {'message' : status.enumName}
          completeResponse = [responseBody, additionalResponseHeaders, status]
      except Exception as exception:
          log.failure(resolveListenerCall, f'Failure while parsing complete response: {completeResponse}. Returning simplified version of it', exception, muteStackTrace=True)
          completeResponse = getCompleteResponseByException(
              Exception(f'Not possible to handle complete response{c.DOT_SPACE_CAUSE}{str(exception)}'),
              wrapperManager.resourceInstance,
              wrapperManager.resourceInstanceMethod,
              resourceInstanceMethodMuteStacktraceOnBusinessRuleException
          )
      return completeResponse
  