nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bbe...@apache.org
Subject [3/3] nifi-registry git commit: NIFIREG-63 Added ability to get latest snapshot metadata - Created a way to retrieve latest snapshot directly from the DB - Increased sizes of DB columns to avoid hitting max sizes - Improving error messages returned from
Date Thu, 07 Dec 2017 19:38:38 GMT
NIFIREG-63 Added ability to get latest snapshot metadata
- Created a way to retrieve latest snapshot directly from the DB
- Increased sizes of DB columns to avoid hitting max sizes
- Improving error messages returned from NiFiRegistryClient to include the underlying response
from the server

This closes #48.

Signed-off-by: Bryan Bende <bbende@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/be2b013b
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/be2b013b
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/be2b013b

Branch: refs/heads/master
Commit: be2b013bf6d73928145d9dacf8474af174454ac8
Parents: b2ff7b5
Author: Bryan Bende <bbende@apache.org>
Authored: Tue Dec 5 10:13:26 2017 -0500
Committer: Bryan Bende <bbende@apache.org>
Committed: Thu Dec 7 14:38:05 2017 -0500

----------------------------------------------------------------------
 .../registry/client/FlowSnapshotClient.java     | 11 +++
 .../client/impl/AbstractJerseyClient.java       | 15 +++-
 .../client/impl/JerseyFlowSnapshotClient.java   | 20 +++++
 .../registry/db/DatabaseMetadataService.java    | 13 +++
 .../db/repository/FlowSnapshotRepository.java   |  3 +
 .../nifi/registry/service/MetadataService.java  | 10 ++-
 .../nifi/registry/service/RegistryService.java  | 85 +++++++++++++-------
 .../db/migration/V1.2__IncreaseColumnSizes.sql  | 25 ++++++
 .../db/TestDatabaseMetadataService.java         | 11 +++
 .../repository/TestFlowSnapshotRepository.java  | 10 +++
 .../registry/web/api/BucketFlowResource.java    | 42 ++++++++--
 .../web/api/UnsecuredNiFiRegistryClientIT.java  | 15 ++++
 12 files changed, 225 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
