private Map<String, String> sendDirectMessage(
      final ProcessContext context,
      final ProcessSession session,
      final FlowFile flowFile,
      final ProcessorLog logger,
      Message message,
      Recipient recipient) {

    String groupAttribute = context.getProperty(GROUP_ATTRIBUTE_NAME).getValue();
    String groupSufixAttribute =
        context.getProperty(GROUP_SUFIX).isSet()
            ? context.getProperty(GROUP_SUFIX).evaluateAttributeExpressions(flowFile).getValue()
            : "";
    String groupSubjectAttribute = context.getProperty(GROUP_SUBJECT_ATTRIBUTE_NAME).getValue();
    String participantsAttribute = context.getProperty(PARTICIPANTS_ATTRIBUTE_NAME).getValue();
    String groupName =
        message.getHeader().getRelatedConversationId() != null
            ? message.getHeader().getRelatedConversationId()
            : UUID.randomUUID().toString();
    groupName += groupSufixAttribute;
    String groupSubject =
        message.getHeader().getSubject() != null
            ? message.getHeader().getSubject()
            : "Private Message";

    String referenceAttributeName = context.getProperty(REFERENCE_ATTRIBUTE_NAME).getValue();

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

    // create references
    generatedReferences.put(recipient.getRecipientId(), UUID.randomUUID().toString());

    FlowFile clone = session.clone(flowFile);
    session.getProvenanceReporter().clone(flowFile, clone);

    clone = session.putAttribute(clone, groupAttribute, groupName);
    clone = session.putAttribute(clone, groupSubjectAttribute, groupSubject);
    clone =
        session.putAttribute(
            clone,
            referenceAttributeName,
            generatedReferences.values().stream().collect(Collectors.joining(",")));
    clone =
        session.putAttribute(
            clone,
            participantsAttribute,
            recipient.getDeliveryAddress().getPhysicalAddress().getAddress());
    session.getProvenanceReporter().modifyAttributes(clone);

    logger.debug("Routing message {} to {}.", new Object[] {clone, REL_DIRECT_MESSAGE});
    session.transfer(clone, REL_DIRECT_MESSAGE);
    session.getProvenanceReporter().route(clone, REL_DIRECT_MESSAGE);

    return generatedReferences;
  }
  private Map<String, String> sendMessagesToPreStablishedGroups(
      final ProcessContext context,
      final ProcessSession session,
      final FlowFile flowFile,
      final ProcessorLog logger,
      List<Recipient> recipients) {

    String groupAttribute = context.getProperty(GROUP_ATTRIBUTE_NAME).getValue();
    String groupSufixAttribute =
        context.getProperty(GROUP_SUFIX).isSet()
            ? context.getProperty(GROUP_SUFIX).evaluateAttributeExpressions(flowFile).getValue()
            : "";
    String referenceAttributeName = context.getProperty(REFERENCE_ATTRIBUTE_NAME).getValue();

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

    recipients
        .stream()
        .forEach(
            r -> {
              generatedReferences.put(r.getRecipientId(), UUID.randomUUID().toString());

              String address = r.getDeliveryAddress().getPhysicalAddress().getAddress();

              FlowFile clone = session.clone(flowFile);
              session.getProvenanceReporter().clone(flowFile, clone);

              clone =
                  session.putAttribute(
                      clone,
                      groupAttribute,
                      convertAddressToGroupName(address, groupSufixAttribute));
              clone =
                  session.putAttribute(
                      clone, referenceAttributeName, generatedReferences.get(r.getRecipientId()));
              session.getProvenanceReporter().modifyAttributes(clone);

              logger.debug("Routing message {} to {}.", new Object[] {clone, REL_PERMANENT_GROUP});
              session.transfer(clone, REL_PERMANENT_GROUP);
              session.getProvenanceReporter().route(clone, REL_PERMANENT_GROUP);
            });

    return generatedReferences;
  }
  private Map<String, String> sendMessageToDynamicGroup(
      final ProcessContext context,
      final ProcessSession session,
      final FlowFile flowFile,
      final ProcessorLog logger,
      Message message,
      List<Recipient> recipients) {

    String groupAttribute = context.getProperty(GROUP_ATTRIBUTE_NAME).getValue();
    String groupSufixAttribute =
        context.getProperty(GROUP_SUFIX).isSet()
            ? context.getProperty(GROUP_SUFIX).evaluateAttributeExpressions(flowFile).getValue()
            : "";
    String groupSubjectAttribute = context.getProperty(GROUP_SUBJECT_ATTRIBUTE_NAME).getValue();
    String participantsAttribute = context.getProperty(PARTICIPANTS_ATTRIBUTE_NAME).getValue();
    String groupName =
        message.getHeader().getRelatedConversationId() != null
            ? message.getHeader().getRelatedConversationId()
            : UUID.randomUUID().toString();
    groupName += groupSufixAttribute;
    String groupSubject =
        message.getHeader().getSubject() != null
            ? message.getHeader().getSubject()
            : "Group Message";

    String referenceAttributeName = context.getProperty(REFERENCE_ATTRIBUTE_NAME).getValue();

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

    // create references
    recipients
        .stream()
        .forEach(r -> generatedReferences.put(r.getRecipientId(), UUID.randomUUID().toString()));

    // convert the recipients insto a JSON array.
    JsonArray participants = new JsonArray();
    recipients
        .stream()
        .map(
            r -> {
              JsonObject jo = new JsonObject();
              jo.addProperty(
                  "participant", r.getDeliveryAddress().getPhysicalAddress().getAddress());
              return jo;
            })
        .forEach(participants::add);

    FlowFile clone = session.clone(flowFile);
    session.getProvenanceReporter().clone(flowFile, clone);

    clone = session.putAttribute(clone, groupAttribute, groupName);
    clone = session.putAttribute(clone, groupSubjectAttribute, groupSubject);
    clone =
        session.putAttribute(
            clone,
            referenceAttributeName,
            generatedReferences.values().stream().collect(Collectors.joining(",")));
    clone = session.putAttribute(clone, participantsAttribute, new Gson().toJson(participants));
    session.getProvenanceReporter().modifyAttributes(clone);

    logger.debug("Routing message {} to {}.", new Object[] {clone, REL_DYNAMIC_GROUP});
    session.transfer(clone, REL_DYNAMIC_GROUP);
    session.getProvenanceReporter().route(clone, REL_DYNAMIC_GROUP);

    return generatedReferences;
  }
  @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.");
    }
  }
