You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by bb...@apache.org on 2017/09/21 13:50:38 UTC

[4/7] nifi-registry git commit: NIFIREG-18 Initial plumbling for H2 database - Setup Flyway with initial migration to define tables - Setup entity classes with repositories - Setup unit testing for repositories - Removed existing MetadataProvider concept

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
index 8762706..d4b42cf 100644
--- a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
+++ b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
@@ -17,21 +17,20 @@
 package org.apache.nifi.registry.service;
 
 import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.db.entity.BucketEntity;
+import org.apache.nifi.registry.db.entity.BucketItemEntity;
+import org.apache.nifi.registry.db.entity.FlowEntity;
+import org.apache.nifi.registry.db.entity.FlowSnapshotEntity;
+import org.apache.nifi.registry.db.entity.FlowSnapshotEntityKey;
 import org.apache.nifi.registry.exception.ResourceNotFoundException;
 import org.apache.nifi.registry.flow.FlowPersistenceProvider;
 import org.apache.nifi.registry.flow.VersionedFlow;
 import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
 import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
 import org.apache.nifi.registry.flow.VersionedProcessGroup;
-import org.apache.nifi.registry.metadata.BucketMetadata;
-import org.apache.nifi.registry.metadata.FlowMetadata;
-import org.apache.nifi.registry.metadata.FlowSnapshotMetadata;
-import org.apache.nifi.registry.metadata.MetadataProvider;
-import org.apache.nifi.registry.metadata.StandardBucketMetadata;
-import org.apache.nifi.registry.metadata.StandardFlowMetadata;
-import org.apache.nifi.registry.metadata.StandardFlowSnapshotMetadata;
 import org.apache.nifi.registry.serialization.FlowSnapshotSerializer;
 import org.apache.nifi.registry.serialization.Serializer;
