@Override
 public void execute(final Object message) throws Exception {
   if (logger.isInfoEnabled()) {
     logger.info("In Finished state");
   }
   final Class<?> klass = message.getClass();
   if (CallStateChanged.class.equals(klass)) {
     final CallStateChanged event = (CallStateChanged) message;
     callState = event.state();
     if (callRecord != null) {
       callRecord = callRecord.setStatus(callState.toString());
       final DateTime end = DateTime.now();
       callRecord = callRecord.setEndTime(end);
       final int seconds =
           (int) (end.getMillis() - callRecord.getStartTime().getMillis()) / 1000;
       callRecord = callRecord.setDuration(seconds);
       final CallDetailRecordsDao records = storage.getCallDetailRecordsDao();
       records.updateCallDetailRecord(callRecord);
     }
     callback();
   }
   context().stop(self());
 }
  @Override
  public void onReceive(final Object message) throws Exception {
    final Class<?> klass = message.getClass();
    final State state = fsm.state();
    final ActorRef sender = sender();
    final ActorRef source = self();

    if (logger.isInfoEnabled()) {
      logger.info(" ********** UssdInterpreter's Current State: " + state.toString());
      logger.info(" ********** UssdInterpreter's Processing Message: " + klass.getName());
    }

    if (StartInterpreter.class.equals(klass)) {
      ussdCall = ((StartInterpreter) message).resource();
      fsm.transition(message, acquiringCallInfo);
    } else if (message instanceof SipServletRequest) {
      SipServletRequest request = (SipServletRequest) message;
      String method = request.getMethod();
      if ("INFO".equalsIgnoreCase(method)) {
        fsm.transition(message, processingInfoRequest);
      } else if ("ACK".equalsIgnoreCase(method)) {
        fsm.transition(message, downloadingRcml);
      } else if ("BYE".equalsIgnoreCase(method)) {
        fsm.transition(message, disconnecting);
      } else if ("CANCEL".equalsIgnoreCase(method)) {
        fsm.transition(message, cancelling);
      }
    } else if (CallStateChanged.class.equals(klass)) {
      final CallStateChanged event = (CallStateChanged) message;
      callState = event.state();
      if (CallStateChanged.State.RINGING == event.state()) {
        if (logger.isInfoEnabled()) {
          logger.info("CallStateChanged.State.RINGING");
        }
      } else if (CallStateChanged.State.IN_PROGRESS == event.state()) {
        if (logger.isInfoEnabled()) {
          logger.info("CallStateChanged.State.IN_PROGRESS");
        }
      } else if (CallStateChanged.State.NO_ANSWER == event.state()
          || CallStateChanged.State.COMPLETED == event.state()
          || CallStateChanged.State.FAILED == event.state()
          || CallStateChanged.State.CANCELED == event.state()) {
        if (logger.isInfoEnabled()) {
          logger.info(
              "CallStateChanged.State.NO_ANSWER OR  CallStateChanged.State.COMPLETED OR CallStateChanged.State.FAILED or CallStateChanged.State.CANCELED");
        }
        fsm.transition(message, finished);
      } else if (CallStateChanged.State.BUSY == event.state()) {
        if (logger.isInfoEnabled()) {
          logger.info("CallStateChanged.State.BUSY");
        }
      }
      //            else if (CallStateChanged.State.COMPLETED == event.state()) {
      //                logger.info("CallStateChanged.State.Completed");
      //                fsm.transition(message, finished);
      //            }
    } else if (CallResponse.class.equals(klass)) {
      if (acquiringCallInfo.equals(state)) {
        @SuppressWarnings("unchecked")
        final CallResponse<CallInfo> response = (CallResponse<CallInfo>) message;
        // Check from whom is the message (initial call or outbound call) and update info
        // accordingly
        if (sender == ussdCall) {
          callInfo = response.get();
        } else {
          outboundCallInfo = response.get();
        }
        final String direction = callInfo.direction();
        if ("inbound".equals(direction)) {
          ussdCall.tell(new Answer(callInfo.sid()), source);
          // fsm.transition(message, downloadingRcml);
        } else {
          fsm.transition(message, downloadingRcml);
          //                     fsm.transition(message, initializingCall);
        }
      }
    } else if (DownloaderResponse.class.equals(klass)) {
      final DownloaderResponse response = (DownloaderResponse) message;
      if (response.succeeded() && HttpStatus.SC_OK == response.get().getStatusCode()) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Rcml URI : "
                  + response.get().getURI()
                  + "response succeeded "
                  + response.succeeded()
                  + ", statusCode "
                  + response.get().getStatusCode());
        }
        fsm.transition(message, ready);
      } else if (response.succeeded()
          && HttpStatus.SC_NOT_FOUND == response.get().getStatusCode()) {
        fsm.transition(message, notFound);
      } else {
        if (downloadingRcml.equals(state)) {
          if (fallbackUrl != null) {
            fsm.transition(message, downloadingFallbackRcml);
          } else {
            fsm.transition(message, finished);
          }
        } else {
          fsm.transition(message, finished);
        }
      }
    } else if (ParserFailed.class.equals(klass)) {
      if (logger.isInfoEnabled()) {
        logger.info("ParserFailed received. Will stop the call");
      }
      fsm.transition(message, cancelling);
    } else if (Tag.class.equals(klass)) {
      final Tag verb = (Tag) message;
      if (ussdLanguage.equals(verb.name())) {
        if (ussdLanguageTag == null) {
          ussdLanguageTag = verb;
          final GetNextVerb next = GetNextVerb.instance();
          parser.tell(next, source);
        } else {
          // We support only one Language element
          invalidVerb(verb);
        }
        return;
      } else if (ussdMessage.equals(verb.name())) {
        ussdMessageTags.add(verb);
        final GetNextVerb next = GetNextVerb.instance();
        parser.tell(next, source);
        return;
      } else if (ussdCollect.equals(verb.name())) {
        if (ussdCollectTag == null) {
          ussdCollectTag = verb;
          final GetNextVerb next = GetNextVerb.instance();
          parser.tell(next, source);
        } else {
          // We support only one Collect element
          invalidVerb(verb);
        }
        return;
      } else {
        invalidVerb(verb);
      }
    } else if (End.class.equals(klass)) {
      fsm.transition(message, preparingMessage);
    }
  }