Esempio n. 5
0
  private DestinationAccepts getDestinationAcceptance(
      final HttpClient client,
      final String uri,
      final ProcessorLog logger,
      final String transactionId)
      throws IOException {
    final HttpHead head = new HttpHead(uri);
    head.addHeader(TRANSACTION_ID_HEADER, transactionId);
    final HttpResponse response = client.execute(head);

    final int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode == Status.METHOD_NOT_ALLOWED.getStatusCode()) {
      // we assume that the destination can support FlowFile v1 always.
      return new DestinationAccepts(false, false, true, false, null);
    } else if (statusCode == Status.OK.getStatusCode()) {
      boolean acceptsFlowFileV3 = false;
      boolean acceptsFlowFileV2 = false;
      boolean acceptsFlowFileV1 = true;
      boolean acceptsGzip = false;
      Integer protocolVersion = null;

      Header[] headers = response.getHeaders(ACCEPT);
      if (headers != null) {
        for (final Header header : headers) {
          for (final String accepted : header.getValue().split(",")) {
            final String trimmed = accepted.trim();
            if (trimmed.equals(APPLICATION_FLOW_FILE_V3)) {
              acceptsFlowFileV3 = true;
            } else if (trimmed.equals(APPLICATION_FLOW_FILE_V2)) {
              acceptsFlowFileV2 = true;
            } else {
              // we assume that the destination accepts FlowFile V1 because legacy versions
              // of NiFi that accepted V1 did not use an Accept header to indicate it... or
              // any other header. So the bets thing we can do is just assume that V1 is
              // accepted, if we're going to send as FlowFile.
              acceptsFlowFileV1 = true;
            }
          }
        }
      }

      final Header destinationVersion = response.getFirstHeader(PROTOCOL_VERSION_HEADER);
      if (destinationVersion != null) {
        try {
          protocolVersion = Integer.valueOf(destinationVersion.getValue());
        } catch (final NumberFormatException e) {
          // nothing to do here really.... it's an invalid value, so treat the same as if not
          // specified
        }
      }

      if (acceptsFlowFileV3) {
        logger.debug(
            "Connection to URI "
                + uri
                + " will be using Content Type "
                + APPLICATION_FLOW_FILE_V3
                + " if sending data as FlowFile");
      } else if (acceptsFlowFileV2) {
        logger.debug(
            "Connection to URI "
                + uri
                + " will be using Content Type "
                + APPLICATION_FLOW_FILE_V2
                + " if sending data as FlowFile");
      } else if (acceptsFlowFileV1) {
        logger.debug(
            "Connection to URI "
                + uri
                + " will be using Content Type "
                + APPLICATION_FLOW_FILE_V1
                + " if sending data as FlowFile");
      }

      headers = response.getHeaders(ACCEPT_ENCODING);
      if (headers != null) {
        for (final Header header : headers) {
          for (final String accepted : header.getValue().split(",")) {
            if (accepted.equalsIgnoreCase("gzip")) {
              acceptsGzip = true;
            }
          }
        }
      }

      if (acceptsGzip) {
        logger.debug(
            "Connection to URI " + uri + " indicates that inline GZIP compression is supported");
      } else {
        logger.debug(
            "Connection to URI "
                + uri
                + " indicates that it does NOT support inline GZIP compression");
      }

      return new DestinationAccepts(
          acceptsFlowFileV3, acceptsFlowFileV2, acceptsFlowFileV1, acceptsGzip, protocolVersion);
    } else {
      logger.warn(
          "Unable to communicate with destination; when attempting to perform an HTTP HEAD, got unexpected response code of "
              + statusCode
              + ": "
              + response.getStatusLine().getReasonPhrase());
      return new DestinationAccepts(false, false, false, false, null);
    }
  }