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."); } }
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); } }