public <T extends Message> List<DeliveryAddress> validateMessageRecipients(MessageWrapper<T> msg)
      throws InvalidAddressException {
    LinkedList<DeliveryAddress> outList = new LinkedList<DeliveryAddress>();

    // Ok Here we go
    Set<String> validServices = services.getServiceNames();

    Set<Recipient> sendTo = msg.getMessage().getHeader().getRecipientsList();
    Iterator<Recipient> itr = sendTo.iterator();
    while (itr.hasNext()) {
      Recipient r = itr.next();
      DeliveryAddress adr = r.getDeliveryAddress();

      AddressType type = adr.getAddressType();

      if (type == null) {

        InvalidAddressException exp =
            new InvalidAddressException("Recipient passed with unknown/type");
        eventLogger.logUserExceptionEvent("validateMessageRecipients", exp);
        throw exp;
      }
      switch (type) {
        case Physical:
          {
            PhysicalAddress a = adr.getPhysicalAddress();
            if (!validServices.contains(a.getServiceId())) {
              outList.add(adr);
            }
            break;
          }
        case Group:
          {
            // TODO: Should we do a deep validation? - For not no - We
            // assume Group integrity

            if (groupMgr.findGroup(adr.getGroupAddress().getName()) == null) {
              outList.add(adr);
            }
            break;
          }
        case Party:
          {
            // TODO: Should we do a deep Validation? - For not no - We
            // assume user integrity;
            if (userMgr.findUser(adr.getPartyAddress().getName()) == null) {
              outList.add(adr);
            }
            break;
          }
        default:
          {
            outList.add(adr);
          }
      }
    }

    // Loop Address - Switch by type
    return outList;
  }
  public List<DeliveryAddress> validateAddress(DeliveryAddress adr) throws InvalidAddressException {
    LinkedList<DeliveryAddress> outList = new LinkedList<DeliveryAddress>();

    switch (adr.getAddressType()) {
      case Physical:
        {
          PhysicalAddress a = adr.getPhysicalAddress();
          if (!services.getServiceNames().contains(a.getServiceId())) {
            outList.add(adr);
          }
          break;
        }
      case Group:
        {
          // TODO: Should we do a deep validation? - For now no - We assume
          // Group integrity

          if (groupMgr.findGroup(adr.getGroupAddress().getName()) == null) {
            outList.add(adr);
          }
          break;
        }
      case Party:
        {
          // TODO: Should we do a deep Validation? - For now no - We assume
          // user integrity;
          if (userMgr.findUser(adr.getPartyAddress().getName()) == null) {
            outList.add(adr);
          }
          break;
        }
      default:
        {
          outList.add(adr);
        }
    }

    // Loop Address - Switch by type
    return outList;
  }
  @Test
  public void testRun() {
    String msgId = "TestMsgId01";

    // exception,type,messageId,msg
    SimpleMessage msg = new SimpleMessage();
    PhysicalAddress senderAdr = new PhysicalAddress();
    senderAdr.setServiceId("test");
    senderAdr.setAddressId("SomeId");
    senderAdr.setAddress("Address");
    DeliveryAddress senderDa = new DeliveryAddress(senderAdr);
    msg.getHeader().setSender(senderDa);
    msg.getHeader().setMessageId(msgId);
    PhysicalAddress receiverAdr = new PhysicalAddress();
    receiverAdr.setServiceId("testrcpt");
    receiverAdr.setAddressId("SomeReceiverId");
    receiverAdr.setAddress("ReceiverAddress");

    DeliveryAddress receiverDa = new DeliveryAddress(receiverAdr);

    ProcessingException exp = new ProcessingException();
    exp.setGeneratingMessage(msgId);
    exp.setIssuingService("IntegrationTest");
    exp.setFault("TestCase");

    String serverId = "ITTest";
    NotifyUCSClientOfException task =
        new NotifyUCSClientOfException(
            cleintReg,
            exp,
            ExceptionType.InvalidMessage,
            msgId,
            msg,
            serverId,
            resolver,
            receiverDa);
    task.run();
  }
  @Override
  public void onTrigger(final ProcessContext context, final ProcessSession session) {
    FlowFile flowFile = session.get();
    if (flowFile == null) {
      return;
    }

    final ProcessorLog logger = getLogger();

    final ObjectHolder<Throwable> errorHolder = new ObjectHolder<>(null);
    final ObjectHolder<MessageWrapper> messageWrapperHolder = new ObjectHolder<>(null);

    session.read(
        flowFile,
        (final InputStream rawIn) -> {
          try {
            messageWrapperHolder.set(MessageSerializer.deserializeMessageWrapper(rawIn));
          } catch (MessageSerializationException ex) {
            errorHolder.set(
                new RuntimeException(
                    "Error deserializing FlowFile content into a MessageWrapper instance. Routing to FAILURE",
                    ex));
          }
        });

    if (errorHolder.get() != null) {
      UCSCreateException.routeFlowFileToException(
          context,
          session,
          logger,
          flowFile,
          REL_FAILURE,
          null,
          "Error in message deserialization: " + errorHolder.get().getCause() != null
              ? errorHolder.get().getCause().getMessage()
              : errorHolder.get().getMessage(),
          ExceptionType.InvalidMessage,
          null,
          null);
      return;
    }

    Message message = messageWrapperHolder.get().getMessage();

    // resolve the sender. We couldn't resolved it before because we needed
    // the specific serviceId.
    UCSController ucsService =
        context.getProperty(UCS_CONTROLLER_SERVICE).asControllerService(UCSController.class);
    UserContactInfo uci =
        ucsService.resolveUserContactInfo(
            message.getHeader().getSender().getPhysicalAddress().getAddress());

    if (uci == null) {
      UCSCreateException.routeFlowFileToException(
          context,
          session,
          logger,
          flowFile,
          REL_FAILURE,
          null,
          "Unknown User: "******"Unknown Service "
              + context.getProperty(SERVICE_ID).getValue()
              + " for  User: "******"GROUP:").
    Map<Boolean, List<Recipient>> chatRecipients =
        message
            .getHeader()
            .getRecipientsList()
            .stream()
            .filter(
                r ->
                    r.getDeliveryAddress() != null
                        && r.getDeliveryAddress().getPhysicalAddress() != null)
            .filter(
                r ->
                    context
                        .getProperty(SERVICE_ID)
                        .getValue()
                        .equals(r.getDeliveryAddress().getPhysicalAddress().getServiceId()))
            .collect(
                Collectors.groupingBy(
                    r ->
                        r.getDeliveryAddress()
                            .getPhysicalAddress()
                            .getAddress()
                            .startsWith("GROUP:")));

    Map<String, String> generatedReferences = new HashMap<>();

    if (chatRecipients.containsKey(Boolean.TRUE)) {
      generatedReferences.putAll(
          this.sendMessagesToPreStablishedGroups(
              context, session, flowFile, logger, chatRecipients.get(Boolean.TRUE)));
    }

    if (chatRecipients.containsKey(Boolean.FALSE)) {
      List<Recipient> recipients = chatRecipients.get(Boolean.FALSE);
      if (recipients.size() == 1) {
        generatedReferences.putAll(
            this.sendDirectMessage(context, session, flowFile, logger, message, recipients.get(0)));
      } else {
        generatedReferences.putAll(
            this.sendMessageToDynamicGroup(
                context, session, flowFile, logger, message, recipients));
      }
    }

    logger.debug("Removing original FlowFile");
    session.remove(flowFile);

    // keep track of the generated references
    // TODO: is this check correct/enough?
    if (message.getHeader().isReceiptNotification()) {
      logger.debug(
          "The message has ReceiptNotification flag enabled -> We are persisting its references.");
      generatedReferences
          .entrySet()
          .stream()
          .forEach(
              (gr) -> {
                ucsService.saveMessageReference(message, gr.getKey(), gr.getValue());
              });
    } else {
      logger.debug(
          "The message doesn't have ReceiptNotification flag enabled -> We are not persisting its references.");
    }
  }
  /**
   * @param adr
   * @param addressMap
   * @param exclude - Set of Delivery addresses already seen to avoid loops
   * @param msg - The Message wrapper for context dependent addressing
   */
  public <T extends Message> void resolveAddress(
      DeliveryAddress adr,
      HashMap<String, List<PhysicalAddress>> addressMap,
      Set<DeliveryAddress> exclude,
      MessageWrapper<T> msg,
      Recipient r) {
    if (!exclude.contains(adr)) {
      exclude.add(adr);

      AddressType type = adr.getAddressType();

      if (type == null) {
        eventLogger.logSummaryEvent(
            LogEntryType.User_SendMessage,
            EventLevel.warn,
            "resolveAddress",
            "RecipientAddress Type Unknown",
            "Recipient passed with unknown/type");
        return;
      }

      switch (adr.getAddressType()) {
        case Physical:
          {
            PhysicalAddress a = adr.getPhysicalAddress();
            List<PhysicalAddress> list = addressMap.get(a.getServiceId());
            if (list == null) {
              list = new LinkedList<PhysicalAddress>();
              addressMap.put(a.getServiceId(), list);
            }
            list.add(a);

            break;
          }
        case Group:
          {
            DeliveryGroup grp = groupMgr.findGroup(adr.getGroupAddress().getName());
            if (grp != null) {
              // Loop the group
              LinkedList<DeliveryAddress> grpList = grp.getGroup();
              Iterator<DeliveryAddress> itr = grpList.iterator();
              while (itr.hasNext()) {
                resolveAddress(itr.next(), addressMap, exclude, msg, r);
              }
            }
            break;
          }
        case Party:
          {
            UserContactInfo userInfo = userMgr.findUser(adr.getPartyAddress().getName());
            if (userInfo != null) {

              // TODO Extend for context and better address selection - ay need more context for the
              // operation.
              // TODO Extend for presence

              // Resolve the user preferred address
              PhysicalAddress a = userInfo.getPreferredAddress();

              List<PhysicalAddress> list = addressMap.get(a.getServiceId());
              if (list == null) {
                list = new LinkedList<PhysicalAddress>();
                addressMap.put(a.getServiceId(), list);
              }
              list.add(a);
            }
            break;
          }
      }
    }
  }