index 48d1877..1141753 100644
--- a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
+++ b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/FlowSnapshotClient.java
@@ -64,6 +64,17 @@ public interface FlowSnapshotClient {
     VersionedFlowSnapshot getLatest(String bucketId, 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 a list of the metadata for all snapshots of a given flow.
      *
      * The contents of each snapshot are not part of the response.

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
index b31cdfa..479699e 100644
--- a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
+++ b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/AbstractJerseyClient.java
@@ -18,8 +18,10 @@ 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;
@@ -69,14 +71,25 @@ public class AbstractJerseyClient {
             return action.execute();
         } catch (final Exception e) {
             final Throwable ioeCause = getIOExceptionCause(e);
+
             if (ioeCause == null) {
-                throw new NiFiRegistryException(errorMessage, e);
+                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.
      *

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
----------------------------------------------------------------------
diff --git a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
index bf9ad2d..deddd5e 100644
--- a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
+++ b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyFlowSnapshotClient.java
@@ -126,6 +126,26 @@ public class JerseyFlowSnapshotClient extends AbstractJerseyClient implements
Fl
     }
 
     @Override
+    public VersionedFlowSnapshotMetadata getLatestMetadata(String bucketId, 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 = flowSnapshotTarget
+                    .path("/latest/metadata")
+                    .resolveTemplate("bucketId", bucketId)
+                    .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 {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
index 3f0373a..6f8415f 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
@@ -375,6 +375,19 @@ public class DatabaseMetadataService implements MetadataService {
     }
 
     @Override
+    public FlowSnapshotEntity getLatestSnapshot(final FlowEntity flowEntity) {
+        if (flowEntity == null) {
+            return null;
+        }
+
+        final FlowSnapshotEntity flowSnapshot = flowSnapshotRepository.findFirstByFlowOrderByIdVersionDesc(flowEntity);
+        if (flowSnapshot == null) {
+            return null;
+        }
+        return flowSnapshot;
+    }
+
+    @Override
     public void deleteFlowSnapshot(final FlowSnapshotEntity flowSnapshot) {
         flowSnapshotRepository.delete(flowSnapshot);
     }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowSnapshotRepository.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowSnapshotRepository.java
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowSnapshotRepository.java
index 817048f..255a511 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowSnapshotRepository.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowSnapshotRepository.java
@@ -16,6 +16,7 @@
  */
 package org.apache.nifi.registry.db.repository;
 
+import org.apache.nifi.registry.db.entity.FlowEntity;
 import org.apache.nifi.registry.db.entity.FlowSnapshotCount;
 import org.apache.nifi.registry.db.entity.FlowSnapshotEntity;
 import org.apache.nifi.registry.db.entity.FlowSnapshotEntityKey;
@@ -32,4 +33,6 @@ public interface FlowSnapshotRepository extends PagingAndSortingRepository<FlowS
     @Query("select new org.apache.nifi.registry.db.entity.FlowSnapshotCount(fs.id.flowId,
count(*)) from FlowSnapshotEntity as fs group by fs.id.flowId")
     List<FlowSnapshotCount> countByFlow();
 
+    FlowSnapshotEntity findFirstByFlowOrderByIdVersionDesc(FlowEntity flowEntity);
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
index 1c6e918..0613aa5 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
@@ -179,7 +179,7 @@ public interface MetadataService {
     /**
      * Retrieves the snapshot for the given flow identifier and snapshot version.
      *
-     * @param bucketIdentifier the identifier of the bucket storign the flow
+     * @param bucketIdentifier the identifier of the bucket storing the flow
      * @param flowIdentifier the identifier of the flow the snapshot belongs to
      * @param version the version of the snapshot
      * @return the versioned flow snapshot for the given flow identifier and version, or
null if none exists
@@ -187,6 +187,14 @@ public interface MetadataService {
     FlowSnapshotEntity getFlowSnapshot(String bucketIdentifier, String flowIdentifier, Integer
version);
 
     /**
+     * Retrieves the snapshot with the latest version number for the given flow in the given
bucket.
+     *
+     * @param flowEntity the flow to retrieve the latest snapshot for
+     * @return the latest snapshot for the flow, or null if one doesn't exist
+     */
+    FlowSnapshotEntity getLatestSnapshot(FlowEntity flowEntity);
+
+    /**
      * Deletes the flow snapshot.
      *
      * @param flowSnapshot the flow snapshot to delete

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
index 348518f..7021f38 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
@@ -130,14 +130,14 @@ public class RegistryService {
 
     public Bucket getBucket(final String bucketIdentifier) {
         if (bucketIdentifier == null) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null");
+            throw new IllegalArgumentException("Bucket identifier cannot be null");
         }
 
         readLock.lock();
         try {
             final BucketEntity bucket = metadataService.getBucketById(bucketIdentifier);
             if (bucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketIdentifier);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
             }
 
             return DataModelMapper.map(bucket);
@@ -172,7 +172,7 @@ public class RegistryService {
         }
 
         if (bucket.getIdentifier() == null) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null");
+            throw new IllegalArgumentException("Bucket identifier cannot be null");
         }
 
         writeLock.lock();
@@ -180,7 +180,7 @@ public class RegistryService {
             // ensure a bucket with the given id exists
             final BucketEntity existingBucketById = metadataService.getBucketById(bucket.getIdentifier());
             if (existingBucketById == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucket.getIdentifier());
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucket.getIdentifier());
             }
 
             // ensure a different bucket with the same name does not exist
@@ -190,7 +190,7 @@ public class RegistryService {
                 if (bucketsWithSameName != null) {
                     for (final BucketEntity bucketWithSameName : bucketsWithSameName) {
                         if (!bucketWithSameName.getId().equals(existingBucketById.getId())){
-                            throw new IllegalStateException("A bucket with the same name
already exists: " + bucket.getName());
+                            throw new IllegalStateException("A bucket with the same name
already exists - " + bucket.getName());
                         }
                     }
                 }
@@ -215,7 +215,7 @@ public class RegistryService {
 
     public Bucket deleteBucket(final String bucketIdentifier) {
         if (bucketIdentifier == null) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null");
+            throw new IllegalArgumentException("Bucket identifier cannot be null");
         }
 
         writeLock.lock();
@@ -223,7 +223,7 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketIdentifier);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
             }
 
             // for each flow in the bucket, delete all snapshots from the flow persistence
provider
@@ -244,14 +244,14 @@ public class RegistryService {
 
     public List<BucketItem> getBucketItems(final QueryParameters queryParameters, final
String bucketIdentifier) {
         if (bucketIdentifier == null) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null");
+            throw new IllegalArgumentException("Bucket identifier cannot be null");
         }
 
         readLock.lock();
         try {
             final BucketEntity bucket = metadataService.getBucketById(bucketIdentifier);
             if (bucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketIdentifier);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
             }
 
             final List<BucketItem> bucketItems = new ArrayList<>();
@@ -264,7 +264,7 @@ public class RegistryService {
 
     public List<BucketItem> getBucketItems(final QueryParameters queryParameters, final
Set<String> bucketIdentifiers) {
         if (bucketIdentifiers == null || bucketIdentifiers.isEmpty()) {
-            throw new IllegalArgumentException("Bucket Identifiers cannot be null or empty");
+            throw new IllegalArgumentException("Bucket identifiers cannot be null or empty");
         }
 
         readLock.lock();
@@ -290,7 +290,7 @@ public class RegistryService {
 
     public VersionedFlow createFlow(final String bucketIdentifier, final VersionedFlow versionedFlow)
{
         if (StringUtils.isBlank(bucketIdentifier)) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null or blank");
+            throw new IllegalArgumentException("Bucket identifier cannot be null or blank");
         }
 
         if (versionedFlow == null) {
@@ -318,7 +318,7 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketIdentifier);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
             }
 
             // ensure another flow with the same name doesn't exist
@@ -341,18 +341,18 @@ public class RegistryService {
 
     public VersionedFlow getFlow(final String bucketIdentifier, final String flowIdentifier)
{
         if (StringUtils.isBlank(bucketIdentifier)) {
-            throw new IllegalArgumentException("Bucket Identifier Identifier cannot be null
or blank");
+            throw new IllegalArgumentException("Bucket identifier cannot be null or blank");
         }
 
         if (StringUtils.isBlank(flowIdentifier)) {
-            throw new IllegalArgumentException("Flow Identifier cannot be null or blank");
+            throw new IllegalArgumentException("Flow identifier cannot be null or blank");
         }
 
         readLock.lock();
         try {
             final FlowEntity flowEntity = metadataService.getFlowByIdWithSnapshotCounts(bucketIdentifier,
flowIdentifier);
             if (flowEntity == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier:
" + flowIdentifier);
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + flowIdentifier);
             }
 
             return DataModelMapper.map(flowEntity);
@@ -363,14 +363,14 @@ public class RegistryService {
 
     public List<VersionedFlow> getFlows(final String bucketId) {
         if (StringUtils.isBlank(bucketId)) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null");
+            throw new IllegalArgumentException("Bucket identifier cannot be null");
         }
 
         readLock.lock();
         try {
             final BucketEntity existingBucket = metadataService.getBucketById(bucketId);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketId);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketId);
             }
 
             // return non-verbose set of flows for the given bucket
@@ -399,7 +399,7 @@ public class RegistryService {
             // ensure a flow with the given id exists
             final FlowEntity existingFlow = metadataService.getFlowById(versionedFlow.getBucketIdentifier(),
versionedFlow.getIdentifier());
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier:
" + versionedFlow.getIdentifier());
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + versionedFlow.getIdentifier());
             }
 
             // ensure a different flow with the same name does not exist
@@ -409,7 +409,7 @@ public class RegistryService {
                 if (flowsWithSameName != null) {
                     for (final FlowEntity flowWithSameName : flowsWithSameName) {
                          if(!flowWithSameName.getId().equals(existingFlow.getId())) {
-                            throw new IllegalStateException("A VersionedFlow with the same
name already exists: " + versionedFlow.getName());
+                            throw new IllegalStateException("A VersionedFlow with the same
name already exists - " + versionedFlow.getName());
                         }
                     }
                 }
@@ -434,10 +434,10 @@ public class RegistryService {
 
     public VersionedFlow deleteFlow(final String bucketIdentifier, final String flowIdentifier)
{
         if (StringUtils.isBlank(bucketIdentifier)) {
-            throw new IllegalArgumentException("Bucket Identifier cannot be null or blank");
+            throw new IllegalArgumentException("Bucket identifier cannot be null or blank");
         }
         if (StringUtils.isBlank(flowIdentifier)) {
-            throw new IllegalArgumentException("Flow Identifier cannot be null or blank");
+            throw new IllegalArgumentException("Flow identifier cannot be null or blank");
         }
 
         writeLock.lock();
@@ -445,7 +445,7 @@ public class RegistryService {
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(bucketIdentifier,
flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier:
" + flowIdentifier);
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + flowIdentifier);
             }
 
             // delete all snapshots from the flow persistence provider
@@ -485,13 +485,13 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(snapshotMetadata.getBucketIdentifier());
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + snapshotMetadata.getBucketIdentifier());
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + snapshotMetadata.getBucketIdentifier());
             }
 
             // ensure the flow exists, we need to use "with counts" here so we can return
this is a part of the response
             final FlowEntity existingFlow = metadataService.getFlowByIdWithSnapshotCounts(snapshotMetadata.getBucketIdentifier(),
snapshotMetadata.getFlowIdentifier());
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier:
" + snapshotMetadata.getFlowIdentifier());
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + snapshotMetadata.getFlowIdentifier());
             }
 
             // convert the set of FlowSnapshotEntity to set of VersionedFlowSnapshotMetadata
@@ -560,7 +560,7 @@ public class RegistryService {
             // we need to populate the version count here so we have to do this retrieval
instead of snapshotEntity.getFlow()
             final FlowEntity flowEntityWithCount = metadataService.getFlowByIdWithSnapshotCounts(bucketIdentifier,
flowIdentifier);
             if (flowEntityWithCount == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for flow
" + flowIdentifier);
+                throw new ResourceNotFoundException("VersionedFlow does not exist with identifier
" + flowIdentifier);
             }
 
             // ensure the snapshot exists
@@ -619,13 +619,13 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier:
" + bucketIdentifier);
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
             }
 
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(bucketIdentifier,
flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier:
" + flowIdentifier);
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + flowIdentifier);
             }
 
             // convert the set of FlowSnapshotEntity to set of VersionedFlowSnapshotMetadata,
ordered by version descending
@@ -641,6 +641,37 @@ public class RegistryService {
         }
     }
 
+    public VersionedFlowSnapshotMetadata getLatestFlowSnapshotMetadata(final String bucketIdentifier,
final String flowIdentifier) {
+        if (StringUtils.isBlank(bucketIdentifier)) {
+            throw new IllegalArgumentException("Bucket identifier cannot be null or blank");
+        }
+
+        if (StringUtils.isBlank(flowIdentifier)) {
+            throw new IllegalArgumentException("Flow identifier cannot be null or blank");
+        }
+
+        readLock.lock();
+        try {
+            // ensure the bucket exists
+            final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
+            if (existingBucket == null) {
+                throw new ResourceNotFoundException("Bucket does not exist for identifier
" + bucketIdentifier);
+            }
+
+            // ensure the flow exists
+            final FlowEntity existingFlow = metadataService.getFlowById(bucketIdentifier,
flowIdentifier);
+            if (existingFlow == null) {
+                throw new ResourceNotFoundException("VersionedFlow does not exist for identifier
" + flowIdentifier);
+            }
+
+            // get latest snapshot for the flow
+            final FlowSnapshotEntity latestSnapshot = metadataService.getLatestSnapshot(existingFlow);
+            return DataModelMapper.map(latestSnapshot);
+        } finally {
+            readLock.unlock();
+        }
+    }
+
     public VersionedFlowSnapshotMetadata deleteFlowSnapshot(final String bucketIdentifier,
final String flowIdentifier, final Integer version) {
         if (StringUtils.isBlank(bucketIdentifier)) {
             throw new IllegalArgumentException("Bucket identifier cannot be null or blank");

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/main/resources/db/migration/V1.2__IncreaseColumnSizes.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/resources/db/migration/V1.2__IncreaseColumnSizes.sql
b/nifi-registry-framework/src/main/resources/db/migration/V1.2__IncreaseColumnSizes.sql
new file mode 100644
index 0000000..b2e92d5
--- /dev/null
+++ b/nifi-registry-framework/src/main/resources/db/migration/V1.2__IncreaseColumnSizes.sql
@@ -0,0 +1,25 @@
+-- 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.
+
+ALTER TABLE BUCKET ALTER COLUMN NAME VARCHAR2(1000);
+ALTER TABLE BUCKET ALTER COLUMN DESCRIPTION VARCHAR2(65535);
+
+ALTER TABLE BUCKET_ITEM ALTER COLUMN NAME VARCHAR2(1000);
+ALTER TABLE BUCKET_ITEM ALTER COLUMN DESCRIPTION VARCHAR2(65535);
+
+ALTER TABLE FLOW_SNAPSHOT ALTER COLUMN CREATED_BY VARCHAR2(4096);
+ALTER TABLE FLOW_SNAPSHOT ALTER COLUMN COMMENTS VARCHAR2(65535);
+
+ALTER TABLE SIGNING_KEY ALTER COLUMN TENANT_IDENTITY VARCHAR2(4096);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/TestDatabaseMetadataService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/TestDatabaseMetadataService.java
b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/TestDatabaseMetadataService.java
index 4fab280..b07e4ed 100644
--- a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/TestDatabaseMetadataService.java
+++ b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/TestDatabaseMetadataService.java
@@ -20,6 +20,7 @@ import org.apache.nifi.registry.db.entity.BucketEntity;
 import org.apache.nifi.registry.db.entity.BucketItemEntity;
 import org.apache.nifi.registry.db.entity.BucketItemEntityType;
 import org.apache.nifi.registry.db.entity.FlowEntity;
+import org.apache.nifi.registry.db.entity.FlowSnapshotEntity;
 import org.apache.nifi.registry.service.QueryParameters;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -101,4 +102,14 @@ public class TestDatabaseMetadataService extends DatabaseBaseTest {
         assertEquals(3, flowEntity.getSnapshotCount());
     }
 
+    @Test
+    public void testGetLatestSnapshot() {
+        final FlowEntity flowEntity = metadataService.getFlowById("1", "1");
+        assertNotNull(flowEntity);
+
+        final FlowSnapshotEntity flowSnapshotEntity = metadataService.getLatestSnapshot(flowEntity);
+        assertNotNull(flowSnapshotEntity);
+        assertEquals(3, flowSnapshotEntity.getId().getVersion().intValue());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/repository/TestFlowSnapshotRepository.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/repository/TestFlowSnapshotRepository.java
b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/repository/TestFlowSnapshotRepository.java
index 2dc74b9..c6bd827 100644
--- a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/repository/TestFlowSnapshotRepository.java
+++ b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/db/repository/TestFlowSnapshotRepository.java
@@ -121,4 +121,14 @@ public class TestFlowSnapshotRepository extends DatabaseBaseTest {
         assertEquals(3, count.getSnapshotCount());
     }
 
+    @Test
+    public void testFindFirstByFlow() {
+        final FlowEntity flowEntity = flowRepository.findById("1").orElse(null);
+        assertNotNull(flowEntity);
+
+        final FlowSnapshotEntity latest = flowSnapshotRepository.findFirstByFlowOrderByIdVersionDesc(flowEntity);
+        assertNotNull(latest);
+        assertEquals(3, latest.getId().getVersion().intValue());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
index c8a8844..2b10919 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
@@ -325,20 +325,50 @@ public class BucketFlowResource extends AuthorizableApplicationResource
{
 
         authorizeBucketAccess(RequestAction.READ, bucketId);
 
-        final SortedSet<VersionedFlowSnapshotMetadata> snapshots = registryService.getFlowSnapshots(bucketId,
flowId);
-        if (snapshots == null || snapshots.size() == 0) {
-            throw new ResourceNotFoundException("Not flow versions found for flow with id
" + flowId);
+        final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(bucketId,
flowId);
+        if (latest == null) {
+            throw new ResourceNotFoundException("No flow versions found for flow with id
" + flowId);
         }
 
-        final VersionedFlowSnapshotMetadata lastSnapshotMetadata = snapshots.first();
-
-        final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot(bucketId,
flowId, lastSnapshotMetadata.getVersion());
+        final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot(bucketId,
flowId, latest.getVersion());
         populateLinks(lastSnapshot);
 
         return Response.status(Response.Status.OK).entity(lastSnapshot).build();
     }
 
     @GET
+    @Path("{flowId}/versions/latest/metadata")
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @ApiOperation(
+            value = "Get the metadata for the latest version of a flow",
+            response = VersionedFlowSnapshotMetadata.class
+    )
+    @ApiResponses({
+            @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401),
+            @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403),
+            @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404),
+            @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) })
+    public Response getLatestFlowVersionMetadata(
+            @PathParam("bucketId")
+            @ApiParam("The bucket identifier")
+            final String bucketId,
+            @PathParam("flowId")
+            @ApiParam("The flow identifier")
+            final String flowId) {
+
+        authorizeBucketAccess(RequestAction.READ, bucketId);
+
+        final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(bucketId,
flowId);
+        if (latest == null) {
+            throw new ResourceNotFoundException("No flow versions found for flow with id
" + flowId);
+        }
+
+        linkService.populateSnapshotLinks(latest);
+        return Response.status(Response.Status.OK).entity(latest).build();
+    }
+
+    @GET
     @Path("{flowId}/versions/{versionNumber: \\d+}")
     @Consumes(MediaType.WILDCARD)
     @Produces(MediaType.APPLICATION_JSON)

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/be2b013b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
index bcc2c0a..8a2a920 100644
--- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
@@ -237,8 +237,23 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase {
         final List<VersionedFlowSnapshotMetadata> retrievedMetadata = snapshotClient.getSnapshotMetadata(snapshotFlow.getBucketIdentifier(),
snapshotFlow.getIdentifier());
         Assert.assertNotNull(retrievedMetadata);
         Assert.assertEquals(2, retrievedMetadata.size());
+        Assert.assertEquals(2, retrievedMetadata.get(0).getVersion());
+        Assert.assertEquals(1, retrievedMetadata.get(1).getVersion());
         retrievedMetadata.stream().forEach(s -> LOGGER.info("Retrieved snapshot metadata
" + s.getVersion()));
 
+        // get latest metadata
+        final VersionedFlowSnapshotMetadata latestMetadata = snapshotClient.getLatestMetadata(snapshotFlow.getBucketIdentifier(),
snapshotFlow.getIdentifier());
+        Assert.assertNotNull(latestMetadata);
+        Assert.assertEquals(2, latestMetadata.getVersion());
+
+        // get latest metadata that doesn't exist
+        try {
+            snapshotClient.getLatestMetadata(snapshotFlow.getBucketIdentifier(), "DOES-NOT-EXIST");
+            Assert.fail("Should have thrown exception");
+        } catch (NiFiRegistryException nfe) {
+            Assert.assertEquals("Error retrieving latest snapshot metadata: VersionedFlow
does not exist for identifier DOES-NOT-EXIST", nfe.getMessage());
+        }
+
         // ---------------------- TEST ITEMS --------------------------//
 
         final ItemsClient itemsClient = client.getItemsClient();


Mime
View raw message