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]
