turcsanyip commented on code in PR #7644:
URL: https://github.com/apache/nifi/pull/7644#discussion_r1389400340


##########
nifi-nar-bundles/nifi-zendesk-bundle/nifi-zendesk-processors/src/main/java/org/apache/nifi/processors/zendesk/AbstractZendesk.java:
##########
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.zendesk;
+
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.common.zendesk.ZendeskAuthenticationContext;
+import org.apache.nifi.common.zendesk.ZendeskAuthenticationType;
+import org.apache.nifi.common.zendesk.ZendeskClient;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.REL_SUCCESS_NAME;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.WEB_CLIENT_SERVICE_PROVIDER;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_AUTHENTICATION_CREDENTIAL;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_AUTHENTICATION_TYPE;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_SUBDOMAIN;
+import static org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_USER;
+
+public abstract class AbstractZendesk extends AbstractProcessor {
+
+    static final String RECORD_COUNT_ATTRIBUTE_NAME = "record.count";
+
+    ZendeskClient zendeskClient;
+
+    static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name(REL_SUCCESS_NAME)
+            .description("For FlowFiles created as a result of a successful 
HTTP request.")
+            .build();
+
+    @OnScheduled
+    public void onScheduled(ProcessContext context) {
+        final WebClientServiceProvider webClientServiceProvider = 
context.getProperty(WEB_CLIENT_SERVICE_PROVIDER).asControllerService(WebClientServiceProvider.class);
+        final String user = 
context.getProperty(ZENDESK_USER).evaluateAttributeExpressions().getValue();
+        final ZendeskAuthenticationType authenticationType = 
ZendeskAuthenticationType.forName(context.getProperty(ZENDESK_AUTHENTICATION_TYPE).getValue());
+        final String authenticationCredentials = 
context.getProperty(ZENDESK_AUTHENTICATION_CREDENTIAL).evaluateAttributeExpressions().getValue();
+        final String subDomain = 
context.getProperty(ZENDESK_SUBDOMAIN).evaluateAttributeExpressions().getValue();

Review Comment:
   Minor:
   ```suggestion
           final String subdomain = 
context.getProperty(ZENDESK_SUBDOMAIN).evaluateAttributeExpressions().getValue();
   ```



##########
nifi-nar-bundles/nifi-zendesk-bundle/nifi-zendesk-common/src/main/java/org/apache/nifi/common/zendesk/ZendeskProperties.java:
##########
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.common.zendesk;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+import static 
org.apache.nifi.expression.ExpressionLanguageScope.FLOWFILE_ATTRIBUTES;
+
+public final class ZendeskProperties {
+
+    public static final String WEB_CLIENT_SERVICE_PROVIDER_NAME = 
"web-client-service-provider";
+    public static final String ZENDESK_SUBDOMAIN_NAME = "zendesk-subdomain";
+    public static final String ZENDESK_USER_NAME = "zendesk-user";
+    public static final String ZENDESK_AUTHENTICATION_TYPE_NAME = 
"zendesk-authentication-type-name";
+    public static final String ZENDESK_AUTHENTICATION_CREDENTIAL_NAME = 
"zendesk-authentication-value-name";
+    public static final String ZENDESK_TICKET_COMMENT_BODY_NAME = 
"zendesk-comment-body";
+    public static final String ZENDESK_TICKET_SUBJECT_NAME = "zendesk-subject";
+    public static final String ZENDESK_TICKET_PRIORITY_NAME = 
"zendesk-priority";
+    public static final String ZENDESK_TICKET_TYPE_NAME = "zendesk-type";
+    public static final String HTTPS = "https";
+    public static final String APPLICATION_JSON = "application/json";
+    public static final String ZENDESK_HOST_TEMPLATE = "%s.zendesk.com";
+    public static final String ZENDESK_CREATE_TICKET_RESOURCE = 
"/api/v2/tickets";
+    public static final String ZENDESK_CREATE_TICKETS_RESOURCE = 
"/api/v2/tickets/create_many";
+
+    public static final String ZENDESK_TICKET_ROOT_NODE = "/ticket";
+    public static final String ZENDESK_TICKETS_ROOT_NODE = "/tickets";
+
+    public static final String REL_SUCCESS_NAME = "success";
+    public static final String REL_FAILURE_NAME = "failure";
+
+    private ZendeskProperties() {}
+
+    public static final PropertyDescriptor WEB_CLIENT_SERVICE_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name(WEB_CLIENT_SERVICE_PROVIDER_NAME)
+            .displayName("Web Client Service Provider")
+            .description("Controller service for HTTP client operations.")
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .required(true)
+            .build();
+
+    public static final PropertyDescriptor ZENDESK_SUBDOMAIN = new 
PropertyDescriptor.Builder()
+            .name(ZENDESK_SUBDOMAIN_NAME)
+            .displayName("Subdomain Name")
+            .description("Name of the Zendesk subdomain.")
+            
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor ZENDESK_USER = new 
PropertyDescriptor.Builder()
+            .name(ZENDESK_USER_NAME)
+            .displayName("User Name")
+            .description("Login user to Zendesk subdomain.")
+            
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor ZENDESK_AUTHENTICATION_TYPE = new 
PropertyDescriptor.Builder()
+            .name(ZENDESK_AUTHENTICATION_TYPE_NAME)
+            .displayName("Authentication Type")
+            .description("Type of authentication to Zendesk API.")
+            .required(true)
+            .allowableValues(ZendeskAuthenticationType.class)
+            .build();
+
+    public static final PropertyDescriptor ZENDESK_AUTHENTICATION_CREDENTIAL = 
new PropertyDescriptor.Builder()
+            .name(ZENDESK_AUTHENTICATION_CREDENTIAL_NAME)
+            .displayName("Authentication Credential")
+            .description("Password or authentication token for Zendesk login 
user.")
+            
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+            .sensitive(true)
+            .required(true)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor.Builder 
ZENDESK_TICKET_COMMENT_BODY_BUILDER = new PropertyDescriptor.Builder()

Review Comment:
   I would not share the `PropertyDescriptor.Builder` instance but a 
`PropertyDescriptor` with a basic configuration instead. Then it can be 
customized via 
`PropertyDescriptor.Builder.fromPropertyDescriptor(PropertyDescriptor)` which 
creates a new builder. This way, different processors cannot change each 
other's builders.
   
   Interfering of builder configurations is not an issue here/now because 
`PutZendeskTicket` and `ZendeskRecordSink` are located in different NARs and 
the builder instance is not shared (as the result of the class loader 
isolation) but it can happen in the future that more processors will be added 
in the same bundle. Also, `fromPropertyDescriptor()` is more commonly used for 
sharing and extending  properties.
   
   



##########
nifi-nar-bundles/nifi-extension-utils/nifi-record-path-property/src/main/java/org/apache/nifi/record/RecordPathPropertyUtil.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.record;
+
+import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.record.path.FieldValue;
+import org.apache.nifi.record.path.RecordPath;
+import org.apache.nifi.record.path.RecordPathResult;
+import org.apache.nifi.serialization.record.DataType;
+import org.apache.nifi.serialization.record.Record;
+import org.apache.nifi.serialization.record.RecordFieldType;
+import org.apache.nifi.serialization.record.type.ChoiceDataType;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.util.stream.Collectors.toList;
+
+public final class RecordPathPropertyUtil {
+
+    private static final String NULL_VALUE = "null";
+    private static final Pattern RECORD_PATH_PATTERN = 
Pattern.compile("@\\{(/.*?)\\}");
+
+    private RecordPathPropertyUtil() {
+    }
+
+    /**
+     * Resolves the property value to be handled as a record path or a 
constant value.
+     *
+     * @param propertyValue property value to be resolved
+     * @param record        record to receive the value from if the field 
value is a record path
+     * @param flowFile      FlowFile to evaluate attribute expressions
+     */
+    public static String resolveFieldValue(PropertyValue propertyValue, Record 
record, FlowFile flowFile) {

Review Comment:
   It is not really straightforward what "field" means here.
   My suggestion would be (also with the modified parameter list discussed in 
another thread above in this PR):
   ```suggestion
       public static String resolvePropertyValue(String propertyValue, Record 
record) {
   ```



##########
nifi-nar-bundles/nifi-zendesk-bundle/nifi-zendesk-common/src/main/java/org/apache/nifi/common/zendesk/util/ZendeskRecordPathUtils.java:
##########
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.common.zendesk.util;
+
+import com.fasterxml.jackson.core.JsonPointer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.record.path.FieldValue;
+import org.apache.nifi.record.path.RecordPath;
+import org.apache.nifi.record.path.RecordPathResult;
+import org.apache.nifi.serialization.record.DataType;
+import org.apache.nifi.serialization.record.Record;
+import org.apache.nifi.serialization.record.RecordFieldType;
+import org.apache.nifi.serialization.record.type.ChoiceDataType;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.util.stream.Collectors.toList;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKETS_ROOT_NODE;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKET_ROOT_NODE;
+
+public final class ZendeskRecordPathUtils {

Review Comment:
   @mark-bathori Thanks for extracting `RecordPathPropertyUtil`! It looks good 
in general. However, it seems it was a bad idea of mine to suggest using 
`PropertyValue` as parameter type because it led to weird `PropertyValue` 
member fields in `ZendeskRecordSink`. If you agree, the `String propertyValue` 
parameter can be restored.



##########
nifi-nar-bundles/nifi-zendesk-bundle/nifi-zendesk-services/src/main/java/org/apache/nifi/services/zendesk/ZendeskRecordSink.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.services.zendesk;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnDisabled;
+import org.apache.nifi.annotation.lifecycle.OnEnabled;
+import org.apache.nifi.common.zendesk.ZendeskAuthenticationContext;
+import org.apache.nifi.common.zendesk.ZendeskAuthenticationType;
+import org.apache.nifi.common.zendesk.ZendeskClient;
+import 
org.apache.nifi.common.zendesk.validation.JsonPointerPropertyNameValidator;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.controller.AbstractControllerService;
+import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.record.sink.RecordSinkService;
+import org.apache.nifi.schema.access.SchemaNotFoundException;
+import org.apache.nifi.serialization.RecordSetWriter;
+import org.apache.nifi.serialization.RecordSetWriterFactory;
+import org.apache.nifi.serialization.WriteResult;
+import org.apache.nifi.serialization.record.Record;
+import org.apache.nifi.serialization.record.RecordSet;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.String.format;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.WEB_CLIENT_SERVICE_PROVIDER;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_AUTHENTICATION_CREDENTIAL;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_AUTHENTICATION_TYPE;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_CREATE_TICKETS_RESOURCE;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_CREATE_TICKET_RESOURCE;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_SUBDOMAIN;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKET_COMMENT_BODY_BUILDER;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKET_PRIORITY_BUILDER;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKET_SUBJECT_BUILDER;
+import static 
org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_TICKET_TYPE_BUILDER;
+import static org.apache.nifi.common.zendesk.ZendeskProperties.ZENDESK_USER;
+import static 
org.apache.nifi.common.zendesk.util.ZendeskRecordPathUtils.addDynamicField;
+import static 
org.apache.nifi.common.zendesk.util.ZendeskRecordPathUtils.addField;
+import static 
org.apache.nifi.common.zendesk.util.ZendeskUtils.createRequestObject;
+import static 
org.apache.nifi.common.zendesk.util.ZendeskUtils.getDynamicProperties;
+import static org.apache.nifi.common.zendesk.util.ZendeskUtils.getResponseBody;
+
+@Tags({"zendesk", "record", "sink"})
+@CapabilityDescription("Create Zendesk tickets using the Zendesk API." +
+        "The service requires a Zendesk account with configured access.")
+public class ZendeskRecordSink extends AbstractControllerService implements 
RecordSinkService {
+
+    private final ObjectMapper mapper = new ObjectMapper();
+    private Map<String, PropertyValue> dynamicProperties;
+    private volatile RecordSetWriterFactory writerFactory;
+    private Cache<String, ObjectNode> recordCache;
+    private ZendeskClient zendeskClient;
+
+    private PropertyValue commentBody;
+    private PropertyValue subject;
+    private PropertyValue priority;
+    private PropertyValue type;
+
+    public static final PropertyDescriptor ZENDESK_TICKET_COMMENT_BODY = 
ZENDESK_TICKET_COMMENT_BODY_BUILDER.build();
+    public static final PropertyDescriptor ZENDESK_TICKET_SUBJECT = 
ZENDESK_TICKET_SUBJECT_BUILDER.build();
+    public static final PropertyDescriptor ZENDESK_TICKET_PRIORITY = 
ZENDESK_TICKET_PRIORITY_BUILDER.build();
+    public static final PropertyDescriptor ZENDESK_TICKET_TYPE = 
ZENDESK_TICKET_TYPE_BUILDER.build();
+
+    static final PropertyDescriptor CACHE_SIZE = new 
PropertyDescriptor.Builder()
+            .name("cache-size")
+            .displayName("Cache Size")
+            .description("Specifies how many Zendesk ticket should be cached.")
+            .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR)
+            .defaultValue("1000")
+            .required(true)
+            .build();
+
+    static final PropertyDescriptor CACHE_EXPIRATION = new 
PropertyDescriptor.Builder()
+            .name("cache-expiration")
+            .displayName("Cache Expiration")
+            .description("Specifies how long a Zendesk ticket that is cached 
should remain in the cache.")
+            .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR)
+            .defaultValue("1 hour")
+            .required(true)
+            .build();
+
+    private static final List<PropertyDescriptor> PROPERTIES = 
Collections.unmodifiableList(Arrays.asList(
+            RecordSinkService.RECORD_WRITER_FACTORY,
+            WEB_CLIENT_SERVICE_PROVIDER,
+            ZENDESK_SUBDOMAIN,
+            ZENDESK_USER,
+            ZENDESK_AUTHENTICATION_TYPE,
+            ZENDESK_AUTHENTICATION_CREDENTIAL,
+            ZENDESK_TICKET_COMMENT_BODY,
+            ZENDESK_TICKET_SUBJECT,
+            ZENDESK_TICKET_PRIORITY,
+            ZENDESK_TICKET_TYPE,
+            CACHE_SIZE,
+            CACHE_EXPIRATION
+    ));
+
+    @Override
+    protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final 
String propertyDescriptorName) {
+        return new PropertyDescriptor.Builder()
+                .name(propertyDescriptorName)
+                .required(false)
+                .addValidator(new JsonPointerPropertyNameValidator())
+                
.expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT)
+                .dynamic(true)
+                .build();
+    }
+
+    @Override
+    public List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+        return PROPERTIES;
+    }
+
+    @Override
+    public WriteResult sendData(RecordSet recordSet, Map<String, String> 
attributes, boolean sendZeroResults) throws IOException {
+        final WriteResult writeResult;
+        List<ObjectNode> zendeskTickets = new ArrayList<>();
+
+        try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            try (final RecordSetWriter writer = 
writerFactory.createWriter(getLogger(), recordSet.getSchema(), out, 
attributes)) {
+
+                writer.beginRecordSet();
+                Record record;
+                while ((record = recordSet.next()) != null) {
+                    ObjectNode baseTicketNode = mapper.createObjectNode();
+                    addField("/comment/body", commentBody, baseTicketNode, 
record);
+                    addField("/subject", subject, baseTicketNode, record);
+                    addField("/priority", priority, baseTicketNode, record);
+                    addField("/type", type, baseTicketNode, record);
+
+                    for (Map.Entry<String, PropertyValue> dynamicProperty : 
dynamicProperties.entrySet()) {
+                        addDynamicField(dynamicProperty.getKey(), 
dynamicProperty.getValue(), baseTicketNode, record, null);
+                    }
+
+                    ObjectNode ticketNode = 
recordCache.getIfPresent(baseTicketNode.toString());
+                    if (ticketNode == null) {
+                        recordCache.put(baseTicketNode.toString(), 
baseTicketNode);
+                        zendeskTickets.add(baseTicketNode);
+                        writer.write(record);
+                        writer.flush();
+                    }
+                }
+                writeResult = writer.finishRecordSet();
+                writer.flush();
+            }
+        } catch (SchemaNotFoundException e) {
+            final String errorMessage = format("RecordSetWriter could not be 
created because the schema was not found. The schema name for the RecordSet to 
write is %s",
+                    recordSet.getSchema().getSchemaName());
+            throw new ProcessException(errorMessage, e);
+        }
+
+        if (!zendeskTickets.isEmpty()) {
+            try {
+                final InputStream inputStream = 
createRequestObject(zendeskTickets);
+                final URI uri = createUri(zendeskTickets.size());
+                final HttpResponseEntity response = 
zendeskClient.performPostRequest(uri, inputStream);
+
+                if (response.statusCode() != 
HttpResponseStatus.CREATED.getCode() && response.statusCode() != 
HttpResponseStatus.OK.getCode()) {
+                    getLogger().error("Failed to create zendesk ticket, HTTP 
status={}, response={}", response.statusCode(), getResponseBody(response));
+                }
+            } catch (IOException e) {
+                throw new IOException("Failed to post request to Zendesk", e);
+            }
+        }
+
+        return writeResult;
+    }
+
+    @OnEnabled
+    public void onEnabled(final ConfigurationContext context) {
+        writerFactory = 
context.getProperty(RecordSinkService.RECORD_WRITER_FACTORY).asControllerService(RecordSetWriterFactory.class);
+        dynamicProperties = getDynamicProperties(context, 
context.getProperties());
+
+        commentBody = context.getProperty(ZENDESK_TICKET_COMMENT_BODY);
+        subject = context.getProperty(ZENDESK_TICKET_SUBJECT);
+        priority = context.getProperty(ZENDESK_TICKET_PRIORITY);
+        type = context.getProperty(ZENDESK_TICKET_TYPE);
+
+        final String subDomain = 
context.getProperty(ZENDESK_SUBDOMAIN).evaluateAttributeExpressions().getValue();

Review Comment:
   Minor:
   ```suggestion
           final String subdomain = 
context.getProperty(ZENDESK_SUBDOMAIN).evaluateAttributeExpressions().getValue();
   ```



##########
nifi-nar-bundles/nifi-zendesk-bundle/nifi-zendesk-services-nar/pom.xml:
##########
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements. See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License. You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.nifi</groupId>
+        <artifactId>nifi-zendesk-bundle</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>nifi-zendesk-services-nar</artifactId>
+    <packaging>nar</packaging>
+
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <source.skip>true</source.skip>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-zendesk-services</artifactId>
+            <version>2.0.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-standard-services-api-nar</artifactId>

Review Comment:
   The parent NAR needs to be updated to `nifi-standard-shared-nar` due to 
[NIFI-12266](https://issues.apache.org/jira/browse/NIFI-12266).
   
   Please also rebase the PR branch onto the current main.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to