You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/09/22 02:11:46 UTC
[47/51] [partial] nifi-registry git commit: NIFIREG-201 Refactoring
project structure to better isolate extensions
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowClient.java
new file mode 100644
index 0000000..6dd72e9
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowClient.java
@@ -0,0 +1,119 @@
+/*
+ * 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.registry.client;
+
+import org.apache.nifi.registry.diff.VersionedFlowDifference;
+import org.apache.nifi.registry.field.Fields;
+import org.apache.nifi.registry.flow.VersionedFlow;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Client for interacting with flows.
+ */
+public interface FlowClient {
+
+ /**
+ * Create the given flow in the given bucket.
+ *
+ * @param flow the flow to create
+ * @return the created flow with the identifier populated
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlow create(VersionedFlow flow) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the flow with the given id in the given bucket.
+ *
+ * The list of snapshot metadata will NOT be populated.
+ *
+ * @param bucketId a bucket id
+ * @param flowId a flow id
+ * @return the flow with the given id in the given bucket
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlow get(String bucketId, String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the flow with the given id.
+ *
+ * @param flowId a flow id
+ * @return the flow with the given id
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlow get(String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Updates the given flow with in the given bucket.
+ *
+ * The identifier of the flow must be populated in the flow object, and only the name and description can be updated.
+ *
+ * @param bucketId a bucket id
+ * @param flow the flow with updates
+ * @return the updated flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlow update(String bucketId, VersionedFlow flow) throws NiFiRegistryException, IOException;
+
+ /**
+ * Deletes the flow with the given id in the given bucket.
+ *
+ * @param bucketId a bucket id
+ * @param flowId the id of the flow to delete
+ * @return the deleted flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlow delete(String bucketId, String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the field info for flows.
+ *
+ * @return field info for flows
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ Fields getFields() throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the flows for a given bucket.
+ *
+ * @param bucketId a bucket id
+ * @return the flows in the given bucket
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ List<VersionedFlow> getByBucket(String bucketId) throws NiFiRegistryException, IOException;
+
+ /**
+ *
+ * @param bucketId a bucket id
+ * @param flowId the flow that is under inspection
+ * @param versionA the first version to use in the comparison
+ * @param versionB the second flow to use in the comparison
+ * @return the list of differences between the 2 flow versions grouped by component
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowDifference diff(final String bucketId, final String flowId,
+ final Integer versionA, final Integer versionB) throws NiFiRegistryException, IOException;
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
new file mode 100644
index 0000000..edf7beb
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
@@ -0,0 +1,133 @@
+/*
+ * 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.registry.client;
+
+import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
+import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Client for interacting with snapshots.
+ */
+public interface FlowSnapshotClient {
+
+ /**
+ * Creates a new snapshot/version for the given flow.
+ *
+ * The snapshot object must have the version populated, and will receive an error if the submitted version is
+ * not the next one-up version.
+ *
+ * @param snapshot the new snapshot
+ * @return the created snapshot
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshot create(VersionedFlowSnapshot snapshot) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the snapshot for the given bucket, flow, and version.
+ *
+ * @param bucketId the bucket id
+ * @param flowId the flow id
+ * @param version the version
+ * @return the snapshot with the given version of the given flow in the given bucket
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshot get(String bucketId, String flowId, int version) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the snapshot for the given flow and version.
+ *
+ * @param flowId the flow id
+ * @param version the version
+ * @return the snapshot with the given version of the given flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshot get(String flowId, int version) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the latest snapshot for the given flow.
+ *
+ * @param bucketId the bucket id
+ * @param flowId the flow id
+ * @return the snapshot with the latest version for the given flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshot getLatest(String bucketId, String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the latest snapshot for the given flow.
+ *
+ * @param flowId the flow id
+ * @return the snapshot with the latest version for the given flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshot getLatest(String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the latest snapshot metadata for the given flow.
+ *
+ * @param bucketId the bucket id
+ * @param flowId the flow id
+ * @return the snapshot metadata for the latest version of the given flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshotMetadata getLatestMetadata(String bucketId, String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the latest snapshot metadata for the given flow.
+ *
+ * @param flowId the flow id
+ * @return the snapshot metadata for the latest version of the given flow
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ VersionedFlowSnapshotMetadata getLatestMetadata(String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets a list of the metadata for all snapshots of a given flow.
+ *
+ * The contents of each snapshot are not part of the response.
+ *
+ * @param bucketId the bucket id
+ * @param flowId the flow id
+ * @return the list of snapshot metadata
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ List<VersionedFlowSnapshotMetadata> getSnapshotMetadata(String bucketId, String flowId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets a list of the metadata for all snapshots of a given flow.
+ *
+ * The contents of each snapshot are not part of the response.
+ *
+ * @param flowId the flow id
+ * @return the list of snapshot metadata
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ List<VersionedFlowSnapshotMetadata> getSnapshotMetadata(String flowId) throws NiFiRegistryException, IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/ItemsClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/ItemsClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/ItemsClient.java
new file mode 100644
index 0000000..96fa801
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/ItemsClient.java
@@ -0,0 +1,64 @@
+/*
+ * 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.registry.client;
+
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.field.Fields;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Client for interacting with bucket items.
+ *
+ * Bucket items contain the common fields across anything stored in the registry.
+ *
+ * Each item contains a type field and a link to the URI of the specific item.
+ *
+ * i.e. The link field of a flow item would contain the URI to the specific flow.
+ */
+public interface ItemsClient {
+
+ /**
+ * Gets all bucket items in the registry.
+ *
+ * @return the list of all bucket items
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ List<BucketItem> getAll() throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets all bucket items for the given bucket.
+ *
+ * @param bucketId the bucket id
+ * @return the list of items in the given bucket
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ List<BucketItem> getByBucket(String bucketId) throws NiFiRegistryException, IOException;
+
+ /**
+ * Gets the field info for bucket items.
+ *
+ * @return the list of field info
+ * @throws NiFiRegistryException if an error is encountered other than IOException
+ * @throws IOException if an I/O error is encountered
+ */
+ Fields getFields() throws NiFiRegistryException, IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClient.java
new file mode 100644
index 0000000..07fb817
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClient.java
@@ -0,0 +1,89 @@
+/*
+ * 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.registry.client;
+
+import java.io.Closeable;
+
+/**
+ * A client for interacting with the REST API of a NiFi registry instance.
+ */
+public interface NiFiRegistryClient extends Closeable {
+
+ /**
+ * @return the client for interacting with buckets
+ */
+ BucketClient getBucketClient();
+
+ /**
+ * @return the client for interacting with buckets on behalf of the given proxied entities
+ */
+ BucketClient getBucketClient(String ... proxiedEntity);
+
+ /**
+ * @return the client for interacting with flows
+ */
+ FlowClient getFlowClient();
+
+ /**
+ * @return the client for interacting with flows on behalf of the given proxied entities
+ */
+ FlowClient getFlowClient(String ... proxiedEntity);
+
+ /**
+ * @return the client for interacting with flows/snapshots
+ */
+ FlowSnapshotClient getFlowSnapshotClient();
+
+ /**
+ * @return the client for interacting with flows/snapshots on behalf of the given proxied entities
+ */
+ FlowSnapshotClient getFlowSnapshotClient(String ... proxiedEntity);
+
+ /**
+ * @return the client for interacting with bucket items
+ */
+ ItemsClient getItemsClient();
+
+ /**
+ * @return the client for interacting with bucket items on behalf of the given proxied entities
+ */
+ ItemsClient getItemsClient(String ... proxiedEntity);
+
+ /**
+ * @return the client for obtaining information about the current user
+ */
+ UserClient getUserClient();
+
+ /**
+ * @return the client for obtaining information about the current user based on the given proxied entities
+ */
+ UserClient getUserClient(String ... proxiedEntity);
+
+ /**
+ * The builder interface that implementations should provide for obtaining the client.
+ */
+ interface Builder {
+
+ Builder config(NiFiRegistryClientConfig clientConfig);
+
+ NiFiRegistryClientConfig getConfig();
+
+ NiFiRegistryClient build();
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
new file mode 100644
index 0000000..de77b51
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
@@ -0,0 +1,257 @@
+/*
+ * 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.registry.client;
+
+import org.apache.nifi.registry.security.util.KeyStoreUtils;
+import org.apache.nifi.registry.security.util.KeystoreType;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+/**
+ * Configuration for a NiFiRegistryClient.
+ */
+public class NiFiRegistryClientConfig {
+
+ private final String baseUrl;
+ private final SSLContext sslContext;
+ private final String keystoreFilename;
+ private final String keystorePass;
+ private final String keyPass;
+ private final KeystoreType keystoreType;
+ private final String truststoreFilename;
+ private final String truststorePass;
+ private final KeystoreType truststoreType;
+ private final HostnameVerifier hostnameVerifier;
+ private final Integer readTimeout;
+ private final Integer connectTimeout;
+
+
+ private NiFiRegistryClientConfig(final Builder builder) {
+ this.baseUrl = builder.baseUrl;
+ this.sslContext = builder.sslContext;
+ this.keystoreFilename = builder.keystoreFilename;
+ this.keystorePass = builder.keystorePass;
+ this.keyPass = builder.keyPass;
+ this.keystoreType = builder.keystoreType;
+ this.truststoreFilename = builder.truststoreFilename;
+ this.truststorePass = builder.truststorePass;
+ this.truststoreType = builder.truststoreType;
+ this.hostnameVerifier = builder.hostnameVerifier;
+ this.readTimeout = builder.readTimeout;
+ this.connectTimeout = builder.connectTimeout;
+ }
+
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+
+ public SSLContext getSslContext() {
+ if (sslContext != null) {
+ return sslContext;
+ }
+
+ final KeyManagerFactory keyManagerFactory;
+ if (keystoreFilename != null && keystorePass != null && keystoreType != null) {
+ try {
+ // prepare the keystore
+ final KeyStore keyStore = KeyStoreUtils.getKeyStore(keystoreType.name());
+ try (final InputStream keyStoreStream = new FileInputStream(new File(keystoreFilename))) {
+ keyStore.load(keyStoreStream, keystorePass.toCharArray());
+ }
+ keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+
+ if (keyPass == null) {
+ keyManagerFactory.init(keyStore, keystorePass.toCharArray());
+ } else {
+ keyManagerFactory.init(keyStore, keyPass.toCharArray());
+ }
+ } catch (final Exception e) {
+ throw new IllegalStateException("Failed to load Keystore", e);
+ }
+ } else {
+ keyManagerFactory = null;
+ }
+
+ final TrustManagerFactory trustManagerFactory;
+ if (truststoreFilename != null && truststorePass != null && truststoreType != null) {
+ try {
+ // prepare the truststore
+ final KeyStore trustStore = KeyStoreUtils.getTrustStore(truststoreType.name());
+ try (final InputStream trustStoreStream = new FileInputStream(new File(truststoreFilename))) {
+ trustStore.load(trustStoreStream, truststorePass.toCharArray());
+ }
+ trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(trustStore);
+ } catch (final Exception e) {
+ throw new IllegalStateException("Failed to load Truststore", e);
+ }
+ } else {
+ trustManagerFactory = null;
+ }
+
+ if (keyManagerFactory != null || trustManagerFactory != null) {
+ try {
+ // initialize the ssl context
+ KeyManager[] keyManagers = keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null;
+ TrustManager[] trustManagers = trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
+ final SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagers, trustManagers, new SecureRandom());
+ sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
+
+ return sslContext;
+ } catch (final Exception e) {
+ throw new IllegalStateException("Created keystore and truststore but failed to initialize SSLContext", e);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public String getKeystoreFilename() {
+ return keystoreFilename;
+ }
+
+ public String getKeystorePass() {
+ return keystorePass;
+ }
+
+ public String getKeyPass() {
+ return keyPass;
+ }
+
+ public KeystoreType getKeystoreType() {
+ return keystoreType;
+ }
+
+ public String getTruststoreFilename() {
+ return truststoreFilename;
+ }
+
+ public String getTruststorePass() {
+ return truststorePass;
+ }
+
+ public KeystoreType getTruststoreType() {
+ return truststoreType;
+ }
+
+ public HostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+ public Integer getReadTimeout() {
+ return readTimeout;
+ }
+
+ public Integer getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ /**
+ * Builder for client configuration.
+ */
+ public static class Builder {
+
+ private String baseUrl;
+ private SSLContext sslContext;
+ private String keystoreFilename;
+ private String keystorePass;
+ private String keyPass;
+ private KeystoreType keystoreType;
+ private String truststoreFilename;
+ private String truststorePass;
+ private KeystoreType truststoreType;
+ private HostnameVerifier hostnameVerifier;
+ private Integer readTimeout;
+ private Integer connectTimeout;
+
+ public Builder baseUrl(final String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public Builder sslContext(final SSLContext sslContext) {
+ this.sslContext = sslContext;
+ return this;
+ }
+
+ public Builder keystoreFilename(final String keystoreFilename) {
+ this.keystoreFilename = keystoreFilename;
+ return this;
+ }
+
+ public Builder keystorePassword(final String keystorePass) {
+ this.keystorePass = keystorePass;
+ return this;
+ }
+
+ public Builder keyPassword(final String keyPass) {
+ this.keyPass = keyPass;
+ return this;
+ }
+
+ public Builder keystoreType(final KeystoreType keystoreType) {
+ this.keystoreType = keystoreType;
+ return this;
+ }
+
+ public Builder truststoreFilename(final String truststoreFilename) {
+ this.truststoreFilename = truststoreFilename;
+ return this;
+ }
+
+ public Builder truststorePassword(final String truststorePass) {
+ this.truststorePass = truststorePass;
+ return this;
+ }
+
+ public Builder truststoreType(final KeystoreType truststoreType) {
+ this.truststoreType = truststoreType;
+ return this;
+ }
+
+ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
+ this.hostnameVerifier = hostnameVerifier;
+ return this;
+ }
+
+ public Builder readTimeout(final Integer readTimeout) {
+ this.readTimeout = readTimeout;
+ return this;
+ }
+
+ public Builder connectTimeout(final Integer connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ return this;
+ }
+
+ public NiFiRegistryClientConfig build() {
+ return new NiFiRegistryClientConfig(this);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryException.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryException.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryException.java
new file mode 100644
index 0000000..273a032
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.registry.client;
+
+/**
+ * Indicates an error interacting with the NiFi registry for a reason other than IOException.
+ */
+public class NiFiRegistryException extends Exception {
+
+ public NiFiRegistryException(final String message) {
+ super(message);
+ }
+
+ public NiFiRegistryException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
new file mode 100644
index 0000000..181f7af
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
@@ -0,0 +1,42 @@
+/*
+ * 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.registry.client;
+
+import org.apache.nifi.registry.authorization.CurrentUser;
+
+import java.io.IOException;
+
+public interface UserClient {
+
+ /**
+ * Obtains the access status of the current user.
+ *
+ * If the UserClient was obtained with proxied entities, then the access status should represent the status
+ * of the last identity in the chain.
+ *
+ * If the UserClient was obtained without proxied entities, then it would represent the identity of the certificate
+ * in the keystore used by the client.
+ *
+ * If the registry is not in secure mode, the anonymous identity is expected to be returned along with a flag indicating
+ * the user is anonymous.
+ *
+ * @return the access status of the current user
+ * @throws NiFiRegistryException if the proxying user is not a valid proxy or identity claim is otherwise invalid
+ */
+ CurrentUser getAccessStatus() throws NiFiRegistryException, IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
new file mode 100644
index 0000000..479699e
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
@@ -0,0 +1,120 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.nifi.registry.client.NiFiRegistryException;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for the client operations to share exception handling.
+ *
+ * Sub-classes should always execute a request from getRequestBuilder(target) to ensure proper headers are sent.
+ */
+public class AbstractJerseyClient {
+
+ private final Map<String,String> headers;
+
+ public AbstractJerseyClient(final Map<String, String> headers) {
+ this.headers = headers == null ? Collections.emptyMap() : Collections.unmodifiableMap(new HashMap<>(headers));
+ }
+
+ protected Map<String,String> getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Creates a new Invocation.Builder for the given WebTarget with the headers added to the builder.
+ *
+ * @param webTarget the target for the request
+ * @return the builder for the target with the headers added
+ */
+ protected Invocation.Builder getRequestBuilder(final WebTarget webTarget) {
+ final Invocation.Builder requestBuilder = webTarget.request();
+ headers.entrySet().stream().forEach(e -> requestBuilder.header(e.getKey(), e.getValue()));
+ return requestBuilder;
+ }
+
+ /**
+ * Executes the given action and returns the result.
+ *
+ * @param action the action to execute
+ * @param errorMessage the message to use if a NiFiRegistryException is thrown
+ * @param <T> the return type of the action
+ * @return the result of the action
+ * @throws NiFiRegistryException if any exception other than IOException is encountered
+ * @throws IOException if an I/O error occurs communicating with the registry
+ */
+ protected <T> T executeAction(final String errorMessage, final NiFiRegistryAction<T> action) throws NiFiRegistryException, IOException {
+ try {
+ return action.execute();
+ } catch (final Exception e) {
+ final Throwable ioeCause = getIOExceptionCause(e);
+
+ if (ioeCause == null) {
+ final StringBuilder errorMessageBuilder = new StringBuilder(errorMessage);
+
+ // see if we have a WebApplicationException, and if so add the response body to the error message
+ if (e instanceof WebApplicationException) {
+ final Response response = ((WebApplicationException) e).getResponse();
+ final String responseBody = response.readEntity(String.class);
+ errorMessageBuilder.append(": ").append(responseBody);
+ }
+
+ throw new NiFiRegistryException(errorMessageBuilder.toString(), e);
+ } else {
+ throw (IOException) ioeCause;
+ }
+ }
+ }
+
+
+ /**
+ * An action to execute with the given return type.
+ *
+ * @param <T> the return type of the action
+ */
+ protected interface NiFiRegistryAction<T> {
+
+ T execute();
+
+ }
+
+ /**
+ * @param e an exception that was encountered interacting with the registry
+ * @return the IOException that caused this exception, or null if the an IOException did not cause this exception
+ */
+ protected Throwable getIOExceptionCause(final Throwable e) {
+ if (e == null) {
+ return null;
+ }
+
+ if (e instanceof IOException) {
+ return e;
+ }
+
+ return getIOExceptionCause(e.getCause());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/BucketItemDeserializer.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/BucketItemDeserializer.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/BucketItemDeserializer.java
new file mode 100644
index 0000000..5640d43
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/BucketItemDeserializer.java
@@ -0,0 +1,76 @@
+/*
+ * 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.registry.client.impl;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.bucket.BucketItemType;
+import org.apache.nifi.registry.flow.VersionedFlow;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class BucketItemDeserializer extends StdDeserializer<BucketItem[]> {
+
+ public BucketItemDeserializer() {
+ super(BucketItem[].class);
+ }
+
+ @Override
+ public BucketItem[] deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
+ final JsonNode arrayNode = jsonParser.getCodec().readTree(jsonParser);
+
+ final List<BucketItem> bucketItems = new ArrayList<>();
+
+ final Iterator<JsonNode> nodeIter = arrayNode.elements();
+ while (nodeIter.hasNext()) {
+ final JsonNode node = nodeIter.next();
+
+ final String type = node.get("type").asText();
+ if (StringUtils.isBlank(type)) {
+ throw new IllegalStateException("BucketItem type cannot be null or blank");
+ }
+
+ final BucketItemType bucketItemType;
+ try {
+ bucketItemType = BucketItemType.valueOf(type);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unknown type for BucketItem: " + type, e);
+ }
+
+
+ switch (bucketItemType) {
+ case Flow:
+ final VersionedFlow versionedFlow = jsonParser.getCodec().treeToValue(node, VersionedFlow.class);
+ bucketItems.add(versionedFlow);
+ break;
+ default:
+ throw new IllegalStateException("Unknown type for BucketItem");
+ }
+ }
+
+ return bucketItems.toArray(new BucketItem[bucketItems.size()]);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyBucketClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyBucketClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyBucketClient.java
new file mode 100644
index 0000000..f84f8c6
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyBucketClient.java
@@ -0,0 +1,140 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.client.BucketClient;
+import org.apache.nifi.registry.client.NiFiRegistryException;
+import org.apache.nifi.registry.field.Fields;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jersey implementation of BucketClient.
+ */
+public class JerseyBucketClient extends AbstractJerseyClient implements BucketClient {
+
+ private final WebTarget bucketsTarget;
+
+
+ public JerseyBucketClient(final WebTarget baseTarget) {
+ this(baseTarget, Collections.emptyMap());
+ }
+
+ public JerseyBucketClient(final WebTarget baseTarget, final Map<String,String> headers) {
+ super(headers);
+ this.bucketsTarget = baseTarget.path("/buckets");
+ }
+
+ @Override
+ public Bucket create(final Bucket bucket) throws NiFiRegistryException, IOException {
+ if (bucket == null) {
+ throw new IllegalArgumentException("Bucket cannot be null");
+ }
+
+ return executeAction("Error creating bucket", () -> {
+ return getRequestBuilder(bucketsTarget)
+ .post(
+ Entity.entity(bucket, MediaType.APPLICATION_JSON),
+ Bucket.class
+ );
+ });
+
+ }
+
+ @Override
+ public Bucket get(final String bucketId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket ID cannot be blank");
+ }
+
+ return executeAction("Error retrieving bucket", () -> {
+ final WebTarget target = bucketsTarget
+ .path("/{bucketId}")
+ .resolveTemplate("bucketId", bucketId);
+
+ return getRequestBuilder(target).get(Bucket.class);
+ });
+
+ }
+
+ @Override
+ public Bucket update(final Bucket bucket) throws NiFiRegistryException, IOException {
+ if (bucket == null) {
+ throw new IllegalArgumentException("Bucket cannot be null");
+ }
+
+ if (StringUtils.isBlank(bucket.getIdentifier())) {
+ throw new IllegalArgumentException("Bucket Identifier must be provided");
+ }
+
+ return executeAction("Error updating bucket", () -> {
+ final WebTarget target = bucketsTarget
+ .path("/{bucketId}")
+ .resolveTemplate("bucketId", bucket.getIdentifier());
+
+ return getRequestBuilder(target)
+ .put(
+ Entity.entity(bucket, MediaType.APPLICATION_JSON),
+ Bucket.class
+ );
+
+ });
+ }
+
+ @Override
+ public Bucket delete(final String bucketId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket ID cannot be blank");
+ }
+
+ return executeAction("Error deleting bucket", () -> {
+ final WebTarget target = bucketsTarget
+ .path("/{bucketId}")
+ .resolveTemplate("bucketId", bucketId);
+
+ return getRequestBuilder(target).delete(Bucket.class);
+ });
+ }
+
+ @Override
+ public Fields getFields() throws NiFiRegistryException, IOException {
+ return executeAction("Error retrieving bucket field info", () -> {
+ final WebTarget target = bucketsTarget
+ .path("/fields");
+
+ return getRequestBuilder(target).get(Fields.class);
+ });
+ }
+
+ @Override
+ public List<Bucket> getAll() throws NiFiRegistryException, IOException {
+ return executeAction("Error retrieving all buckets", () -> {
+ final Bucket[] buckets = getRequestBuilder(bucketsTarget).get(Bucket[].class);
+ return buckets == null ? Collections.emptyList() : Arrays.asList(buckets);
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowClient.java
new file mode 100644
index 0000000..486a20a
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowClient.java
@@ -0,0 +1,205 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.client.FlowClient;
+import org.apache.nifi.registry.client.NiFiRegistryException;
+import org.apache.nifi.registry.diff.VersionedFlowDifference;
+import org.apache.nifi.registry.field.Fields;
+import org.apache.nifi.registry.flow.VersionedFlow;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jersey implementation of FlowClient.
+ */
+public class JerseyFlowClient extends AbstractJerseyClient implements FlowClient {
+
+ private final WebTarget flowsTarget;
+ private final WebTarget bucketFlowsTarget;
+
+ public JerseyFlowClient(final WebTarget baseTarget) {
+ this(baseTarget, Collections.emptyMap());
+ }
+
+ public JerseyFlowClient(final WebTarget baseTarget, final Map<String,String> headers) {
+ super(headers);
+ this.flowsTarget = baseTarget.path("/flows");
+ this.bucketFlowsTarget = baseTarget.path("/buckets/{bucketId}/flows");
+ }
+
+ @Override
+ public VersionedFlow create(final VersionedFlow flow) throws NiFiRegistryException, IOException {
+ if (flow == null) {
+ throw new IllegalArgumentException("VersionedFlow cannot be null");
+ }
+
+ final String bucketId = flow.getBucketIdentifier();
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ return executeAction("Error creating flow", () -> {
+ final WebTarget target = bucketFlowsTarget
+ .resolveTemplate("bucketId", bucketId);
+
+ return getRequestBuilder(target)
+ .post(
+ Entity.entity(flow, MediaType.APPLICATION_JSON),
+ VersionedFlow.class
+ );
+ });
+ }
+
+ @Override
+ public VersionedFlow get(final String bucketId, final String flowId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving flow", () -> {
+ final WebTarget target = bucketFlowsTarget
+ .path("/{flowId}")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlow.class);
+ });
+ }
+
+ @Override
+ public VersionedFlow get(final String flowId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ // this uses the flowsTarget because its calling /flows/{flowId} without knowing a bucketId
+ return executeAction("Error retrieving flow", () -> {
+ final WebTarget target = flowsTarget
+ .path("/{flowId}")
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlow.class);
+ });
+ }
+
+ @Override
+ public VersionedFlow update(final String bucketId, final VersionedFlow flow) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (flow == null) {
+ throw new IllegalArgumentException("VersionedFlow cannot be null");
+ }
+
+ if (StringUtils.isBlank(flow.getIdentifier())) {
+ throw new IllegalArgumentException("VersionedFlow identifier must be provided");
+ }
+
+ return executeAction("Error updating flow", () -> {
+ final WebTarget target = bucketFlowsTarget
+ .path("/{flowId}")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flow.getIdentifier());
+
+ return getRequestBuilder(target)
+ .put(
+ Entity.entity(flow, MediaType.APPLICATION_JSON),
+ VersionedFlow.class
+ );
+ });
+ }
+
+ @Override
+ public VersionedFlow delete(final String bucketId, final String flowId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error deleting flow", () -> {
+ final WebTarget target = bucketFlowsTarget
+ .path("/{flowId}")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).delete(VersionedFlow.class);
+ });
+ }
+
+ @Override
+ public Fields getFields() throws NiFiRegistryException, IOException {
+ return executeAction("Error retrieving fields info for flows", () -> {
+ final WebTarget target = flowsTarget.path("/fields");
+ return getRequestBuilder(target).get(Fields.class);
+ });
+ }
+
+ @Override
+ public List<VersionedFlow> getByBucket(final String bucketId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ return executeAction("Error getting flows for bucket", () -> {
+ WebTarget target = bucketFlowsTarget;
+ target = target.resolveTemplate("bucketId", bucketId);
+
+ final VersionedFlow[] versionedFlows = getRequestBuilder(target).get(VersionedFlow[].class);
+ return versionedFlows == null ? Collections.emptyList() : Arrays.asList(versionedFlows);
+ });
+ }
+
+ @Override
+ public VersionedFlowDifference diff(final String bucketId, final String flowId,
+ final Integer versionA, final Integer versionB) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving flow", () -> {
+ final WebTarget target = bucketFlowsTarget
+ .path("/{flowId}/diff/{versionA}/{versionB}")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId)
+ .resolveTemplate("versionA", versionA)
+ .resolveTemplate("versionB", versionB);
+
+ return getRequestBuilder(target).get(VersionedFlowDifference.class);
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
new file mode 100644
index 0000000..befe389
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
@@ -0,0 +1,246 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.client.FlowSnapshotClient;
+import org.apache.nifi.registry.client.NiFiRegistryException;
+import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
+import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jersey implementation of FlowSnapshotClient.
+ */
+public class JerseyFlowSnapshotClient extends AbstractJerseyClient implements FlowSnapshotClient {
+
+ final WebTarget bucketFlowSnapshotTarget;
+ final WebTarget flowsFlowSnapshotTarget;
+
+ public JerseyFlowSnapshotClient(final WebTarget baseTarget) {
+ this(baseTarget, Collections.emptyMap());
+ }
+
+ public JerseyFlowSnapshotClient(final WebTarget baseTarget, final Map<String,String> headers) {
+ super(headers);
+ this.bucketFlowSnapshotTarget = baseTarget.path("/buckets/{bucketId}/flows/{flowId}/versions");
+ this.flowsFlowSnapshotTarget = baseTarget.path("/flows/{flowId}/versions");
+ }
+
+ @Override
+ public VersionedFlowSnapshot create(final VersionedFlowSnapshot snapshot)
+ throws NiFiRegistryException, IOException {
+ if (snapshot.getSnapshotMetadata() == null) {
+ throw new IllegalArgumentException("Snapshot Metadata cannot be null");
+ }
+
+ final String bucketId = snapshot.getSnapshotMetadata().getBucketIdentifier();
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ final String flowId = snapshot.getSnapshotMetadata().getFlowIdentifier();
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error creating snapshot", () -> {
+ final WebTarget target = bucketFlowSnapshotTarget
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target)
+ .post(
+ Entity.entity(snapshot, MediaType.APPLICATION_JSON),
+ VersionedFlowSnapshot.class
+ );
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshot get(final String bucketId, final String flowId, final int version)
+ throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ if (version < 1) {
+ throw new IllegalArgumentException("Version must be greater than 1");
+ }
+
+ return executeAction("Error retrieving flow snapshot", () -> {
+ final WebTarget target = bucketFlowSnapshotTarget
+ .path("/{version}")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId)
+ .resolveTemplate("version", version);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshot.class);
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshot get(final String flowId, final int version)
+ throws NiFiRegistryException, IOException {
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ if (version < 1) {
+ throw new IllegalArgumentException("Version must be greater than 1");
+ }
+
+ return executeAction("Error retrieving flow snapshot", () -> {
+ final WebTarget target = flowsFlowSnapshotTarget
+ .path("/{version}")
+ .resolveTemplate("flowId", flowId)
+ .resolveTemplate("version", version);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshot.class);
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshot getLatest(final String bucketId, final String flowId)
+ throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving latest snapshot", () -> {
+ final WebTarget target = bucketFlowSnapshotTarget
+ .path("/latest")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshot.class);
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshot getLatest(final String flowId)
+ throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving latest snapshot", () -> {
+ final WebTarget target = flowsFlowSnapshotTarget
+ .path("/latest")
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshot.class);
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshotMetadata getLatestMetadata(final String bucketId, final String flowId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving latest snapshot metadata", () -> {
+ final WebTarget target = bucketFlowSnapshotTarget
+ .path("/latest/metadata")
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshotMetadata.class);
+ });
+ }
+
+ @Override
+ public VersionedFlowSnapshotMetadata getLatestMetadata(final String flowId) throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving latest snapshot metadata", () -> {
+ final WebTarget target = flowsFlowSnapshotTarget
+ .path("/latest/metadata")
+ .resolveTemplate("flowId", flowId);
+
+ return getRequestBuilder(target).get(VersionedFlowSnapshotMetadata.class);
+ });
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List<VersionedFlowSnapshotMetadata> getSnapshotMetadata(final String bucketId, final String flowId)
+ throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving snapshot metadata", () -> {
+ final WebTarget target = bucketFlowSnapshotTarget
+ .resolveTemplate("bucketId", bucketId)
+ .resolveTemplate("flowId", flowId);
+
+ final VersionedFlowSnapshotMetadata[] snapshots = getRequestBuilder(target)
+ .get(VersionedFlowSnapshotMetadata[].class);
+
+ return snapshots == null ? Collections.emptyList() : Arrays.asList(snapshots);
+ });
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List<VersionedFlowSnapshotMetadata> getSnapshotMetadata(final String flowId)
+ throws NiFiRegistryException, IOException {
+
+ if (StringUtils.isBlank(flowId)) {
+ throw new IllegalArgumentException("Flow Identifier cannot be blank");
+ }
+
+ return executeAction("Error retrieving snapshot metadata", () -> {
+ final WebTarget target = flowsFlowSnapshotTarget
+ .resolveTemplate("flowId", flowId);
+
+ final VersionedFlowSnapshotMetadata[] snapshots = getRequestBuilder(target)
+ .get(VersionedFlowSnapshotMetadata[].class);
+
+ return snapshots == null ? Collections.emptyList() : Arrays.asList(snapshots);
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyItemsClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyItemsClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyItemsClient.java
new file mode 100644
index 0000000..6b01fc4
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyItemsClient.java
@@ -0,0 +1,85 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.client.ItemsClient;
+import org.apache.nifi.registry.client.NiFiRegistryException;
+import org.apache.nifi.registry.field.Fields;
+
+import javax.ws.rs.client.WebTarget;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jersey implementation of ItemsClient.
+ */
+public class JerseyItemsClient extends AbstractJerseyClient implements ItemsClient {
+
+ private final WebTarget itemsTarget;
+
+ public JerseyItemsClient(final WebTarget baseTarget) {
+ this(baseTarget, Collections.emptyMap());
+ }
+
+ public JerseyItemsClient(final WebTarget baseTarget, final Map<String,String> headers) {
+ super(headers);
+ this.itemsTarget = baseTarget.path("/items");
+ }
+
+
+
+ @Override
+ public List<BucketItem> getAll() throws NiFiRegistryException, IOException {
+ return executeAction("", () -> {
+ WebTarget target = itemsTarget;
+ final BucketItem[] bucketItems = getRequestBuilder(target).get(BucketItem[].class);
+ return bucketItems == null ? Collections.emptyList() : Arrays.asList(bucketItems);
+ });
+ }
+
+ @Override
+ public List<BucketItem> getByBucket(final String bucketId)
+ throws NiFiRegistryException, IOException {
+ if (StringUtils.isBlank(bucketId)) {
+ throw new IllegalArgumentException("Bucket Identifier cannot be blank");
+ }
+
+ return executeAction("", () -> {
+ WebTarget target = itemsTarget
+ .path("/{bucketId}")
+ .resolveTemplate("bucketId", bucketId);
+
+ final BucketItem[] bucketItems = getRequestBuilder(target).get(BucketItem[].class);
+ return bucketItems == null ? Collections.emptyList() : Arrays.asList(bucketItems);
+ });
+ }
+
+ @Override
+ public Fields getFields() throws NiFiRegistryException, IOException {
+ return executeAction("", () -> {
+ final WebTarget target = itemsTarget.path("/fields");
+ return getRequestBuilder(target).get(Fields.class);
+
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyNiFiRegistryClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyNiFiRegistryClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyNiFiRegistryClient.java
new file mode 100644
index 0000000..329a47a
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyNiFiRegistryClient.java
@@ -0,0 +1,247 @@
+/*
+ * 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.registry.client.impl;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.client.BucketClient;
+import org.apache.nifi.registry.client.FlowClient;
+import org.apache.nifi.registry.client.FlowSnapshotClient;
+import org.apache.nifi.registry.client.ItemsClient;
+import org.apache.nifi.registry.client.NiFiRegistryClient;
+import org.apache.nifi.registry.client.NiFiRegistryClientConfig;
+import org.apache.nifi.registry.client.UserClient;
+import org.apache.nifi.registry.security.util.ProxiedEntitiesUtils;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * A NiFiRegistryClient that uses Jersey Client.
+ */
+public class JerseyNiFiRegistryClient implements NiFiRegistryClient {
+
+ static final String NIFI_REGISTRY_CONTEXT = "nifi-registry-api";
+ static final int DEFAULT_CONNECT_TIMEOUT = 10000;
+ static final int DEFAULT_READ_TIMEOUT = 10000;
+
+ private final Client client;
+ private final WebTarget baseTarget;
+
+ private final BucketClient bucketClient;
+ private final FlowClient flowClient;
+ private final FlowSnapshotClient flowSnapshotClient;
+ private final ItemsClient itemsClient;
+
+ private JerseyNiFiRegistryClient(final NiFiRegistryClient.Builder builder) {
+ final NiFiRegistryClientConfig registryClientConfig = builder.getConfig();
+ if (registryClientConfig == null) {
+ throw new IllegalArgumentException("NiFiRegistryClientConfig cannot be null");
+ }
+
+ String baseUrl = registryClientConfig.getBaseUrl();
+ if (StringUtils.isBlank(baseUrl)) {
+ throw new IllegalArgumentException("Base URL cannot be blank");
+ }
+
+ if (baseUrl.endsWith("/")) {
+ baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
+ }
+
+ if (!baseUrl.endsWith(NIFI_REGISTRY_CONTEXT)) {
+ baseUrl = baseUrl + "/" + NIFI_REGISTRY_CONTEXT;
+ }
+
+ try {
+ new URI(baseUrl);
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Invalid base URL: " + e.getMessage(), e);
+ }
+
+ final SSLContext sslContext = registryClientConfig.getSslContext();
+ final HostnameVerifier hostnameVerifier = registryClientConfig.getHostnameVerifier();
+
+ final ClientBuilder clientBuilder = ClientBuilder.newBuilder();
+ if (sslContext != null) {
+ clientBuilder.sslContext(sslContext);
+ }
+ if (hostnameVerifier != null) {
+ clientBuilder.hostnameVerifier(hostnameVerifier);
+ }
+
+ final int connectTimeout = registryClientConfig.getConnectTimeout() == null ? DEFAULT_CONNECT_TIMEOUT : registryClientConfig.getConnectTimeout();
+ final int readTimeout = registryClientConfig.getReadTimeout() == null ? DEFAULT_READ_TIMEOUT : registryClientConfig.getReadTimeout();
+
+ final ClientConfig clientConfig = new ClientConfig();
+ clientConfig.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout);
+ clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeout);
+ clientConfig.register(jacksonJaxbJsonProvider());
+ clientBuilder.withConfig(clientConfig);
+ this.client = clientBuilder.build();
+
+ this.baseTarget = client.target(baseUrl);
+ this.bucketClient = new JerseyBucketClient(baseTarget);
+ this.flowClient = new JerseyFlowClient(baseTarget);
+ this.flowSnapshotClient = new JerseyFlowSnapshotClient(baseTarget);
+ this.itemsClient = new JerseyItemsClient(baseTarget);
+ }
+
+ @Override
+ public BucketClient getBucketClient() {
+ return this.bucketClient;
+ }
+
+ @Override
+ public FlowClient getFlowClient() {
+ return this.flowClient;
+ }
+
+ @Override
+ public FlowSnapshotClient getFlowSnapshotClient() {
+ return this.flowSnapshotClient;
+ }
+
+ @Override
+ public ItemsClient getItemsClient() {
+ return this.itemsClient;
+ }
+
+ @Override
+ public BucketClient getBucketClient(String... proxiedEntity) {
+ final Map<String,String> headers = getHeaders(proxiedEntity);
+ return new JerseyBucketClient(baseTarget, headers);
+ }
+
+ @Override
+ public FlowClient getFlowClient(String... proxiedEntity) {
+ final Map<String,String> headers = getHeaders(proxiedEntity);
+ return new JerseyFlowClient(baseTarget, headers);
+ }
+
+ @Override
+ public FlowSnapshotClient getFlowSnapshotClient(String... proxiedEntity) {
+ final Map<String,String> headers = getHeaders(proxiedEntity);
+ return new JerseyFlowSnapshotClient(baseTarget, headers);
+ }
+
+ @Override
+ public ItemsClient getItemsClient(String... proxiedEntity) {
+ final Map<String,String> headers = getHeaders(proxiedEntity);
+ return new JerseyItemsClient(baseTarget, headers);
+ }
+
+ @Override
+ public UserClient getUserClient() {
+ return new JerseyUserClient(baseTarget);
+ }
+
+ @Override
+ public UserClient getUserClient(String... proxiedEntity) {
+ final Map<String,String> headers = getHeaders(proxiedEntity);
+ return new JerseyUserClient(baseTarget, headers);
+ }
+
+ private Map<String,String> getHeaders(String[] proxiedEntities) {
+ final String proxiedEntitiesValue = getProxiedEntitesValue(proxiedEntities);
+
+ final Map<String,String> headers = new HashMap<>();
+ if (proxiedEntitiesValue != null) {
+ headers.put(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, proxiedEntitiesValue);
+ }
+ return headers;
+ }
+
+ private String getProxiedEntitesValue(String[] proxiedEntities) {
+ if (proxiedEntities == null) {
+ return null;
+ }
+
+ final List<String> proxiedEntityChain = Arrays.stream(proxiedEntities).map(ProxiedEntitiesUtils::formatProxyDn).collect(Collectors.toList());
+ return StringUtils.join(proxiedEntityChain, "");
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (this.client != null) {
+ try {
+ this.client.close();
+ } catch (Exception e) {
+
+ }
+ }
+ }
+
+ /**
+ * Builder for creating a JerseyNiFiRegistryClient.
+ */
+ public static class Builder implements NiFiRegistryClient.Builder {
+
+ private NiFiRegistryClientConfig clientConfig;
+
+ @Override
+ public Builder config(final NiFiRegistryClientConfig clientConfig) {
+ this.clientConfig = clientConfig;
+ return this;
+ }
+
+ @Override
+ public NiFiRegistryClientConfig getConfig() {
+ return clientConfig;
+ }
+
+ @Override
+ public NiFiRegistryClient build() {
+ return new JerseyNiFiRegistryClient(this);
+ }
+
+ }
+
+ private static JacksonJaxbJsonProvider jacksonJaxbJsonProvider() {
+ JacksonJaxbJsonProvider jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider();
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL));
+ mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory()));
+ // Ignore unknown properties so that deployed client remain compatible with future versions of NiFi Registry that add new fields
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ SimpleModule module = new SimpleModule();
+ module.addDeserializer(BucketItem[].class, new BucketItemDeserializer());
+ mapper.registerModule(module);
+
+ jacksonJaxbJsonProvider.setMapper(mapper);
+ return jacksonJaxbJsonProvider;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
new file mode 100644
index 0000000..7625f35
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
@@ -0,0 +1,47 @@
+/*
+ * 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.registry.client.impl;
+
+import org.apache.nifi.registry.client.NiFiRegistryException;
+import org.apache.nifi.registry.client.UserClient;
+import org.apache.nifi.registry.authorization.CurrentUser;
+
+import javax.ws.rs.client.WebTarget;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+public class JerseyUserClient extends AbstractJerseyClient implements UserClient {
+
+ private final WebTarget accessTarget;
+
+ public JerseyUserClient(final WebTarget baseTarget) {
+ this(baseTarget, Collections.emptyMap());
+ }
+
+ public JerseyUserClient(final WebTarget baseTarget, final Map<String,String> headers) {
+ super(headers);
+ this.accessTarget = baseTarget.path("/access");
+ }
+
+ @Override
+ public CurrentUser getAccessStatus() throws NiFiRegistryException, IOException {
+ return executeAction("Error retrieving access status for the current user", () -> {
+ return getRequestBuilder(accessTarget).get(CurrentUser.class);
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-data-model/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-data-model/pom.xml b/nifi-registry-core/nifi-registry-data-model/pom.xml
new file mode 100644
index 0000000..3b63ddc
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-data-model/pom.xml
@@ -0,0 +1,41 @@
+<?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.registry</groupId>
+ <artifactId>nifi-registry-core</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>nifi-registry-data-model</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.swagger</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ </dependencies>
+</project>