+import org.apache.nifi.registry.service.params.QueryParameters;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
@@ -43,8 +42,12 @@ import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
@@ -60,7 +63,7 @@ import static org.mockito.Mockito.when;
 
 public class TestRegistryService {
 
-    private MetadataProvider metadataProvider;
+    private MetadataService metadataService;
     private FlowPersistenceProvider flowPersistenceProvider;
     private Serializer<VersionedFlowSnapshot> snapshotSerializer;
     private Validator validator;
@@ -69,14 +72,14 @@ public class TestRegistryService {
 
     @Before
     public void setup() {
-        metadataProvider = mock(MetadataProvider.class);
+        metadataService = mock(MetadataService.class);
         flowPersistenceProvider = mock(FlowPersistenceProvider.class);
         snapshotSerializer = mock(FlowSnapshotSerializer.class);
 
         final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
         validator = validatorFactory.getValidator();
 
-        registryService = new RegistryService(metadataProvider, flowPersistenceProvider, snapshotSerializer, validator);
+        registryService = new RegistryService(metadataService, flowPersistenceProvider, snapshotSerializer, validator);
     }
 
     // ---------------------- Test Bucket methods ---------------------------------------------
@@ -87,9 +90,9 @@ public class TestRegistryService {
         bucket.setName("My Bucket");
         bucket.setDescription("This is my bucket.");
 
-        when(metadataProvider.getBucketByName(bucket.getName())).thenReturn(null);
+        when(metadataService.getBucketsByName(bucket.getName())).thenReturn(Collections.emptyList());
 
-        doAnswer(createBucketAnswer()).when(metadataProvider).createBucket(any(BucketMetadata.class));
+        doAnswer(createBucketAnswer()).when(metadataService).createBucket(any(BucketEntity.class));
 
         final Bucket createdBucket = registryService.createBucket(bucket);
         assertNotNull(createdBucket);
@@ -106,13 +109,12 @@ public class TestRegistryService {
         bucket.setName("My Bucket");
         bucket.setDescription("This is my bucket.");
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketByName(bucket.getName())).thenReturn(existingBucket);
+        when(metadataService.getBucketsByName(bucket.getName())).thenReturn(Collections.singletonList(existingBucket));
 
         // should throw exception since a bucket with the same name exists
         registryService.createBucket(bucket);
@@ -121,33 +123,32 @@ public class TestRegistryService {
     @Test(expected = ConstraintViolationException.class)
     public void testCreateBucketWithMissingName() {
         final Bucket bucket = new Bucket();
-        when(metadataProvider.getBucketByName(bucket.getName())).thenReturn(null);
+        when(metadataService.getBucketsByName(bucket.getName())).thenReturn(Collections.emptyList());
         registryService.createBucket(bucket);
     }
 
     @Test
     public void testGetExistingBucket() {
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
-        final Bucket bucket = registryService.getBucket(existingBucket.getIdentifier());
+        final Bucket bucket = registryService.getBucket(existingBucket.getId(), true);
         assertNotNull(bucket);
-        assertEquals(existingBucket.getIdentifier(), bucket.getIdentifier());
+        assertEquals(existingBucket.getId(), bucket.getIdentifier());
         assertEquals(existingBucket.getName(), bucket.getName());
         assertEquals(existingBucket.getDescription(), bucket.getDescription());
-        assertEquals(existingBucket.getCreatedTimestamp(), bucket.getCreatedTimestamp());
+        assertEquals(existingBucket.getCreated().getTime(), bucket.getCreatedTimestamp());
     }
 
     @Test(expected = ResourceNotFoundException.class)
     public void testGetBucketDoesNotExist() {
-        when(metadataProvider.getBucketById(any(String.class))).thenReturn(null);
-        registryService.getBucket("does-not-exist");
+        when(metadataService.getBucketById(any(String.class))).thenReturn(null);
+        registryService.getBucket("does-not-exist", true);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -166,33 +167,31 @@ public class TestRegistryService {
         bucket.setDescription("This is my bucket.");
         registryService.updateBucket(bucket);
 
-        when(metadataProvider.getBucketById(any(String.class))).thenReturn(null);
+        when(metadataService.getBucketById(any(String.class))).thenReturn(null);
         registryService.updateBucket(bucket);
     }
 
     @Test(expected = IllegalStateException.class)
     public void testUpdateBucketWithSameNameAsExistingBucket() {
-        final BucketMetadata bucketToUpdate = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity bucketToUpdate = new BucketEntity();
+        bucketToUpdate.setId("b1");
+        bucketToUpdate.setName("My Bucket");
+        bucketToUpdate.setDescription("This is my bucket");
+        bucketToUpdate.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(bucketToUpdate.getIdentifier())).thenReturn(bucketToUpdate);
+        when(metadataService.getBucketById(bucketToUpdate.getId())).thenReturn(bucketToUpdate);
 
-        final BucketMetadata otherBucket = new StandardBucketMetadata.Builder()
-                .identifier("b2")
-                .name("My Bucket #2")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity otherBucket = new BucketEntity();
+        otherBucket.setId("b2");
+        otherBucket.setName("My Bucket #2");
+        otherBucket.setDescription("This is my bucket");
+        otherBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketByName(otherBucket.getName())).thenReturn(otherBucket);
+        when(metadataService.getBucketsByName(otherBucket.getName())).thenReturn(Collections.singletonList(otherBucket));
 
         // should fail because other bucket has the same name
         final Bucket updatedBucket = new Bucket();
-        updatedBucket.setIdentifier(bucketToUpdate.getIdentifier());
+        updatedBucket.setIdentifier(bucketToUpdate.getId());
         updatedBucket.setName("My Bucket #2");
         updatedBucket.setDescription(bucketToUpdate.getDescription());
 
@@ -201,19 +200,18 @@ public class TestRegistryService {
 
     @Test
     public void testUpdateBucket() {
-        final BucketMetadata bucketToUpdate = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity bucketToUpdate = new BucketEntity();
+        bucketToUpdate.setId("b1");
+        bucketToUpdate.setName("My Bucket");
+        bucketToUpdate.setDescription("This is my bucket");
+        bucketToUpdate.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(bucketToUpdate.getIdentifier())).thenReturn(bucketToUpdate);
+        when(metadataService.getBucketById(bucketToUpdate.getId())).thenReturn(bucketToUpdate);
 
-        doAnswer(updateBucketAnswer()).when(metadataProvider).updateBucket(any(BucketMetadata.class));
+        doAnswer(updateBucketAnswer()).when(metadataService).updateBucket(any(BucketEntity.class));
 
         final Bucket updatedBucket = new Bucket();
-        updatedBucket.setIdentifier(bucketToUpdate.getIdentifier());
+        updatedBucket.setIdentifier(bucketToUpdate.getId());
         updatedBucket.setName("Updated Name");
         updatedBucket.setDescription("Updated Description");
 
@@ -225,19 +223,18 @@ public class TestRegistryService {
 
     @Test
     public void testUpdateBucketPartial() {
-        final BucketMetadata bucketToUpdate = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity bucketToUpdate = new BucketEntity();
+        bucketToUpdate.setId("b1");
+        bucketToUpdate.setName("My Bucket");
+        bucketToUpdate.setDescription("This is my bucket");
+        bucketToUpdate.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(bucketToUpdate.getIdentifier())).thenReturn(bucketToUpdate);
+        when(metadataService.getBucketById(bucketToUpdate.getId())).thenReturn(bucketToUpdate);
 
-        doAnswer(updateBucketAnswer()).when(metadataProvider).updateBucket(any(BucketMetadata.class));
+        doAnswer(updateBucketAnswer()).when(metadataService).updateBucket(any(BucketEntity.class));
 
         final Bucket updatedBucket = new Bucket();
-        updatedBucket.setIdentifier(bucketToUpdate.getIdentifier());
+        updatedBucket.setIdentifier(bucketToUpdate.getId());
         updatedBucket.setName("Updated Name");
         updatedBucket.setDescription(null);
 
@@ -251,39 +248,36 @@ public class TestRegistryService {
     @Test(expected = ResourceNotFoundException.class)
     public void testDeleteBucketDoesNotExist() {
         final String bucketId = "b1";
-        when(metadataProvider.getBucketById(bucketId)).thenReturn(null);
+        when(metadataService.getBucketById(bucketId)).thenReturn(null);
         registryService.deleteBucket(bucketId);
     }
 
     @Test
     public void testDeleteBucketWithFlows() {
-        final BucketMetadata bucketToDelete = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity bucketToDelete = new BucketEntity();
+        bucketToDelete.setId("b1");
+        bucketToDelete.setName("My Bucket");
+        bucketToDelete.setDescription("This is my bucket");
+        bucketToDelete.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(bucketToDelete.getIdentifier())).thenReturn(bucketToDelete);
+        final FlowEntity flowToDelete = new FlowEntity();
+        flowToDelete.setId("flow1");
+        flowToDelete.setName("Flow 1");
+        flowToDelete.setDescription("This is flow 1");
+        flowToDelete.setCreated(new Date());
 
-        final FlowMetadata flowToDelete = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("Flow 1")
-                .description("This is flow 1")
-                .created(System.currentTimeMillis())
-                .build();
+        final Set<BucketItemEntity> items = new HashSet<>();
+        items.add(flowToDelete);
+        bucketToDelete.setItems(items);
 
-        final Set<FlowMetadata> flowsToDelete = new HashSet<>();
-        flowsToDelete.add(flowToDelete);
+        when(metadataService.getBucketById(bucketToDelete.getId())).thenReturn(bucketToDelete);
 
-        when(metadataProvider.getFlows(bucketToDelete.getIdentifier())).thenReturn(flowsToDelete);
-
-        final Bucket deletedBucket = registryService.deleteBucket(bucketToDelete.getIdentifier());
+        final Bucket deletedBucket = registryService.deleteBucket(bucketToDelete.getId());
         assertNotNull(deletedBucket);
-        assertEquals(bucketToDelete.getIdentifier(), deletedBucket.getIdentifier());
+        assertEquals(bucketToDelete.getId(), deletedBucket.getIdentifier());
 
         verify(flowPersistenceProvider, times(1))
-                .deleteSnapshots(eq(bucketToDelete.getIdentifier()), eq(flowToDelete.getIdentifier()));
+                .deleteSnapshots(eq(bucketToDelete.getId()), eq(flowToDelete.getId()));
     }
 
     // ---------------------- Test VersionedFlow methods ---------------------------------------------
@@ -297,7 +291,7 @@ public class TestRegistryService {
     @Test(expected = ResourceNotFoundException.class)
     public void testCreateFlowBucketDoesNotExist() {
 
-        when(metadataProvider.getBucketById(any(String.class))).thenReturn(null);
+        when(metadataService.getBucketById(any(String.class))).thenReturn(null);
 
         final VersionedFlow versionedFlow = new VersionedFlow();
         versionedFlow.setName("My Flow");
@@ -308,30 +302,27 @@ public class TestRegistryService {
 
     @Test(expected = IllegalStateException.class)
     public void testCreateFlowWithSameName() {
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
         // setup a flow with the same name that already exists
 
-        final FlowMetadata flowMetadata = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
+        final FlowEntity flowWithSameName = new FlowEntity();
+        flowWithSameName.setId("flow1");
+        flowWithSameName.setName("Flow 1");
+        flowWithSameName.setDescription("This is flow 1");
+        flowWithSameName.setCreated(new Date());
+        flowWithSameName.setModified(new Date());
 
-        when(metadataProvider.getFlowByName(flowMetadata.getName())).thenReturn(flowMetadata);
+        when(metadataService.getFlowsByName(flowWithSameName.getName())).thenReturn(Collections.singletonList(flowWithSameName));
 
         final VersionedFlow versionedFlow = new VersionedFlow();
-        versionedFlow.setName(flowMetadata.getName());
+        versionedFlow.setName(flowWithSameName.getName());
         versionedFlow.setBucketIdentifier("b1");
 
         registryService.createFlow(versionedFlow.getBucketIdentifier(), versionedFlow);
@@ -339,20 +330,19 @@ public class TestRegistryService {
 
     @Test
     public void testCreateFlowValid() {
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
         final VersionedFlow versionedFlow = new VersionedFlow();
         versionedFlow.setName("My Flow");
         versionedFlow.setBucketIdentifier("b1");
 
-        doAnswer(createFlowAnswer()).when(metadataProvider).createFlow(any(String.class), any(FlowMetadata.class));
+        doAnswer(createFlowAnswer()).when(metadataService).createFlow(any(FlowEntity.class));
 
         final VersionedFlow createdFlow = registryService.createFlow(versionedFlow.getBucketIdentifier(), versionedFlow);
         assertNotNull(createdFlow);
@@ -366,106 +356,112 @@ public class TestRegistryService {
 
     @Test(expected = ResourceNotFoundException.class)
     public void testGetFlowDoesNotExist() {
-        when(metadataProvider.getFlowById(any(String.class))).thenReturn(null);
-        registryService.getFlow("flow1");
+        when(metadataService.getFlowById(any(String.class))).thenReturn(null);
+        registryService.getFlow("flow1", false);
     }
 
     @Test
     public void testGetFlowExists() {
-        final FlowMetadata flowMetadata = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowById(flowMetadata.getIdentifier())).thenReturn(flowMetadata);
-
-        final VersionedFlow versionedFlow = registryService.getFlow(flowMetadata.getIdentifier());
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowEntity = new FlowEntity();
+        flowEntity.setId("flow1");
+        flowEntity.setName("My Flow");
+        flowEntity.setDescription("This is my flow.");
+        flowEntity.setCreated(new Date());
+        flowEntity.setModified(new Date());
+        flowEntity.setBucket(existingBucket);
+
+        when(metadataService.getFlowById(flowEntity.getId())).thenReturn(flowEntity);
+
+        final VersionedFlow versionedFlow = registryService.getFlow(flowEntity.getId(), false);
         assertNotNull(versionedFlow);
-        assertEquals(flowMetadata.getIdentifier(), versionedFlow.getIdentifier());
-        assertEquals(flowMetadata.getName(), versionedFlow.getName());
-        assertEquals(flowMetadata.getDescription(), versionedFlow.getDescription());
-        assertEquals(flowMetadata.getBucketIdentifier(), versionedFlow.getBucketIdentifier());
-        assertEquals(flowMetadata.getCreatedTimestamp(), versionedFlow.getCreatedTimestamp());
-        assertEquals(flowMetadata.getModifiedTimestamp(), versionedFlow.getModifiedTimestamp());
+        assertEquals(flowEntity.getId(), versionedFlow.getIdentifier());
+        assertEquals(flowEntity.getName(), versionedFlow.getName());
+        assertEquals(flowEntity.getDescription(), versionedFlow.getDescription());
+        assertEquals(flowEntity.getBucket().getId(), versionedFlow.getBucketIdentifier());
+        assertEquals(flowEntity.getCreated().getTime(), versionedFlow.getCreatedTimestamp());
+        assertEquals(flowEntity.getModified().getTime(), versionedFlow.getModifiedTimestamp());
     }
 
     @Test
     public void testGetFlows() {
-        final FlowMetadata flowMetadata1 = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        final FlowMetadata flowMetadata2 = new StandardFlowMetadata.Builder()
-                .identifier("flow2")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        final Set<FlowMetadata> flows = new LinkedHashSet<>();
-        flows.add(flowMetadata1);
-        flows.add(flowMetadata2);
-
-        when(metadataProvider.getFlows()).thenReturn(flows);
-
-        final Set<VersionedFlow> allFlows = registryService.getFlows();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowEntity1 = new FlowEntity();
+        flowEntity1.setId("flow1");
+        flowEntity1.setName("My Flow");
+        flowEntity1.setDescription("This is my flow.");
+        flowEntity1.setCreated(new Date());
+        flowEntity1.setModified(new Date());
+        flowEntity1.setBucket(existingBucket);
+
+        final FlowEntity flowEntity2 = new FlowEntity();
+        flowEntity2.setId("flow2");
+        flowEntity2.setName("My Flow 2");
+        flowEntity2.setDescription("This is my flow 2.");
+        flowEntity2.setCreated(new Date());
+        flowEntity2.setModified(new Date());
+        flowEntity2.setBucket(existingBucket);
+
+        final List<FlowEntity> flows = new ArrayList<>();
+        flows.add(flowEntity1);
+        flows.add(flowEntity2);
+
+        when(metadataService.getFlows(any(QueryParameters.class))).thenReturn(flows);
+
+        final QueryParameters queryParameters = new QueryParameters.Builder().build();
+        final List<VersionedFlow> allFlows = registryService.getFlows(queryParameters);
         assertNotNull(allFlows);
         assertEquals(2, allFlows.size());
     }
 
     @Test(expected = ResourceNotFoundException.class)
     public void testGetFlowsByBucketDoesNotExist() {
-        when(metadataProvider.getBucketById(any(String.class))).thenReturn(null);
+        when(metadataService.getBucketById(any(String.class))).thenReturn(null);
         registryService.getFlows("b1");
     }
 
     @Test
     public void testGetFlowsByBucketExists() {
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier("b1")
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
-
-        final FlowMetadata flowMetadata1 = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        final FlowMetadata flowMetadata2 = new StandardFlowMetadata.Builder()
-                .identifier("flow2")
-                .name("My Flow")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        final Set<FlowMetadata> flows = new LinkedHashSet<>();
-        flows.add(flowMetadata1);
-        flows.add(flowMetadata2);
-
-        when(metadataProvider.getFlows(existingBucket.getIdentifier())).thenReturn(flows);
-
-        final Set<VersionedFlow> allFlows = registryService.getFlows(existingBucket.getIdentifier());
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowEntity1 = new FlowEntity();
+        flowEntity1.setId("flow1");
+        flowEntity1.setName("My Flow");
+        flowEntity1.setDescription("This is my flow.");
+        flowEntity1.setCreated(new Date());
+        flowEntity1.setModified(new Date());
+        flowEntity1.setBucket(existingBucket);
+
+        final FlowEntity flowEntity2 = new FlowEntity();
+        flowEntity2.setId("flow2");
+        flowEntity2.setName("My Flow 2");
+        flowEntity2.setDescription("This is my flow 2.");
+        flowEntity2.setCreated(new Date());
+        flowEntity2.setModified(new Date());
+        flowEntity2.setBucket(existingBucket);
+
+        final Set<BucketItemEntity> flows = new LinkedHashSet<>();
+        flows.add(flowEntity1);
+        flows.add(flowEntity2);
+        existingBucket.setItems(flows);
+
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
+
+        final List<VersionedFlow> allFlows = registryService.getFlows(existingBucket.getId());
         assertNotNull(allFlows);
         assertEquals(2, allFlows.size());
     }
@@ -481,37 +477,41 @@ public class TestRegistryService {
         final VersionedFlow versionedFlow = new VersionedFlow();
         versionedFlow.setIdentifier("flow1");
 
-        when(metadataProvider.getFlowById(versionedFlow.getIdentifier())).thenReturn(null);
+        when(metadataService.getFlowById(versionedFlow.getIdentifier())).thenReturn(null);
 
         registryService.updateFlow(versionedFlow);
     }
 
     @Test(expected = IllegalStateException.class)
     public void testUpdateFlowWithSameNameAsExistingFlow() {
-        final FlowMetadata flowToUpdate = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowById(flowToUpdate.getIdentifier())).thenReturn(flowToUpdate);
-
-        final FlowMetadata otherFlow = new StandardFlowMetadata.Builder()
-                .identifier("flow2")
-                .name("My Flow 2")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowByName(otherFlow.getName())).thenReturn(otherFlow);
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowToUpdate = new FlowEntity();
+        flowToUpdate.setId("flow1");
+        flowToUpdate.setName("My Flow");
+        flowToUpdate.setDescription("This is my flow.");
+        flowToUpdate.setCreated(new Date());
+        flowToUpdate.setModified(new Date());
+        flowToUpdate.setBucket(existingBucket);
+
+        when(metadataService.getFlowById(flowToUpdate.getId())).thenReturn(flowToUpdate);
+
+        final FlowEntity otherFlow = new FlowEntity();
+        otherFlow.setId("flow2");
+        otherFlow.setName("My Flow 2");
+        otherFlow.setDescription("This is my flow 2.");
+        otherFlow.setCreated(new Date());
+        otherFlow.setModified(new Date());
+        otherFlow.setBucket(existingBucket);
+
+        when(metadataService.getFlowsByName(otherFlow.getName())).thenReturn(Collections.singletonList(otherFlow));
 
         final VersionedFlow versionedFlow = new VersionedFlow();
-        versionedFlow.setIdentifier(flowToUpdate.getIdentifier());
+        versionedFlow.setIdentifier(flowToUpdate.getId());
         versionedFlow.setName(otherFlow.getName());
 
         registryService.updateFlow(versionedFlow);
@@ -519,22 +519,27 @@ public class TestRegistryService {
 
     @Test
     public void testUpdateFlow() throws InterruptedException {
-        final FlowMetadata flowToUpdate = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowToUpdate = new FlowEntity();
+        flowToUpdate.setId("flow1");
+        flowToUpdate.setName("My Flow");
+        flowToUpdate.setDescription("This is my flow.");
+        flowToUpdate.setCreated(new Date());
+        flowToUpdate.setModified(new Date());
+        flowToUpdate.setBucket(existingBucket);
 
-        when(metadataProvider.getFlowById(flowToUpdate.getIdentifier())).thenReturn(flowToUpdate);
-        when(metadataProvider.getFlowByName(flowToUpdate.getName())).thenReturn(flowToUpdate);
+        when(metadataService.getFlowById(flowToUpdate.getId())).thenReturn(flowToUpdate);
+        when(metadataService.getFlowsByName(flowToUpdate.getName())).thenReturn(Collections.singletonList(flowToUpdate));
 
-        doAnswer(updateFlowAnswer()).when(metadataProvider).updateFlow(any(FlowMetadata.class));
+        doAnswer(updateFlowAnswer()).when(metadataService).updateFlow(any(FlowEntity.class));
 
         final VersionedFlow versionedFlow = new VersionedFlow();
-        versionedFlow.setIdentifier(flowToUpdate.getIdentifier());
+        versionedFlow.setIdentifier(flowToUpdate.getId());
         versionedFlow.setName("New Flow Name");
         versionedFlow.setDescription("This is a new description");
 
@@ -549,42 +554,43 @@ public class TestRegistryService {
         assertEquals(versionedFlow.getDescription(), updatedFlow.getDescription());
 
         // other fields should not be updated
-        assertEquals(flowToUpdate.getBucketIdentifier(), updatedFlow.getBucketIdentifier());
-        assertEquals(flowToUpdate.getCreatedTimestamp(), updatedFlow.getCreatedTimestamp());
-
-        // modified timestamp should be auto updated
-        assertTrue(updatedFlow.getModifiedTimestamp() > flowToUpdate.getModifiedTimestamp());
+        assertEquals(flowToUpdate.getBucket().getId(), updatedFlow.getBucketIdentifier());
+        assertEquals(flowToUpdate.getCreated().getTime(), updatedFlow.getCreatedTimestamp());
     }
 
     @Test(expected = ResourceNotFoundException.class)
     public void testDeleteFlowDoesNotExist() {
-        when(metadataProvider.getFlowById(any(String.class))).thenReturn(null);
+        when(metadataService.getFlowById(any(String.class))).thenReturn(null);
         registryService.deleteFlow("flow1");
     }
 
     @Test
     public void testDeleteFlowWithSnapshots() {
-        final FlowMetadata flowToDelete = new StandardFlowMetadata.Builder()
-                .identifier("flow1")
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier("b1")
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowById(flowToDelete.getIdentifier())).thenReturn(flowToDelete);
-        when(metadataProvider.getFlowByName(flowToDelete.getName())).thenReturn(flowToDelete);
-
-        final VersionedFlow deletedFlow = registryService.deleteFlow(flowToDelete.getIdentifier());
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity flowToDelete = new FlowEntity();
+        flowToDelete.setId("flow1");
+        flowToDelete.setName("My Flow");
+        flowToDelete.setDescription("This is my flow.");
+        flowToDelete.setCreated(new Date());
+        flowToDelete.setModified(new Date());
+        flowToDelete.setBucket(existingBucket);
+
+        when(metadataService.getFlowById(flowToDelete.getId())).thenReturn(flowToDelete);
+        when(metadataService.getFlowsByName(flowToDelete.getName())).thenReturn(Collections.singletonList(flowToDelete));
+
+        final VersionedFlow deletedFlow = registryService.deleteFlow(flowToDelete.getId());
         assertNotNull(deletedFlow);
-        assertEquals(flowToDelete.getIdentifier(), deletedFlow.getIdentifier());
+        assertEquals(flowToDelete.getId(), deletedFlow.getIdentifier());
 
         verify(flowPersistenceProvider, times(1))
-                .deleteSnapshots(flowToDelete.getBucketIdentifier(), flowToDelete.getIdentifier());
+                .deleteSnapshots(flowToDelete.getBucket().getId(), flowToDelete.getId());
 
-        verify(metadataProvider, times(1))
-                .deleteFlow(flowToDelete.getIdentifier());
+        verify(metadataService, times(1)).deleteFlow(flowToDelete);
     }
 
     // ---------------------- Test VersionedFlowSnapshot methods ---------------------------------------------
@@ -638,7 +644,7 @@ public class TestRegistryService {
 
     @Test(expected = ResourceNotFoundException.class)
     public void testCreateSnapshotBucketDoesNotExist() {
-        when(metadataProvider.getBucketById(any(String.class))).thenReturn(null);
+        when(metadataService.getBucketById(any(String.class))).thenReturn(null);
 
         final VersionedFlowSnapshot snapshot = createSnapshot();
         registryService.createFlowSnapshot(snapshot);
@@ -648,16 +654,15 @@ public class TestRegistryService {
     public void testCreateSnapshotFlowDoesNotExist() {
         final VersionedFlowSnapshot snapshot = createSnapshot();
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
-        when(metadataProvider.getFlowById(snapshot.getSnapshotMetadata().getFlowIdentifier())).thenReturn(null);
+        when(metadataService.getFlowById(snapshot.getSnapshotMetadata().getFlowIdentifier())).thenReturn(null);
 
         registryService.createFlowSnapshot(snapshot);
     }
@@ -666,37 +671,37 @@ public class TestRegistryService {
     public void testCreateSnapshotVersionAlreadyExists() {
         final VersionedFlowSnapshot snapshot = createSnapshot();
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
+
+        // return a flow with the existing snapshot when getFlowById is called
+        final FlowEntity existingFlow = new FlowEntity();
+        existingFlow.setId("flow1");
+        existingFlow.setName("My Flow");
+        existingFlow.setDescription("This is my flow.");
+        existingFlow.setCreated(new Date());
+        existingFlow.setModified(new Date());
+        existingFlow.setBucket(existingBucket);
 
         // make a snapshot that has the same version as the one being created
-        final FlowSnapshotMetadata existingSnapshot = new StandardFlowSnapshotMetadata.Builder()
-                .flowIdentifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .flowName(snapshot.getSnapshotMetadata().getFlowName())
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .version(snapshot.getSnapshotMetadata().getVersion())
-                .comments("This is an existing snapshot")
-                .created(System.currentTimeMillis())
-                .build();
+        final FlowSnapshotEntityKey key = new FlowSnapshotEntityKey();
+        key.setFlowId(snapshot.getSnapshotMetadata().getFlowIdentifier());
+        key.setVersion(snapshot.getSnapshotMetadata().getVersion());
 
-        // return a flow with the existing snapshot when getFlowById is called
-        final FlowMetadata existingFlow = new StandardFlowMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .addSnapshot(existingSnapshot)
-                .build();
-
-        when(metadataProvider.getFlowById(existingFlow.getIdentifier())).thenReturn(existingFlow);
+        final FlowSnapshotEntity existingSnapshot = new FlowSnapshotEntity();
+        existingSnapshot.setId(key);
+        existingSnapshot.setComments("This is an existing snapshot");
+        existingSnapshot.setCreated(new Date());
+        existingSnapshot.setFlow(existingFlow);
+
+        existingFlow.setSnapshots(Collections.singleton(existingSnapshot));
+
+        when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
 
         registryService.createFlowSnapshot(snapshot);
     }
@@ -705,37 +710,37 @@ public class TestRegistryService {
     public void testCreateSnapshotVersionNotNextVersion() {
         final VersionedFlowSnapshot snapshot = createSnapshot();
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
-
-        // make a snapshot for version 1
-        final FlowSnapshotMetadata existingSnapshot = new StandardFlowSnapshotMetadata.Builder()
-                .flowIdentifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .flowName(snapshot.getSnapshotMetadata().getFlowName())
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .version(1)
-                .comments("This is an existing snapshot")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
         // return a flow with the existing snapshot when getFlowById is called
-        final FlowMetadata existingFlow = new StandardFlowMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .addSnapshot(existingSnapshot)
-                .build();
-
-        when(metadataProvider.getFlowById(existingFlow.getIdentifier())).thenReturn(existingFlow);
+        final FlowEntity existingFlow = new FlowEntity();
+        existingFlow.setId("flow1");
+        existingFlow.setName("My Flow");
+        existingFlow.setDescription("This is my flow.");
+        existingFlow.setCreated(new Date());
+        existingFlow.setModified(new Date());
+        existingFlow.setBucket(existingBucket);
+
+        // make a snapshot that has the same version as the one being created
+        final FlowSnapshotEntityKey key = new FlowSnapshotEntityKey();
+        key.setFlowId(snapshot.getSnapshotMetadata().getFlowIdentifier());
+        key.setVersion(snapshot.getSnapshotMetadata().getVersion());
+
+        final FlowSnapshotEntity existingSnapshot = new FlowSnapshotEntity();
+        existingSnapshot.setId(key);
+        existingSnapshot.setComments("This is an existing snapshot");
+        existingSnapshot.setCreated(new Date());
+        existingSnapshot.setFlow(existingFlow);
+
+        existingFlow.setSnapshots(Collections.singleton(existingSnapshot));
+
+        when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
 
         // set the version to something that is not the next one-up version
         snapshot.getSnapshotMetadata().setVersion(100);
@@ -746,59 +751,55 @@ public class TestRegistryService {
     public void testCreateFirstSnapshot() {
         final VersionedFlowSnapshot snapshot = createSnapshot();
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
         // return a flow with the existing snapshot when getFlowById is called
-        final FlowMetadata existingFlow = new StandardFlowMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
+        final FlowEntity existingFlow = new FlowEntity();
+        existingFlow.setId("flow1");
+        existingFlow.setName("My Flow");
+        existingFlow.setDescription("This is my flow.");
+        existingFlow.setCreated(new Date());
+        existingFlow.setModified(new Date());
+        existingFlow.setBucket(existingBucket);
 
-        when(metadataProvider.getFlowById(existingFlow.getIdentifier())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
 
         final VersionedFlowSnapshot createdSnapshot = registryService.createFlowSnapshot(snapshot);
         assertNotNull(createdSnapshot);
 
         verify(snapshotSerializer, times(1)).serialize(eq(snapshot), any(OutputStream.class));
         verify(flowPersistenceProvider, times(1)).saveSnapshot(any(), any());
-        verify(metadataProvider, times(1)).createFlowSnapshot(any(FlowSnapshotMetadata.class));
+        verify(metadataService, times(1)).createFlowSnapshot(any(FlowSnapshotEntity.class));
     }
 
     @Test(expected = IllegalStateException.class)
     public void testCreateFirstSnapshotWithBadVersion() {
         final VersionedFlowSnapshot snapshot = createSnapshot();
 
-        final BucketMetadata existingBucket = new StandardBucketMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .name("My Bucket #1")
-                .description("This is my bucket.")
-                .created(System.currentTimeMillis())
-                .build();
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
 
-        when(metadataProvider.getBucketById(existingBucket.getIdentifier())).thenReturn(existingBucket);
+        when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
         // return a flow with the existing snapshot when getFlowById is called
-        final FlowMetadata existingFlow = new StandardFlowMetadata.Builder()
-                .identifier(snapshot.getSnapshotMetadata().getFlowIdentifier())
-                .name("My Flow 1")
-                .description("This is my flow.")
-                .bucketIdentifier(snapshot.getSnapshotMetadata().getBucketIdentifier())
-                .created(System.currentTimeMillis())
-                .modified(System.currentTimeMillis())
-                .build();
+        final FlowEntity existingFlow = new FlowEntity();
+        existingFlow.setId("flow1");
+        existingFlow.setName("My Flow");
+        existingFlow.setDescription("This is my flow.");
+        existingFlow.setCreated(new Date());
+        existingFlow.setModified(new Date());
+        existingFlow.setBucket(existingBucket);
 
-        when(metadataProvider.getFlowById(existingFlow.getIdentifier())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
 
         // set the first version to something other than 1
         snapshot.getSnapshotMetadata().setVersion(100);
@@ -809,59 +810,46 @@ public class TestRegistryService {
     public void testGetSnapshotDoesNotExistInMetadataProvider() {
         final String flowId = "flow1";
         final Integer version = 1;
-        when(metadataProvider.getFlowSnapshot(flowId, version)).thenReturn(null);
+        when(metadataService.getFlowSnapshot(flowId, version)).thenReturn(null);
         registryService.getFlowSnapshot(flowId, version);
     }
 
     @Test(expected = IllegalStateException.class)
     public void testGetSnapshotDoesNotExistInPersistenceProvider() {
-        final FlowSnapshotMetadata existingSnapshot = new StandardFlowSnapshotMetadata.Builder()
-                .bucketIdentifier("b1")
-                .flowIdentifier("flow1")
-                .flowName("Flow 1")
-                .version(1)
-                .comments("This is snapshot 1")
-                .created(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowSnapshot(existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion()))
-                .thenReturn(existingSnapshot);
+        final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
+        final FlowSnapshotEntityKey key = existingSnapshot.getId();
+
+        when(metadataService.getFlowSnapshot(key.getFlowId(), key.getVersion())).thenReturn(existingSnapshot);
 
         when(flowPersistenceProvider.getSnapshot(
-                existingSnapshot.getBucketIdentifier(),
-                existingSnapshot.getFlowIdentifier(),
-                existingSnapshot.getVersion()
+                existingSnapshot.getFlow().getBucket().getId(),
+                existingSnapshot.getFlow().getId(),
+                existingSnapshot.getId().getVersion()
         )).thenReturn(null);
 
-        registryService.getFlowSnapshot(existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion());
+        registryService.getFlowSnapshot(existingSnapshot.getFlow().getId(), existingSnapshot.getId().getVersion());
     }
 
     @Test
     public void testGetSnapshotExists() {
-        final FlowSnapshotMetadata existingSnapshot = new StandardFlowSnapshotMetadata.Builder()
-                .bucketIdentifier("b1")
-                .flowIdentifier("flow1")
-                .flowName("Flow 1")
-                .version(1)
-                .comments("This is snapshot 1")
-                .created(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowSnapshot(existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion()))
+        final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
+        final FlowSnapshotEntityKey key = existingSnapshot.getId();
+
+        when(metadataService.getFlowSnapshot(key.getFlowId(), key.getVersion()))
                 .thenReturn(existingSnapshot);
 
         // return a non-null, non-zero-length array so something gets passed to the serializer
         when(flowPersistenceProvider.getSnapshot(
-                existingSnapshot.getBucketIdentifier(),
-                existingSnapshot.getFlowIdentifier(),
-                existingSnapshot.getVersion()
+                existingSnapshot.getFlow().getBucket().getId(),
+                existingSnapshot.getFlow().getId(),
+                existingSnapshot.getId().getVersion()
         )).thenReturn(new byte[10]);
 
         final VersionedFlowSnapshot snapshotToDeserialize = createSnapshot();
         when(snapshotSerializer.deserialize(any(InputStream.class))).thenReturn(snapshotToDeserialize);
 
         final VersionedFlowSnapshot returnedSnapshot = registryService.getFlowSnapshot(
-                existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion());
+                existingSnapshot.getFlow().getId(), existingSnapshot.getId().getVersion());
         assertNotNull(returnedSnapshot);
     }
 
@@ -869,68 +857,86 @@ public class TestRegistryService {
     public void testDeleteSnapshotDoesNotExist() {
         final String flowId = "flow1";
         final Integer version = 1;
-        when(metadataProvider.getFlowSnapshot(flowId, version)).thenReturn(null);
+        when(metadataService.getFlowSnapshot(flowId, version)).thenReturn(null);
         registryService.deleteFlowSnapshot(flowId, version);
     }
 
     @Test
     public void testDeleteSnapshotExists() {
-        final FlowSnapshotMetadata existingSnapshot = new StandardFlowSnapshotMetadata.Builder()
-                .bucketIdentifier("b1")
-                .flowIdentifier("flow1")
-                .flowName("Flow 1")
-                .version(1)
-                .comments("This is snapshot 1")
-                .created(System.currentTimeMillis())
-                .build();
-
-        when(metadataProvider.getFlowSnapshot(existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion()))
+        final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
+        final FlowSnapshotEntityKey key = existingSnapshot.getId();
+
+        when(metadataService.getFlowSnapshot(key.getFlowId(), key.getVersion()))
                 .thenReturn(existingSnapshot);
 
-        final VersionedFlowSnapshotMetadata deletedSnapshot = registryService.deleteFlowSnapshot(
-                existingSnapshot.getFlowIdentifier(), existingSnapshot.getVersion());
+        final VersionedFlowSnapshotMetadata deletedSnapshot = registryService.deleteFlowSnapshot(key.getFlowId(), key.getVersion());
         assertNotNull(deletedSnapshot);
-        assertEquals(existingSnapshot.getFlowIdentifier(), deletedSnapshot.getFlowIdentifier());
+        assertEquals(existingSnapshot.getId().getFlowId(), deletedSnapshot.getFlowIdentifier());
 
         verify(flowPersistenceProvider, times(1)).deleteSnapshot(
-                existingSnapshot.getBucketIdentifier(),
-                existingSnapshot.getFlowIdentifier(),
-                existingSnapshot.getVersion()
+                existingSnapshot.getFlow().getBucket().getId(),
+                existingSnapshot.getFlow().getId(),
+                existingSnapshot.getId().getVersion()
         );
 
-        verify(metadataProvider, times(1)).deleteFlowSnapshot(
-                existingSnapshot.getFlowIdentifier(),
-                existingSnapshot.getVersion()
-        );
+        verify(metadataService, times(1)).deleteFlowSnapshot(existingSnapshot);
+    }
+
+    private FlowSnapshotEntity createFlowSnapshotEntity() {
+        final BucketEntity existingBucket = new BucketEntity();
+        existingBucket.setId("b1");
+        existingBucket.setName("My Bucket");
+        existingBucket.setDescription("This is my bucket");
+        existingBucket.setCreated(new Date());
+
+        final FlowEntity existingFlow = new FlowEntity();
+        existingFlow.setId("flow1");
+        existingFlow.setName("My Flow");
+        existingFlow.setDescription("This is my flow.");
+        existingFlow.setCreated(new Date());
+        existingFlow.setModified(new Date());
+        existingFlow.setBucket(existingBucket);
+
+        final FlowSnapshotEntityKey key = new FlowSnapshotEntityKey();
+        key.setFlowId("flow1");
+        key.setVersion(1);
+
+        final FlowSnapshotEntity existingSnapshot = new FlowSnapshotEntity();
+        existingSnapshot.setId(key);
+        existingSnapshot.setComments("This is an existing snapshot");
+        existingSnapshot.setCreated(new Date());
+        existingSnapshot.setFlow(existingFlow);
+
+        return existingSnapshot;
     }
 
     // -------------------------------------------------------------------
 
-    private Answer<BucketMetadata> createBucketAnswer() {
+    private Answer<BucketEntity> createBucketAnswer() {
         return (InvocationOnMock invocation) -> {
-            BucketMetadata bucketMetadata = (BucketMetadata) invocation.getArguments()[0];
-            return bucketMetadata;
+            BucketEntity bucketEntity = (BucketEntity) invocation.getArguments()[0];
+            return bucketEntity;
         };
     }
 
-    private Answer<BucketMetadata> updateBucketAnswer() {
+    private Answer<BucketEntity> updateBucketAnswer() {
         return (InvocationOnMock invocation) -> {
-            BucketMetadata bucketMetadata = (BucketMetadata) invocation.getArguments()[0];
-            return bucketMetadata;
+            BucketEntity bucketEntity = (BucketEntity) invocation.getArguments()[0];
+            return bucketEntity;
         };
     }
 
-    private Answer<FlowMetadata> createFlowAnswer() {
+    private Answer<FlowEntity> createFlowAnswer() {
         return (InvocationOnMock invocation) -> {
-            final FlowMetadata flowMetadata = (FlowMetadata) invocation.getArguments()[1];
-            return flowMetadata;
+            final FlowEntity flowEntity = (FlowEntity) invocation.getArguments()[0];
+            return flowEntity;
         };
     }
 
-    private Answer<FlowMetadata> updateFlowAnswer() {
+    private Answer<FlowEntity> updateFlowAnswer() {
         return (InvocationOnMock invocation) -> {
-            final FlowMetadata flowMetadata = (FlowMetadata) invocation.getArguments()[0];
-            return flowMetadata;
+            final FlowEntity flowEntity = (FlowEntity) invocation.getArguments()[0];
+            return flowEntity;
         };
     }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-framework/src/test/resources/application.properties
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/resources/application.properties b/nifi-registry-framework/src/test/resources/application.properties
new file mode 100644
index 0000000..fb91fb6
--- /dev/null
+++ b/nifi-registry-framework/src/test/resources/application.properties
@@ -0,0 +1,19 @@
+# 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.
+
+# Properties for Spring Boot tests
+
+spring.jpa.hibernate.ddl-auto=validate
+spring.jpa.show-sql=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql b/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
new file mode 100644
index 0000000..4352e50
--- /dev/null
+++ b/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
@@ -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.
+
+-- test data for buckets
+
+insert into bucket (id, name, description, created)
+  values ('1', 'Bucket 1', 'This is test bucket 1', parsedatetime('2017-09-11 12:51:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+insert into bucket (id, name, description, created)
+  values ('2', 'Bucket 2', 'This is test bucket 2', parsedatetime('2017-09-11 12:52:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+insert into bucket (id, name, description, created)
+  values ('3', 'Bucket 3', 'This is test bucket 3', parsedatetime('2017-09-11 12:53:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+insert into bucket (id, name, description, created)
+  values ('4', 'Bucket 4', 'This is test bucket 4', parsedatetime('2017-09-11 12:54:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+insert into bucket (id, name, description, created)
+  values ('5', 'Bucket 5', 'This is test bucket 5', parsedatetime('2017-09-11 12:55:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+insert into bucket (id, name, description, created)
+  values ('6', 'Bucket 6', 'This is test bucket 6', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+
+
+-- test data for flows
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('1', 'Flow 1', 'This is flow 1', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '1');
+
+insert into flow (id) values ('1');
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('2', 'Flow 2', 'This is flow 2', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '1');
+
+insert into flow (id) values ('2');
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('3', 'Flow 3', 'This is flow 3', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '2');
+
+insert into flow (id) values ('3');
+
+
+-- test data for flow snapshots
+
+insert into flow_snapshot (flow_id, version, created, comments)
+  values ('1', 1, parsedatetime('2017-09-11 12:57:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 1');
+
+insert into flow_snapshot (flow_id, version, created, comments)
+  values ('1', 2, parsedatetime('2017-09-11 12:58:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 2');
+
+insert into flow_snapshot (flow_id, version, created, comments)
+  values ('1', 3, parsedatetime('2017-09-11 12:59:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 3');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-framework/src/test/resources/provider/providers-class-not-found.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/resources/provider/providers-class-not-found.xml b/nifi-registry-framework/src/test/resources/provider/providers-class-not-found.xml
index 8b5debe..9adba54 100644
--- a/nifi-registry-framework/src/test/resources/provider/providers-class-not-found.xml
+++ b/nifi-registry-framework/src/test/resources/provider/providers-class-not-found.xml
@@ -15,12 +15,6 @@
 -->
 <providers>
 
-    <metadataProvider>
-        <class>org.apache.nifi.registry.provider.MetadataProviderXXX</class>
-        <property name="Metadata Property 1">foo</property>
-        <property name="Metadata Property 2">bar</property>
-    </metadataProvider>
-
     <flowPersistenceProvider>
         <class>org.apache.nifi.registry.provider.FlowProviderXXX</class>
         <property name="Flow Property 1">foo</property>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-framework/src/test/resources/provider/providers-good.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/resources/provider/providers-good.xml b/nifi-registry-framework/src/test/resources/provider/providers-good.xml
index 4ef2a06..32414e5 100644
--- a/nifi-registry-framework/src/test/resources/provider/providers-good.xml
+++ b/nifi-registry-framework/src/test/resources/provider/providers-good.xml
@@ -15,12 +15,6 @@
 -->
 <providers>
 
-    <metadataProvider>
-        <class>org.apache.nifi.registry.provider.MockMetadataProvider</class>
-        <property name="Metadata Property 1">metadata foo</property>
-        <property name="Metadata Property 2">metadata bar</property>
-    </metadataProvider>
-
     <flowPersistenceProvider>
         <class>org.apache.nifi.registry.provider.MockFlowPersistenceProvider</class>
         <property name="Flow Property 1">flow foo</property>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
----------------------------------------------------------------------
diff --git a/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
index 35a1b48..6aac4a6 100644
--- a/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
+++ b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
@@ -47,6 +47,9 @@ public class NiFiRegistryProperties extends Properties {
 
     public static final String PROVIDERS_CONFIGURATION_FILE = "nifi.registry.providers.configuration.file";
 
+    public static final String DATABASE_DIRECTORY = "nifi.registry.db.directory";
+    public static final String DATABASE_URL_APPEND = "nifi.registry.db.url.append";
+
     // Defaults
     public static final String DEFAULT_WEB_WORKING_DIR = "./work/jetty";
     public static final String DEFAULT_WAR_DIR = "./lib";
@@ -155,4 +158,13 @@ public class NiFiRegistryProperties extends Properties {
             return new File(value);
         }
     }
+
+    public String getDatabaseDirectory() {
+        return getProperty(DATABASE_DIRECTORY);
+    }
+
+    public String getDatabaseUrlAppend() {
+        return getProperty(DATABASE_URL_APPEND);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/BucketMetadata.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/BucketMetadata.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/BucketMetadata.java
deleted file mode 100644
index 7d10da5..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/BucketMetadata.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-import java.util.Set;
-
-/**
- * The metadata for a bucket, along with the metadata about any objects stored in the bucket, such as flows.
- */
-public interface BucketMetadata {
-
-    /**
-     * @return the identifier of this bucket
-     */
-    String getIdentifier();
-
-    /**
-     * @return the name of this bucket
-     */
-    String getName();
-
-    /**
-     * @return the timestamp of when this bucket was created
-     */
-    long getCreatedTimestamp();
-
-    /**
-     * @return the description of this bucket
-     */
-    String getDescription();
-
-    /**
-     * @return the metadata about the flows that are part of this bucket
-     */
-    Set<FlowMetadata> getFlowMetadata();
-
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowMetadata.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowMetadata.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowMetadata.java
deleted file mode 100644
index 0aebb63..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowMetadata.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-import java.util.Set;
-
-/**
- * The metadata about a flow, including the metadata about any of it's snapshots.
- */
-public interface FlowMetadata {
-
-    /**
-     * @return the identifier of this flow
-     */
-    String getIdentifier();
-
-    /**
-     * @return the name of this flow
-     */
-    String getName();
-
-    /**
-     * @return the identifier of the bucket this flow belongs to
-     */
-    String getBucketIdentifier();
-
-    /**
-     * @return the timestamp this flow was created
-     */
-    long getCreatedTimestamp();
-
-    /**
-     * @return the timestamp this flow was modified
-     */
-    long getModifiedTimestamp();
-
-    /**
-     * @return the description of this flow
-     */
-    String getDescription();
-
-    /**
-     * @return the metadata for the snapshots of this flow
-     */
-    Set<FlowSnapshotMetadata> getSnapshotMetadata();
-
-    /**
-     * Get the snapshot for the given version.
-     *
-     * @param version the version of a snapshot
-     * @return the snapshot for the given version, or null if one doesn't exist
-     */
-    FlowSnapshotMetadata getSnapshot(int version);
-
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowSnapshotMetadata.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowSnapshotMetadata.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowSnapshotMetadata.java
deleted file mode 100644
index 98cb666..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/FlowSnapshotMetadata.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-/**
- * The metadata for a flow snapshot.
- */
-public interface FlowSnapshotMetadata {
-
-    /**
-     * @return the identifier of the bucket this snapshot belongs to
-     */
-    String getBucketIdentifier();
-
-    /**
-     * @return the identifier of the flow this snapshot belongs to
-     */
-    String getFlowIdentifier();
-
-    /**
-     * @return the name of the flow this snapshot belongs to
-     */
-    String getFlowName();
-
-    /**
-     * @return the version of this snapshot
-     */
-    int getVersion();
-
-    /**
-     * @return the timestamp of when this snapshot was created
-     */
-    long getCreatedTimestamp();
-
-    /**
-     * @return the comments for this snapshot
-     */
-    String getComments();
-
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProvider.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProvider.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProvider.java
deleted file mode 100644
index 3ddcadc..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProvider.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-import org.apache.nifi.registry.provider.Provider;
-
-import java.util.Set;
-
-/**
- * A service for managing metadata about all objects stored by the registry.
- *
- * NOTE: Although this interface is intended to be an extension point, it is not yet considered stable and thus may
- * change across releases until the registry matures.
- */
-public interface MetadataProvider extends Provider {
-
-    /**
-     * Creates the given bucket.
-     *
-     * @param bucket the bucket to create
-     * @return the created bucket
-     */
-    BucketMetadata createBucket(BucketMetadata bucket);
-
-    /**
-     * Retrieves the bucket with the given id.
-     *
-     * @param bucketIdentifier the id of the bucket to retrieve
-     * @return the bucket with the given id, or null if it does not exist
-     */
-    BucketMetadata getBucketById(String bucketIdentifier);
-
-    /**
-     * Retrieves the bucket with the given name. The name comparison must be case-insensitive.
-     *
-     * @param name the name of the bucket to retrieve
-     * @return the bucket with the given name, or null if it does not exist
-     */
-    BucketMetadata getBucketByName(String name);
-    /**
-     * Updates the given bucket, only the name and description should be allowed to be updated.
-     *
-     * @param bucket the updated bucket to save
-     * @return the updated bucket, or null if no bucket with the given id exists
-     */
-    BucketMetadata updateBucket(BucketMetadata bucket);
-
-    /**
-     * Deletes the bucket with the given identifier, as well as any objects that reference the bucket.
-     *
-     * @param bucketIdentifier the id of the bucket to delete
-     */
-    void deleteBucket(String bucketIdentifier);
-
-    /**
-     * Retrieves all buckets known to this metadata provider.
-     *
-     * @return the set of all buckets
-     */
-    Set<BucketMetadata> getBuckets();
-
-    /**
-     * Creates a versioned flow in the given bucket.
-     *
-     * @param bucketIdentifier the id of the bucket where the flow is being created
-     * @param flow the versioned flow to create
-     * @return the created versioned flow
-     * @throws IllegalStateException if no bucket with the given identifier exists
-     */
-    FlowMetadata createFlow(String bucketIdentifier, FlowMetadata flow);
-
-    /**
-     * Retrieves the versioned flow with the given id.
-     *
-     * @param flowIdentifier the identifier of the flow to retrieve
-     * @return the versioned flow with the given id, or null if no flow with the given id exists
-     */
-    FlowMetadata getFlowById(String flowIdentifier);
-
-    /**
-     * Retrieves the versioned flow with the given name. The name comparison must be case-insensitive.
-     *
-     * @param name the name of the flow to retrieve
-     * @return the versioned flow with the given name, or null if no flow with the given name exists
-     */
-    FlowMetadata getFlowByName(String name);
-
-    /**
-     * Updates the given versioned flow, only the name and description should be allowed to be updated.
-     *
-     * @param versionedFlow the updated versioned flow to save
-     * @return the updated versioned flow
-     */
-    FlowMetadata updateFlow(FlowMetadata versionedFlow);
-
-    /**
-     * Deletes the versioned flow with the given identifier if one exists.
-     *
-     * @param flowIdentifier the id of the versioned flow to delete
-     */
-    void deleteFlow(String flowIdentifier);
-
-    /**
-     * Retrieves all versioned flows known to this metadata provider.
-     *
-     * @return the set of all versioned flows
-     */
-    Set<FlowMetadata> getFlows();
-
-    /**
-     * Retrieves all the versioned flows for the given bucket.
-     *
-     * @param bucketId the id of the bucket to retrieve flow for
-     * @return the set of versioned flows for the given bucket, or an empty set if none exist
-     */
-    Set<FlowMetadata> getFlows(String bucketId);
-
-    /**
-     * Creates a versioned flow snapshot.
-     *
-     * @param flowSnapshot the snapshot to create
-     * @return the created snapshot
-     * @throws IllegalStateException if the versioned flow specified by flowSnapshot.getFlowIdentifier() does not exist
-     */
-    FlowSnapshotMetadata createFlowSnapshot(FlowSnapshotMetadata flowSnapshot);
-
-    /**
-     * Retrieves the snapshot for the given flow identifier and snapshot version.
-     *
-     * @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
-     */
-    FlowSnapshotMetadata getFlowSnapshot(String flowIdentifier, Integer version);
-
-    /**
-     * Deletes the snapshot for the given flow identifier and version.
-     *
-     * @param flowIdentifier the identifier of the flow the snapshot belongs to
-     * @param version the version of the snapshot
-     */
-    void deleteFlowSnapshot(String flowIdentifier, Integer version);
-
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProviderException.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProviderException.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProviderException.java
deleted file mode 100644
index bce9352..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/MetadataProviderException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-/**
- * An exception thrown when an error is encountered by a MetadataProvider.
- */
-public class MetadataProviderException extends RuntimeException {
-
-    public MetadataProviderException(String message) {
-        super(message);
-    }
-
-    public MetadataProviderException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public MetadataProviderException(Throwable cause) {
-        super(cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/d478c20e/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/StandardBucketMetadata.java
----------------------------------------------------------------------
diff --git a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/StandardBucketMetadata.java b/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/StandardBucketMetadata.java
deleted file mode 100644
index 02568e6..0000000
--- a/nifi-registry-provider-api/src/main/java/org/apache/nifi/registry/metadata/StandardBucketMetadata.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.metadata;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-public class StandardBucketMetadata implements BucketMetadata {
-
-    private final String identifier;
-    private final String name;
-    private final long createdTimestamp;
-    private final String description;
-    private final Set<FlowMetadata> flowMetadata;
-
-    private StandardBucketMetadata(final Builder builder) {
-        this.identifier = builder.identifier;
-        this.name = builder.name;
-        this.createdTimestamp = builder.createdTimestamp;
-        this.description = builder.description;
-        this.flowMetadata = Collections.unmodifiableSet(
-                builder.flowMetadata == null
-                        ? Collections.emptySet() : new LinkedHashSet<>(builder.flowMetadata)
-        );
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public long getCreatedTimestamp() {
-        return createdTimestamp;
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-    @Override
-    public Set<FlowMetadata> getFlowMetadata() {
-        return flowMetadata;
-    }
-
-    public static class Builder {
-
-        private String identifier;
-        private String name;
-        private long createdTimestamp;
-        private String description;
-        private Set<FlowMetadata> flowMetadata = new LinkedHashSet<>();
-
-        public Builder() {
-
-        }
-
-        public Builder(BucketMetadata bucketMetadata) {
-            identifier(bucketMetadata.getIdentifier());
-            name(bucketMetadata.getName());
-            created(bucketMetadata.getCreatedTimestamp());
-            description(bucketMetadata.getDescription());
-            addFlows(bucketMetadata.getFlowMetadata());
-        }
-
-        public Builder identifier(final String identifier) {
-            this.identifier = identifier;
-            return this;
-        }
-
-        public Builder name(final String name) {
-            this.name = name;
-            return this;
-        }
-
-        public Builder created(final long createdTimestamp) {
-            this.createdTimestamp = createdTimestamp;
-            return this;
-        }
-
-        public Builder description(final String description) {
-            this.description = description;
-            return this;
-        }
-
-        public Builder addFlow(final FlowMetadata flowMetadata) {
-            if (flowMetadata != null) {
-                this.flowMetadata.add(flowMetadata);
-            }
-            return this;
-        }
-
-        public Builder addFlows(final Collection<FlowMetadata> flows) {
-            if (flows != null) {
-                this.flowMetadata.addAll(flows);
-            }
-            return this;
-        }
-
-        public Builder clearFlows() {
-            this.flowMetadata.clear();
-            return this;
-        }
-
-        public StandardBucketMetadata build() {
-            return new StandardBucketMetadata(this);
-        }
-    }
-}