diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/pom.xml b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/pom.xml new file mode 100644 index 0000000000..ab068d8ea8 --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.apache.nifi + nifi-graph-bundle + 1.16.0-SNAPSHOT + + nifi-neo4j-3-cypher-service-nar + nar + + + org.apache.nifi + nifi-graph-client-service-api-nar + 1.16.0-SNAPSHOT + nar + + + org.apache.nifi + nifi-neo4j-3-cypher-service + 1.16.0-SNAPSHOT + + + diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/LICENSE b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/LICENSE new file mode 100644 index 0000000000..2d2db982bb --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/LICENSE @@ -0,0 +1,246 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + +************ +MIT +************ + + This product optionally depends on 'Bouncy Castle Crypto APIs' to generate + a temporary self-signed X.509 certificate when the JVM does not provide the + equivalent functionality. It can be obtained at: + + * LICENSE: + * license/LICENSE.bouncycastle.txt (MIT License) + * HOMEPAGE: + * http://www.bouncycastle.org/ + + The binary distribution of this product bundles 'ParaNamer' and 'Paranamer Core' + which is available under a BSD style license. + + Copyright (c) 2006 Paul Hammant & ThoughtWorks Inc + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/NOTICE new file mode 100644 index 0000000000..bb2b72c5a1 --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service-nar/src/main/resources/META-INF/NOTICE @@ -0,0 +1,152 @@ +nifi-cypher-services-nar +Copyright 2017-2018 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +****************** +Apache Software License v2 +****************** + +The following binary components are provided under the Apache Software License v2 + + (ASLv2) Apache Commons Compress + The following NOTICE information applies: + Apache Commons Compress + Copyright 2002-2017 The Apache Software Foundation + + The files in the package org.apache.commons.compress.archivers.sevenz + were derived from the LZMA SDK, version 9.20 (C/ and CPP/7zip/), + which has been placed in the public domain: + + "LZMA SDK is placed in the public domain." (http://www.7-zip.org/sdk.html) + + (ASLv2) Apache Commons Configuration + The following NOTICE information applies: + Apache Commons Configuration + Copyright 2001-2017 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache Commons CSV + The following NOTICE information applies: + Apache Commons CSV + Copyright 2005-2016 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache Commons BeanUtils + The following NOTICE information applies: + Apache Commons BeanUtils + Copyright 2000-2016 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache Commons Lang + The following NOTICE information applies: + Apache Commons Lang + Copyright 2001-2015 The Apache Software Foundation + + This product includes software from the Spring Framework, + under the Apache License 2.0 (see: StringUtils.containsWhitespace()) + + (ASLv2) Apache Commons Codec + The following NOTICE information applies: + Apache Commons Codec + Copyright 2002-2014 The Apache Software Foundation + + src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java + contains test data from http://aspell.net/test/orig/batch0.tab. + Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) + + =============================================================================== + + The content of package org.apache.commons.codec.language.bm has been translated + from the original php source code available at http://stevemorse.org/phoneticinfo.htm + with permission from the original authors. + Original source copyright: + Copyright (c) 2008 Alexander Beider & Stephen P. Morse. + + (ASLv2) Apache Commons Logging + The following NOTICE information applies: + Apache Commons Logging + Copyright 2003-2013 The Apache Software Foundation + + (ASLv2) Apache Commons IO + The following NOTICE information applies: + Apache Commons IO + Copyright 2002-2016 The Apache Software Foundation + + (ASLv2) Apache Commons Text + The following NOTICE information applies: + Apache Commons Text + Copyright 2001-2018 The Apache Software Foundation + + (ASLv2) Caffeine + The following NOTICE information applies: + Caffeine (caching library) + Copyright Ben Manes + + (ASLv2) Jackson JSON processor + The following NOTICE information applies: + # Jackson JSON processor + + Jackson is a high-performance, Free/Open Source JSON processing library. + It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has + been in development since 2007. + It is currently developed by a community of developers, as well as supported + commercially by FasterXML.com. + + ## Licensing + + Jackson core and extension components may licensed under different licenses. + To find the details that apply to this artifact see the accompanying LICENSE file. + For more information, including possible other licensing options, contact + FasterXML.com (http://fasterxml.com). + + ## Credits + + A list of contributors may be found from CREDITS file, which is included + in some artifacts (usually source distributions); but is always available + from the source code management (SCM) system project uses. + + (ASL2 License) + (ASLv2) Neo4j Java Driver + Neo4j + Copyright © 20022018 Neo4j Sweden AB (referred to in this notice as "Neo4j") + [http://neo4j.com] + + + (ASLv2) Snappy Java + The following NOTICE information applies: + This product includes software developed by Google + Snappy: http://code.google.com/p/snappy/ (New BSD License) + + This product includes software developed by Apache + PureJavaCrc32C from apache-hadoop-common http://hadoop.apache.org/ + (Apache 2.0 license) + + This library containd statically linked libstdc++. This inclusion is allowed by + "GCC RUntime Library Exception" + http://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html + + +***************** +Public Domain +***************** + +The following binary components are provided to the 'Public Domain'. See project link for details. + + (Public Domain) XZ for Java (org.tukaani:xz:jar:1.5 - http://tukaani.org/xz/java.html + + +************************ +Creative Commons Attribution-ShareAlike 3.0 +************************ + +The following binary components are provided under the Creative Commons Attribution-ShareAlike 3.0. See project link for details. + + (CCAS 3.0) MaxMind DB (https://github.com/maxmind/MaxMind-DB) diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/pom.xml b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/pom.xml new file mode 100644 index 0000000000..64ffe418d0 --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + org.apache.nifi + nifi-graph-bundle + 1.16.0-SNAPSHOT + + nifi-neo4j-3-cypher-service + jar + + + + org.apache.nifi + nifi-api + + + + org.apache.nifi + nifi-lookup-service-api + provided + + + org.apache.nifi + nifi-graph-client-service-api + ${project.version} + provided + + + org.apache.nifi + nifi-ssl-context-service-api + provided + + + org.apache.nifi + nifi-utils + 1.16.0-SNAPSHOT + + + org.apache.nifi + nifi-record + + + org.apache.nifi + nifi-mock + 1.16.0-SNAPSHOT + test + + + org.apache.nifi + nifi-avro-record-utils + 1.16.0-SNAPSHOT + compile + + + org.apache.nifi + nifi-utils + 1.16.0-SNAPSHOT + + + org.apache.nifi + nifi-schema-registry-service-api + compile + + + org.apache.nifi + nifi-json-utils + 1.16.0-SNAPSHOT + compile + + + org.neo4j.driver + neo4j-java-driver + 1.7.5 + compile + + + + + + + + org.apache.rat + apache-rat-plugin + + + src/test/resources/simple.avsc + src/test/resources/test.csv + src/test/resources/test.properties + src/test/resources/test.xml + + + + + + diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypher3ClientService.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypher3ClientService.java new file mode 100644 index 0000000000..8925075f66 --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypher3ClientService.java @@ -0,0 +1,317 @@ +/* + * 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.graph; + +import org.apache.commons.lang3.StringUtils; +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.components.AllowableValue; +import org.apache.nifi.components.PropertyDescriptor; +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.ssl.SSLContextService; +import org.neo4j.driver.internal.InternalNode; +import org.neo4j.driver.v1.AuthTokens; +import org.neo4j.driver.v1.Config; +import org.neo4j.driver.v1.Driver; +import org.neo4j.driver.v1.GraphDatabase; +import org.neo4j.driver.v1.Record; +import org.neo4j.driver.v1.Session; +import org.neo4j.driver.v1.StatementResult; +import org.neo4j.driver.v1.summary.ResultSummary; +import org.neo4j.driver.v1.summary.SummaryCounters; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Deprecated +@Tags({ "graph", "neo4j", "cypher" }) +@CapabilityDescription("Provides a client service for managing connections to a Neo4J 3.X database. Configuration information for " + + "the Neo4J driver that corresponds to most of the settings for this service can be found here: " + + "https://neo4j.com/docs/driver-manual/current/client-applications/#driver-configuration") +public class Neo4JCypher3ClientService extends AbstractControllerService implements GraphClientService { + public static final PropertyDescriptor CONNECTION_URL = new PropertyDescriptor.Builder() + .name("neo4j-connection-url") + .displayName("Neo4j Connection URL") + .description("Neo4J endpoing to connect to.") + .required(true) + .defaultValue("bolt://localhost:7687") + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .build(); + + public static final PropertyDescriptor USERNAME = new PropertyDescriptor.Builder() + .name("neo4j-username") + .displayName("Username") + .description("Username for accessing Neo4J") + .required(true) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .addValidator(StandardValidators.NON_BLANK_VALIDATOR) + .build(); + + public static final PropertyDescriptor PASSWORD = new PropertyDescriptor.Builder() + .name("neo4j-password") + .displayName("Password") + .description("Password for Neo4J user. A dummy non-blank password is required even if it disabled on the server.") + .required(true) + .sensitive(true) + .addValidator(StandardValidators.NON_BLANK_VALIDATOR) + .build(); + public static AllowableValue LOAD_BALANCING_STRATEGY_ROUND_ROBIN = new AllowableValue(Config.LoadBalancingStrategy.ROUND_ROBIN.name(), "Round Robin", "Round Robin Strategy"); + + public static AllowableValue LOAD_BALANCING_STRATEGY_LEAST_CONNECTED = new AllowableValue(Config.LoadBalancingStrategy.LEAST_CONNECTED.name(), "Least Connected", "Least Connected Strategy"); + + protected static final PropertyDescriptor LOAD_BALANCING_STRATEGY = new PropertyDescriptor.Builder() + .name("neo4j-load-balancing-strategy") + .displayName("Load Balancing Strategy") + .description("Load Balancing Strategy (Round Robin or Least Connected)") + .required(false) + .defaultValue(LOAD_BALANCING_STRATEGY_ROUND_ROBIN.getValue()) + .allowableValues(LOAD_BALANCING_STRATEGY_ROUND_ROBIN, LOAD_BALANCING_STRATEGY_LEAST_CONNECTED) + .build(); + + public static final PropertyDescriptor CONNECTION_TIMEOUT = new PropertyDescriptor.Builder() + .name("neo4j-max-connection-time-out") + .displayName("Neo4J Max Connection Time Out (seconds)") + .description("The maximum time for establishing connection to the Neo4j") + .defaultValue("5 seconds") + .required(true) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(false) + .build(); + + public static final PropertyDescriptor MAX_CONNECTION_POOL_SIZE = new PropertyDescriptor.Builder() + .name("neo4j-max-connection-pool-size") + .displayName("Neo4J Max Connection Pool Size") + .description("The maximum connection pool size for Neo4j.") + .defaultValue("100") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(false) + .build(); + + public static final PropertyDescriptor MAX_CONNECTION_ACQUISITION_TIMEOUT = new PropertyDescriptor.Builder() + .name("neo4j-max-connection-acquisition-timeout") + .displayName("Neo4J Max Connection Acquisition Timeout") + .description("The maximum connection acquisition timeout.") + .defaultValue("60 second") + .required(true) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(false) + .build(); + + public static final PropertyDescriptor IDLE_TIME_BEFORE_CONNECTION_TEST = new PropertyDescriptor.Builder() + .name("neo4j-idle-time-before-test") + .displayName("Neo4J Idle Time Before Connection Test") + .description("The idle time before connection test.") + .defaultValue("60 seconds") + .required(true) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(false) + .build(); + + public static final PropertyDescriptor MAX_CONNECTION_LIFETIME = new PropertyDescriptor.Builder() + .name("neo4j-max-connection-lifetime") + .displayName("Neo4J Max Connection Lifetime") + .description("The maximum connection lifetime") + .defaultValue("3600 seconds") + .required(true) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(false) + .build(); + + public static final PropertyDescriptor ENCRYPTION = new PropertyDescriptor.Builder() + .name("neo4j-driver-tls-encryption-enabled") + .displayName("Neo4J Driver TLS Encryption") + .description("Is the driver using TLS encryption ?") + .defaultValue("true") + .required(true) + .allowableValues("true","false") + .addValidator(StandardValidators.BOOLEAN_VALIDATOR) + .sensitive(false) + .build(); + + public static final PropertyDescriptor SSL_CONTEXT_SERVICE = new PropertyDescriptor.Builder() + .name("SSL Context Service") + .description("The SSL Context Service used to provide client certificate information for TLS/SSL " + + "connections.") + .required(false) + .identifiesControllerService(SSLContextService.class) + .build(); + + protected Driver neo4JDriver; + protected String username; + protected String password; + protected String connectionUrl; + + private static final List DESCRIPTORS; + static { + List _temp = new ArrayList<>(); + _temp.add(CONNECTION_URL); + _temp.add(USERNAME); + _temp.add(PASSWORD); + _temp.add(LOAD_BALANCING_STRATEGY); + _temp.add(CONNECTION_TIMEOUT); + _temp.add(MAX_CONNECTION_POOL_SIZE); + _temp.add(MAX_CONNECTION_ACQUISITION_TIMEOUT); + _temp.add(IDLE_TIME_BEFORE_CONNECTION_TEST); + _temp.add(MAX_CONNECTION_LIFETIME); + _temp.add(ENCRYPTION); + _temp.add(SSL_CONTEXT_SERVICE); + + DESCRIPTORS = Collections.unmodifiableList(_temp); + } + + @Override + public List getSupportedPropertyDescriptors() { + return DESCRIPTORS; + } + + protected Driver getDriver(ConfigurationContext context) { + connectionUrl = context.getProperty(CONNECTION_URL).evaluateAttributeExpressions().getValue(); + username = context.getProperty(USERNAME).evaluateAttributeExpressions().getValue(); + password = context.getProperty(PASSWORD).getValue(); + + Config.ConfigBuilder configBuilder = Config.build(); + String loadBalancingStrategyValue = context.getProperty(LOAD_BALANCING_STRATEGY).getValue(); + if ( ! StringUtils.isBlank(loadBalancingStrategyValue) ) { + configBuilder = configBuilder.withLoadBalancingStrategy( + Config.LoadBalancingStrategy.valueOf(loadBalancingStrategyValue)); + } + + configBuilder.withMaxConnectionPoolSize(context.getProperty(MAX_CONNECTION_POOL_SIZE).evaluateAttributeExpressions().asInteger()); + + configBuilder.withConnectionTimeout(context.getProperty(CONNECTION_TIMEOUT).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS), TimeUnit.SECONDS); + + configBuilder.withConnectionAcquisitionTimeout(context.getProperty(MAX_CONNECTION_ACQUISITION_TIMEOUT).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS), TimeUnit.SECONDS); + + configBuilder.withMaxConnectionLifetime(context.getProperty(MAX_CONNECTION_LIFETIME).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS), TimeUnit.SECONDS); + + configBuilder.withConnectionLivenessCheckTimeout(context.getProperty(IDLE_TIME_BEFORE_CONNECTION_TEST).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS), TimeUnit.SECONDS); + + if ( context.getProperty(ENCRYPTION).asBoolean() ) { + configBuilder.withEncryption(); + } else { + configBuilder.withoutEncryption(); + } + + final SSLContextService sslService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class); + if (sslService != null) { + if ( sslService.isTrustStoreConfigured()) { + configBuilder.withTrustStrategy(Config.TrustStrategy.trustCustomCertificateSignedBy(new File( + sslService.getTrustStoreFile()))); + } else { + configBuilder.withTrustStrategy(Config.TrustStrategy.trustSystemCertificates()); + } + } + + return GraphDatabase.driver( connectionUrl, AuthTokens.basic( username, password), + configBuilder.toConfig()); + } + + /** + * Helper method to help testability + * @return Driver instance + */ + protected Driver getNeo4JDriver() { + return neo4JDriver; + } + + @OnEnabled + public void onEnabled(final ConfigurationContext context) { + try { + neo4JDriver = getDriver(context); + } catch(Exception e) { + getLogger().error("Error while getting connection " + e.getLocalizedMessage(),e); + throw new ProcessException("Error while getting connection" + e.getLocalizedMessage(),e); + } + getLogger().info("Neo4JCypherExecutor connection created for url {}", + new Object[] {connectionUrl}); + } + + @OnDisabled + public void close() { + getLogger().info("Closing driver"); + if ( neo4JDriver != null ) { + neo4JDriver.close(); + neo4JDriver = null; + } + } + + private Map handleInternalNode(Map recordMap) { + if (recordMap.size() == 1) { + String key = recordMap.keySet().iterator().next(); + Object value = recordMap.get(key); + if (value instanceof InternalNode) { + return ((InternalNode)value).asMap(); + } + } + + return recordMap; + } + + @Override + public Map executeQuery(String query, Map parameters, GraphQueryResultCallback handler) { + try (Session session = neo4JDriver.session()) { + StatementResult result = session.run(query, parameters); + long count = 0; + while (result.hasNext()) { + Record record = result.next(); + Map asMap = handleInternalNode(record.asMap()); + handler.process(asMap, result.hasNext()); + count++; + } + + ResultSummary summary = result.summary(); + SummaryCounters counters = summary.counters(); + + Map resultAttributes = new HashMap<>(); + resultAttributes.put(NODES_CREATED,String.valueOf(counters.nodesCreated())); + resultAttributes.put(RELATIONS_CREATED,String.valueOf(counters.relationshipsCreated())); + resultAttributes.put(LABELS_ADDED,String.valueOf(counters.labelsAdded())); + resultAttributes.put(NODES_DELETED,String.valueOf(counters.nodesDeleted())); + resultAttributes.put(RELATIONS_DELETED,String.valueOf(counters.relationshipsDeleted())); + resultAttributes.put(PROPERTIES_SET, String.valueOf(counters.propertiesSet())); + resultAttributes.put(ROWS_RETURNED, String.valueOf(count)); + + return resultAttributes; + } catch (Exception ex) { + throw new ProcessException("Query execution failed", ex); + } + } + + @Override + public String getTransitUrl() { + return connectionUrl; + } +} diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService new file mode 100644 index 0000000000..239a278dac --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService @@ -0,0 +1,16 @@ +# 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. + +org.apache.nifi.graph.Neo4JCypher3ClientService \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypher3Executor.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypher3Executor.java new file mode 100644 index 0000000000..fc1d34b789 --- /dev/null +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-3-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypher3Executor.java @@ -0,0 +1,152 @@ +/* + * 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.graph; + +import org.apache.nifi.util.NoOpProcessor; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.neo4j.driver.v1.AuthTokens; +import org.neo4j.driver.v1.Driver; +import org.neo4j.driver.v1.GraphDatabase; +import org.neo4j.driver.v1.Session; +import org.neo4j.driver.v1.StatementResult; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Neo4J Cypher integration tests. Please set the neo4j url, user and password according to your setup. + */ +public class ITNeo4JCypher3Executor { + protected TestRunner runner; + protected Driver driver; + protected String neo4jUrl = "bolt://localhost:7687"; + protected String user = "neo4j"; + protected String password = "testing1234"; + + private GraphClientService clientService; + private GraphQueryResultCallback EMPTY_CALLBACK = (record, hasMore) -> {}; + + @Before + public void setUp() throws Exception { + clientService = new Neo4JCypher3ClientService(); + runner = TestRunners.newTestRunner(NoOpProcessor.class); + runner.addControllerService("clientService", clientService); + runner.setProperty(clientService, Neo4JCypher3ClientService.USERNAME, user); + runner.setProperty(clientService, Neo4JCypher3ClientService.PASSWORD, password); + runner.enableControllerService(clientService); + driver = GraphDatabase.driver(neo4jUrl, AuthTokens.basic(user, password)); + executeSession("match (n) detach delete n"); + + StatementResult result = executeSession("match (n) return n"); + + assertEquals("nodes should be equal", 0, result.list().size()); + } + + protected StatementResult executeSession(String statement) { + try (Session session = driver.session()) { + return session.run(statement); + } + } + + @After + public void tearDown() { + runner = null; + if (driver != null) { + driver.close(); + } + driver = null; + } + + @Test + public void testCreateNodeNoReturn() { + String query = "create (n:nodereturn { name: \"Testing\"})"; + + Map attributes = clientService.executeQuery(query, new HashMap<>(), EMPTY_CALLBACK); + assertEquals("1",attributes.get(GraphClientService.LABELS_ADDED)); + assertEquals("1",attributes.get(GraphClientService.NODES_CREATED)); + assertEquals("0",attributes.get(GraphClientService.NODES_DELETED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_CREATED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_DELETED)); + assertEquals("1",attributes.get(GraphClientService.PROPERTIES_SET)); + assertEquals("0",attributes.get(GraphClientService.ROWS_RETURNED)); + } + + @Test + public void testCreateNodeOnePropertyWithReturn() { + String query = "create (n { name:'abc' }) return n.name"; + + final List> result = new ArrayList<>(); + Map attributes = clientService.executeQuery(query, new HashMap<>(), (record, hasMore) -> result.add(record)); + assertEquals("0",attributes.get(GraphClientService.LABELS_ADDED)); + assertEquals("1",attributes.get(GraphClientService.NODES_CREATED)); + assertEquals("0",attributes.get(GraphClientService.NODES_DELETED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_CREATED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_DELETED)); + assertEquals("1",attributes.get(GraphClientService.PROPERTIES_SET)); + assertEquals("1",attributes.get(GraphClientService.ROWS_RETURNED)); + assertEquals(1, result.size()); + assertEquals("abc", result.get(0).get("n.name")); + } + + @Test + public void testCreateNodeTwoPropertyOneLabelWithReturn() { + String query = "create (n:Person { name:'abc', age : 1 }) return n.name, n.age"; + + final List> result = new ArrayList<>(); + Map attributes = clientService.executeQuery(query, new HashMap<>(), (record, hasMore) -> { + result.add(record); + }); + + assertEquals("1",attributes.get(GraphClientService.LABELS_ADDED)); + assertEquals("1",attributes.get(GraphClientService.NODES_CREATED)); + assertEquals("0",attributes.get(GraphClientService.NODES_DELETED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_CREATED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_DELETED)); + assertEquals("2",attributes.get(GraphClientService.PROPERTIES_SET)); + assertEquals("1",attributes.get(GraphClientService.ROWS_RETURNED)); + assertEquals(1, result.size()); + assertEquals("abc", result.get(0).get("n.name")); + assertEquals(1l, result.get(0).get("n.age")); + } + + @Test + public void testCreateTwoNodeTwoPropertyOneRelationshipWithReturn() { + String query = "create (m:Person { name:'abc', age : 1 }) create (n:Person { name : 'pqr'}) create (m)-[r:hello]->(n) return m.name, n.name, type(r)"; + + List> result = new ArrayList<>(); + Map attributes = clientService.executeQuery(query, new HashMap<>(), ((record, isMore) -> result.add(record))); + assertEquals("2",attributes.get(GraphClientService.LABELS_ADDED)); + assertEquals("2",attributes.get(GraphClientService.NODES_CREATED)); + assertEquals("0",attributes.get(GraphClientService.NODES_DELETED)); + assertEquals("1",attributes.get(GraphClientService.RELATIONS_CREATED)); + assertEquals("0",attributes.get(GraphClientService.RELATIONS_DELETED)); + assertEquals("3",attributes.get(GraphClientService.PROPERTIES_SET)); + assertEquals("1",attributes.get(GraphClientService.ROWS_RETURNED)); + assertEquals(1, result.size()); + assertEquals("abc", result.get(0).get("m.name")); + assertEquals("pqr", result.get(0).get("n.name")); + assertEquals("hello", result.get(0).get("type(r)")); + } +} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/pom.xml b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/pom.xml index c0b94f657a..766224cfd7 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/pom.xml +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/pom.xml @@ -74,7 +74,7 @@ org.neo4j.driver neo4j-java-driver - 1.6.2 + 4.3.7 compile diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypherClientService.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypherClientService.java index 643bf29465..f6b53391ef 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypherClientService.java +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/main/java/org/apache/nifi/graph/Neo4JCypherClientService.java @@ -17,12 +17,10 @@ package org.apache.nifi.graph; -import org.apache.commons.lang3.StringUtils; 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.components.AllowableValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.ConfigurationContext; @@ -30,16 +28,16 @@ import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.ssl.SSLContextService; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Record; +import org.neo4j.driver.Result; +import org.neo4j.driver.Session; import org.neo4j.driver.internal.InternalNode; -import org.neo4j.driver.v1.AuthTokens; -import org.neo4j.driver.v1.Config; -import org.neo4j.driver.v1.Driver; -import org.neo4j.driver.v1.GraphDatabase; -import org.neo4j.driver.v1.Record; -import org.neo4j.driver.v1.Session; -import org.neo4j.driver.v1.StatementResult; -import org.neo4j.driver.v1.summary.ResultSummary; -import org.neo4j.driver.v1.summary.SummaryCounters; +import org.neo4j.driver.summary.ResultSummary; +import org.neo4j.driver.summary.SummaryCounters; import java.io.File; import java.util.ArrayList; @@ -50,9 +48,11 @@ import java.util.Map; import java.util.concurrent.TimeUnit; @Tags({ "graph", "neo4j", "cypher" }) -@CapabilityDescription("Provides a client service for managing connections to a Neo4J database. Configuration information for " + +@CapabilityDescription("Provides a client service for managing connections to a Neo4J 4.X or newer database. Configuration information for " + "the Neo4J driver that corresponds to most of the settings for this service can be found here: " + - "https://neo4j.com/docs/driver-manual/current/client-applications/#driver-configuration") + "https://neo4j.com/docs/driver-manual/current/client-applications/#driver-configuration. This service was created as a " + + "result of the break in driver compatibility between Neo4J 3.X and 4.X and might be renamed in the future if and when " + + "Neo4J should break driver compatibility between 4.X and a future release.") public class Neo4JCypherClientService extends AbstractControllerService implements GraphClientService { public static final PropertyDescriptor CONNECTION_URL = new PropertyDescriptor.Builder() .name("neo4j-connection-url") @@ -81,18 +81,6 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen .sensitive(true) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .build(); - public static AllowableValue LOAD_BALANCING_STRATEGY_ROUND_ROBIN = new AllowableValue(Config.LoadBalancingStrategy.ROUND_ROBIN.name(), "Round Robin", "Round Robin Strategy"); - - public static AllowableValue LOAD_BALANCING_STRATEGY_LEAST_CONNECTED = new AllowableValue(Config.LoadBalancingStrategy.LEAST_CONNECTED.name(), "Least Connected", "Least Connected Strategy"); - - protected static final PropertyDescriptor LOAD_BALANCING_STRATEGY = new PropertyDescriptor.Builder() - .name("neo4j-load-balancing-strategy") - .displayName("Load Balancing Strategy") - .description("Load Balancing Strategy (Round Robin or Least Connected)") - .required(false) - .defaultValue(LOAD_BALANCING_STRATEGY_ROUND_ROBIN.getValue()) - .allowableValues(LOAD_BALANCING_STRATEGY_ROUND_ROBIN, LOAD_BALANCING_STRATEGY_LEAST_CONNECTED) - .build(); public static final PropertyDescriptor CONNECTION_TIMEOUT = new PropertyDescriptor.Builder() .name("neo4j-max-connection-time-out") @@ -153,7 +141,7 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen .name("neo4j-driver-tls-encryption-enabled") .displayName("Neo4J Driver TLS Encryption") .description("Is the driver using TLS encryption ?") - .defaultValue("true") + .defaultValue("false") .required(true) .allowableValues("true","false") .addValidator(StandardValidators.BOOLEAN_VALIDATOR) @@ -179,7 +167,6 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen _temp.add(CONNECTION_URL); _temp.add(USERNAME); _temp.add(PASSWORD); - _temp.add(LOAD_BALANCING_STRATEGY); _temp.add(CONNECTION_TIMEOUT); _temp.add(MAX_CONNECTION_POOL_SIZE); _temp.add(MAX_CONNECTION_ACQUISITION_TIMEOUT); @@ -201,12 +188,7 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen username = context.getProperty(USERNAME).evaluateAttributeExpressions().getValue(); password = context.getProperty(PASSWORD).getValue(); - Config.ConfigBuilder configBuilder = Config.build(); - String loadBalancingStrategyValue = context.getProperty(LOAD_BALANCING_STRATEGY).getValue(); - if ( ! StringUtils.isBlank(loadBalancingStrategyValue) ) { - configBuilder = configBuilder.withLoadBalancingStrategy( - Config.LoadBalancingStrategy.valueOf(loadBalancingStrategyValue)); - } + Config.ConfigBuilder configBuilder = Config.builder(); configBuilder.withMaxConnectionPoolSize(context.getProperty(MAX_CONNECTION_POOL_SIZE).evaluateAttributeExpressions().asInteger()); @@ -235,7 +217,7 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen } return GraphDatabase.driver( connectionUrl, AuthTokens.basic( username, password), - configBuilder.toConfig()); + configBuilder.build()); } /** @@ -282,7 +264,7 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen @Override public Map executeQuery(String query, Map parameters, GraphQueryResultCallback handler) { try (Session session = neo4JDriver.session()) { - StatementResult result = session.run(query, parameters); + Result result = session.run(query, parameters); long count = 0; while (result.hasNext()) { Record record = result.next(); @@ -291,7 +273,7 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen count++; } - ResultSummary summary = result.summary(); + ResultSummary summary = result.consume(); SummaryCounters counters = summary.counters(); Map resultAttributes = new HashMap<>(); @@ -305,13 +287,12 @@ public class Neo4JCypherClientService extends AbstractControllerService implemen return resultAttributes; } catch (Exception ex) { - getLogger().error("", ex); - throw new ProcessException(ex); + throw new ProcessException("Query execution failed", ex); } } @Override public String getTransitUrl() { - return null; + return connectionUrl; } } diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypherExecutor.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypherExecutor.java index fd3566dcba..70e099ab7a 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypherExecutor.java +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/ITNeo4JCypherExecutor.java @@ -16,16 +16,17 @@ */ package org.apache.nifi.graph; +import org.apache.nifi.util.NoOpProcessor; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.neo4j.driver.v1.AuthTokens; -import org.neo4j.driver.v1.Driver; -import org.neo4j.driver.v1.GraphDatabase; -import org.neo4j.driver.v1.Session; -import org.neo4j.driver.v1.StatementResult; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Record; +import org.neo4j.driver.Session; import java.util.ArrayList; import java.util.HashMap; @@ -40,7 +41,7 @@ import static org.junit.Assert.assertEquals; public class ITNeo4JCypherExecutor { protected TestRunner runner; protected Driver driver; - protected String neo4jUrl = "bolt://localhost:7687"; + protected String neo4jUrl = "neo4j://localhost:7687"; protected String user = "neo4j"; protected String password = "testing1234"; @@ -50,23 +51,22 @@ public class ITNeo4JCypherExecutor { @BeforeEach public void setUp() throws Exception { clientService = new Neo4JCypherClientService(); - runner = TestRunners.newTestRunner(MockProcessor.class); + runner = TestRunners.newTestRunner(NoOpProcessor.class); runner.addControllerService("clientService", clientService); runner.setProperty(clientService, Neo4JCypherClientService.USERNAME, user); runner.setProperty(clientService, Neo4JCypherClientService.PASSWORD, password); runner.enableControllerService(clientService); - runner.setProperty(MockProcessor.CLIENT, "clientService"); driver = GraphDatabase.driver(neo4jUrl, AuthTokens.basic(user, password)); executeSession("match (n) detach delete n"); - StatementResult result = executeSession("match (n) return n"); + List result = executeSession("match (n) return n"); - assertEquals("nodes should be equal", 0, result.list().size()); + assertEquals("nodes should be equal", 0, result.size()); } - protected StatementResult executeSession(String statement) { + protected List executeSession(String statement) { try (Session session = driver.session()) { - return session.run(statement); + return session.run(statement).list(); } } diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/MockProcessor.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/MockProcessor.java deleted file mode 100644 index 5ae484457b..0000000000 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-neo4j-cypher-service/src/test/java/org/apache/nifi/graph/MockProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.graph; - -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.processor.AbstractProcessor; -import org.apache.nifi.processor.ProcessContext; -import org.apache.nifi.processor.ProcessSession; -import org.apache.nifi.processor.exception.ProcessException; - -import java.util.Arrays; -import java.util.List; - -public class MockProcessor extends AbstractProcessor { - public static final PropertyDescriptor CLIENT = new PropertyDescriptor.Builder() - .name("client") - .required(true) - .identifiesControllerService(GraphClientService.class) - .build(); - - public static final List PROPS = Arrays.asList(CLIENT); - - @Override - public List getSupportedPropertyDescriptors() { - return PROPS; - } - - @Override - public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { - - } -} diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/pom.xml b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/pom.xml index 69970c13c4..62d5543f09 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/pom.xml +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/pom.xml @@ -63,6 +63,11 @@ 1.16.0-SNAPSHOT compile + + org.apache.nifi + nifi-utils + 1.16.0-SNAPSHOT + org.apache.nifi nifi-schema-registry-service-api diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/GremlinClientServiceIT.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/GremlinClientServiceIT.java index bdec0bd322..ce447651b5 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/GremlinClientServiceIT.java +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/GremlinClientServiceIT.java @@ -18,6 +18,7 @@ package org.apache.nifi.graph; import org.apache.commons.io.IOUtils; +import org.apache.nifi.util.NoOpProcessor; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; import org.junit.After; @@ -39,10 +40,9 @@ public class GremlinClientServiceIT { @Before public void setup() throws Exception { clientService = new TestableGremlinClientService(); - runner = TestRunners.newTestRunner(MockProcessor.class); + runner = TestRunners.newTestRunner(NoOpProcessor.class); runner.addControllerService("gremlinService", clientService); runner.setProperty(clientService, AbstractTinkerpopClientService.CONTACT_POINTS, "localhost"); - runner.setProperty(MockProcessor.GREMLIN_CLIENT, "gremlinService"); runner.enableControllerService(clientService); runner.assertValid(); diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/MockProcessor.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/MockProcessor.java deleted file mode 100644 index 0504887d9d..0000000000 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/MockProcessor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.graph; - -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.processor.AbstractProcessor; -import org.apache.nifi.processor.ProcessContext; -import org.apache.nifi.processor.ProcessSession; -import org.apache.nifi.processor.exception.ProcessException; - -import java.util.Arrays; -import java.util.List; - -public class MockProcessor extends AbstractProcessor { - public static final PropertyDescriptor CLIENT = new PropertyDescriptor.Builder() - .name("client") - .required(false) - .identifiesControllerService(GraphClientService.class) - .build(); - public static final PropertyDescriptor GREMLIN_CLIENT = new PropertyDescriptor.Builder() - .name("gremlin-client") - .required(false) - .identifiesControllerService(GremlinClientService.class) - .build(); - - public static final List PROPS = Arrays.asList(CLIENT, GREMLIN_CLIENT); - - @Override - public List getSupportedPropertyDescriptors() { - return PROPS; - } - - @Override - public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { - - } -} diff --git a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/OpenCypherClientServiceIT.java b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/OpenCypherClientServiceIT.java index 6397d3f1a0..b15deff909 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/OpenCypherClientServiceIT.java +++ b/nifi-nar-bundles/nifi-graph-bundle/nifi-other-graph-services/src/test/java/org/apache/nifi/graph/OpenCypherClientServiceIT.java @@ -17,6 +17,7 @@ package org.apache.nifi.graph; +import org.apache.nifi.util.NoOpProcessor; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; @@ -57,10 +58,9 @@ public class OpenCypherClientServiceIT { @BeforeEach public void before() throws Exception { service = new OpenCypherClientService(); - runner = TestRunners.newTestRunner(MockProcessor.class); + runner = TestRunners.newTestRunner(NoOpProcessor.class); runner.addControllerService("clientService", service); runner.setProperty(service, AbstractTinkerpopClientService.CONTACT_POINTS, "localhost"); - runner.setProperty(MockProcessor.CLIENT, "clientService"); runner.enableControllerService(service); runner.assertValid(); diff --git a/nifi-nar-bundles/nifi-graph-bundle/pom.xml b/nifi-nar-bundles/nifi-graph-bundle/pom.xml index f9e9c9bc0e..1eacb7aede 100644 --- a/nifi-nar-bundles/nifi-graph-bundle/pom.xml +++ b/nifi-nar-bundles/nifi-graph-bundle/pom.xml @@ -33,6 +33,8 @@ nifi-graph-nar nifi-neo4j-cypher-service nifi-neo4j-cypher-service-nar + nifi-neo4j-3-cypher-service + nifi-neo4j-3-cypher-service-nar nifi-other-graph-services nifi-other-graph-services-nar