You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/09/22 02:11:39 UTC
[40/51] [partial] nifi-registry git commit: NIFIREG-201 Refactoring
project structure to better isolate extensions
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/pom.xml b/nifi-registry-core/nifi-registry-framework/pom.xml
new file mode 100644
index 0000000..ca74ab1
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/pom.xml
@@ -0,0 +1,366 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-core</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>nifi-registry-framework</artifactId>
+ <packaging>jar</packaging>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>src/main/xsd</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jaxb2-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>providers</id>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/xsd/providers.xsd</source>
+ </sources>
+ <packageName>org.apache.nifi.registry.provider.generated</packageName>
+ <clearOutputDir>false</clearOutputDir>
+ </configuration>
+ </execution>
+ <execution>
+ <id>authorizers</id>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/xsd/authorizers.xsd</source>
+ </sources>
+ <packageName>org.apache.nifi.registry.security.authorization.generated</packageName>
+ <clearOutputDir>false</clearOutputDir>
+ </configuration>
+ </execution>
+ <execution>
+ <id>authorizations</id>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/xsd/authorizations.xsd</source>
+ </sources>
+ <packageName>org.apache.nifi.registry.security.authorization.file.generated</packageName>
+ <clearOutputDir>false</clearOutputDir>
+ </configuration>
+ </execution>
+ <execution>
+ <id>tenants</id>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/xsd/tenants.xsd</source>
+ </sources>
+ <packageName>org.apache.nifi.registry.security.authorization.file.tenants.generated</packageName>
+ <clearOutputDir>false</clearOutputDir>
+ </configuration>
+ </execution>
+ <execution>
+ <id>identity-providers</id>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/main/xsd/identity-providers.xsd</source>
+ </sources>
+ <packageName>org.apache.nifi.registry.security.authentication.generated</packageName>
+ <clearOutputDir>false</clearOutputDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <excludes>**/generated/*.java</excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.gmavenplus</groupId>
+ <artifactId>gmavenplus-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>addTestSources</goal>
+ <goal>testCompile</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes combine.children="append">
+ <exclude>src/test/resources/serialization/json/no-version.snapshot</exclude>
+ <exclude>src/test/resources/serialization/json/non-integer-version.snapshot</exclude>
+ <exclude>src/test/resources/serialization/ver1.snapshot</exclude>
+ <exclude>src/test/resources/serialization/ver2.snapshot</exclude>
+ <exclude>src/test/resources/serialization/ver3.snapshot</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-data-model</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-properties</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-utils</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <scope>provided</scope> <!-- will be in lib dir -->
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-provider-api</artifactId>
+ <scope>provided</scope> <!-- will be in lib dir -->
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-security-api</artifactId>
+ <scope>provided</scope> <!-- will be in lib dir -->
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-security-utils</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ <version>${spring.boot.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-ldap</artifactId>
+ <version>${spring.security.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-tx</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>1.55</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish</groupId>
+ <artifactId>javax.el</artifactId>
+ </dependency>
+ <!-- We're using spring-boot-starter-data-jpa to bring in spring-data-jdbc and a few other dependencies, but
+ we aren't actually using any JPA dependencies, this also brings in the standard Spring dependencies for the backend -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ <version>${spring.boot.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat-jdbc</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.data</groupId>
+ <artifactId>spring-data-jpa</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.flywaydb</groupId>
+ <artifactId>flyway-core</artifactId>
+ <version>${flyway.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <version>1.4.196</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit</artifactId>
+ <version>4.11.0.201803080745-r</version>
+ </dependency>
+ <dependency>
+ <groupId>com.jcraft</groupId>
+ <artifactId>jsch</artifactId>
+ <version>0.1.54</version>
+ </dependency>
+ <dependency>
+ <groupId>org.yaml</groupId>
+ <artifactId>snakeyaml</artifactId>
+ <version>1.20</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.module</groupId>
+ <artifactId>jackson-module-jaxb-annotations</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <!-- Test Dependencies -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <version>${spring.boot.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.flywaydb.flyway-test-extensions</groupId>
+ <artifactId>flyway-spring-test</artifactId>
+ <version>${flyway.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.spockframework</groupId>
+ <artifactId>spock-core</artifactId>
+ <version>1.0-groovy-2.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <version>2.4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <version>2.2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-all</artifactId>
+ <version>2.0.0-M24</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.registry</groupId>
+ <artifactId>nifi-registry-flow-diff</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/CustomFlywayMigrationStrategy.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/CustomFlywayMigrationStrategy.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/CustomFlywayMigrationStrategy.java
new file mode 100644
index 0000000..7748acf
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/CustomFlywayMigrationStrategy.java
@@ -0,0 +1,157 @@
+/*
+ * 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.db;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.db.migration.BucketEntityV1;
+import org.apache.nifi.registry.db.migration.FlowEntityV1;
+import org.apache.nifi.registry.db.migration.FlowSnapshotEntityV1;
+import org.apache.nifi.registry.db.migration.LegacyDataSourceFactory;
+import org.apache.nifi.registry.db.migration.LegacyDatabaseService;
+import org.apache.nifi.registry.db.migration.LegacyEntityMapper;
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.apache.nifi.registry.service.MetadataService;
+import org.flywaydb.core.Flyway;
+import org.flywaydb.core.api.FlywayException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Custom Flyway migration strategy that lets us perform data migration from the original database used in the
+ * 0.1.0 release, to the new database. The data migration will be triggered when it is determined that new database
+ * is brand new AND the legacy DB properties are specified. If the primary database already contains the 'BUCKET' table,
+ * or if the legacy database properties are not specified, then no data migration is performed.
+ */
+@Component
+public class CustomFlywayMigrationStrategy implements FlywayMigrationStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CustomFlywayMigrationStrategy.class);
+
+ private NiFiRegistryProperties properties;
+
+ @Autowired
+ public CustomFlywayMigrationStrategy(final NiFiRegistryProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void migrate(Flyway flyway) {
+ final boolean newDatabase = isNewDatabase(flyway.getDataSource());
+ if (newDatabase) {
+ LOGGER.info("First time initializing database...");
+ } else {
+ LOGGER.info("Found existing database...");
+ }
+
+ boolean existingLegacyDatabase = false;
+ if (!StringUtils.isBlank(properties.getLegacyDatabaseDirectory())) {
+ LOGGER.info("Found legacy database properties...");
+
+ final File legacyDatabaseFile = new File(properties.getLegacyDatabaseDirectory(), "nifi-registry.mv.db");
+ if (legacyDatabaseFile.exists()) {
+ LOGGER.info("Found legacy database file...");
+ existingLegacyDatabase = true;
+ } else {
+ LOGGER.info("Did not find legacy database file...");
+ existingLegacyDatabase = false;
+ }
+ }
+
+ // If newDatabase is true, then we need to run the Flyway migration first to create all the tables, then the data migration
+ // If newDatabase is false, then we need to run the Flyway migration to run any schema updates, but no data migration
+
+ flyway.migrate();
+
+ if (newDatabase && existingLegacyDatabase) {
+ final LegacyDataSourceFactory legacyDataSourceFactory = new LegacyDataSourceFactory(properties);
+ final DataSource legacyDataSource = legacyDataSourceFactory.getDataSource();
+ final DataSource primaryDataSource = flyway.getDataSource();
+ migrateData(legacyDataSource, primaryDataSource);
+ }
+ }
+
+ /**
+ * Determines if the database represented by this data source is being initialized for the first time based on
+ * whether or not the table named 'BUCKET' or 'bucket' already exists.
+ *
+ * @param dataSource the data source
+ * @return true if the database has never been initialized before, false otherwise
+ */
+ private boolean isNewDatabase(final DataSource dataSource) {
+ try (final Connection connection = dataSource.getConnection();
+ final ResultSet rsUpper = connection.getMetaData().getTables(null, null, "BUCKET", null);
+ final ResultSet rsLower = connection.getMetaData().getTables(null, null, "bucket", null)) {
+ return !rsUpper.next() && !rsLower.next();
+ } catch (SQLException e) {
+ LOGGER.error(e.getMessage(), e);
+ throw new FlywayException("Unable to obtain connection from Flyway DataSource", e);
+ }
+ }
+
+ /**
+ * Transfers all data from the source to the destination.
+ *
+ * @param source the legacy H2 DataSource
+ * @param dest the new destination DataSource
+ */
+ private void migrateData(final DataSource source, final DataSource dest) {
+ final LegacyDatabaseService legacyDatabaseService = new LegacyDatabaseService(source);
+
+ final JdbcTemplate destJdbcTemplate = new JdbcTemplate(dest);
+ final MetadataService destMetadataService = new DatabaseMetadataService(destJdbcTemplate);
+
+ LOGGER.info("Migrating data from legacy database to new new database...");
+
+ // Migrate buckets
+ final List<BucketEntityV1> sourceBuckets = legacyDatabaseService.getAllBuckets();
+ LOGGER.info("Migrating {} buckets..", new Object[]{sourceBuckets.size()});
+
+ sourceBuckets.stream()
+ .map(b -> LegacyEntityMapper.createBucketEntity(b))
+ .forEach(b -> destMetadataService.createBucket(b));
+
+ // Migrate flows
+ final List<FlowEntityV1> sourceFlows = legacyDatabaseService.getAllFlows();
+ LOGGER.info("Migrating {} flows..", new Object[]{sourceFlows.size()});
+
+ sourceFlows.stream()
+ .map(f -> LegacyEntityMapper.createFlowEntity(f))
+ .forEach(f -> destMetadataService.createFlow(f));
+
+ // Migrate flow snapshots
+ final List<FlowSnapshotEntityV1> sourceSnapshots = legacyDatabaseService.getAllFlowSnapshots();
+ LOGGER.info("Migrating {} flow snapshots..", new Object[]{sourceSnapshots.size()});
+
+ sourceSnapshots.stream()
+ .map(fs -> LegacyEntityMapper.createFlowSnapshotEntity(fs))
+ .forEach(fs -> destMetadataService.createFlowSnapshot(fs));
+
+ LOGGER.info("Data migration complete!");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DataSourceFactory.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DataSourceFactory.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DataSourceFactory.java
new file mode 100644
index 0000000..29c132e
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DataSourceFactory.java
@@ -0,0 +1,97 @@
+/*
+ * 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.db;
+
+import com.zaxxer.hikari.HikariDataSource;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+
+/**
+ * Overriding Spring Boot's normal automatic creation of a DataSource in order to use the properties
+ * from NiFiRegistryProperties rather than the standard application.properties/yaml.
+ */
+@Configuration
+public class DataSourceFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceFactory.class);
+
+ private final NiFiRegistryProperties properties;
+
+ private DataSource dataSource;
+
+ @Autowired
+ public DataSourceFactory(final NiFiRegistryProperties properties) {
+ this.properties = properties;
+ }
+
+ @Bean
+ @Primary
+ public DataSource getDataSource() {
+ if (dataSource == null) {
+ dataSource = createDataSource();
+ }
+
+ return dataSource;
+ }
+
+ private DataSource createDataSource() {
+ final String databaseUrl = properties.getDatabaseUrl();
+ if (StringUtils.isBlank(databaseUrl)) {
+ throw new IllegalStateException(NiFiRegistryProperties.DATABASE_URL + " is required");
+ }
+
+ final String databaseDriver = properties.getDatabaseDriverClassName();
+ if (StringUtils.isBlank(databaseDriver)) {
+ throw new IllegalStateException(NiFiRegistryProperties.DATABASE_DRIVER_CLASS_NAME + " is required");
+ }
+
+ final String databaseUsername = properties.getDatabaseUsername();
+ if (StringUtils.isBlank(databaseUsername)) {
+ throw new IllegalStateException(NiFiRegistryProperties.DATABASE_USERNAME + " is required");
+ }
+
+ String databasePassword = properties.getDatabasePassword();
+ if (StringUtils.isBlank(databasePassword)) {
+ throw new IllegalStateException(NiFiRegistryProperties.DATABASE_PASSWORD + " is required");
+ }
+
+ final DataSource dataSource = DataSourceBuilder
+ .create()
+ .url(databaseUrl)
+ .driverClassName(databaseDriver)
+ .username(databaseUsername)
+ .password(databasePassword)
+ .build();
+
+ if (dataSource instanceof HikariDataSource) {
+ LOGGER.info("Setting maximum pool size on HikariDataSource to {}", new Object[]{properties.getDatabaseMaxConnections()});
+ ((HikariDataSource)dataSource).setMaximumPoolSize(properties.getDatabaseMaxConnections());
+ }
+
+ return dataSource;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseKeyService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseKeyService.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseKeyService.java
new file mode 100644
index 0000000..1d4f721
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseKeyService.java
@@ -0,0 +1,136 @@
+/*
+ * 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.db;
+
+import org.apache.nifi.registry.db.entity.KeyEntity;
+import org.apache.nifi.registry.db.mapper.KeyEntityRowMapper;
+import org.apache.nifi.registry.security.key.Key;
+import org.apache.nifi.registry.security.key.KeyService;
+import org.apache.nifi.registry.service.DataModelMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+@Service
+public class DatabaseKeyService implements KeyService {
+
+ private static final Logger logger = LoggerFactory.getLogger(DatabaseKeyService.class);
+
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock readLock = lock.readLock();
+ private final Lock writeLock = lock.writeLock();
+
+ private JdbcTemplate jdbcTemplate;
+
+ @Autowired
+ public DatabaseKeyService(final JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @Override
+ public Key getKey(String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("Id cannot be null");
+ }
+
+ Key key = null;
+ readLock.lock();
+ try {
+ final String sql = "SELECT * FROM signing_key WHERE id = ?";
+
+ KeyEntity keyEntity;
+ try {
+ keyEntity = jdbcTemplate.queryForObject(sql, new KeyEntityRowMapper(), id);
+ } catch (EmptyResultDataAccessException e) {
+ keyEntity = null;
+ }
+
+ if (keyEntity != null) {
+ key = DataModelMapper.map(keyEntity);
+ } else {
+ logger.debug("No signing key found with id='" + id + "'");
+ }
+ } finally {
+ readLock.unlock();
+ }
+ return key;
+ }
+
+ @Override
+ public Key getOrCreateKey(String tenantIdentity) {
+ if (tenantIdentity == null) {
+ throw new IllegalArgumentException("Identity cannot be null");
+ }
+
+ Key key;
+ writeLock.lock();
+ try {
+ final String selectSql = "SELECT * FROM signing_key WHERE tenant_identity = ?";
+
+ KeyEntity existingKeyEntity;
+ try {
+ existingKeyEntity = jdbcTemplate.queryForObject(selectSql, new KeyEntityRowMapper(), tenantIdentity);
+ } catch (EmptyResultDataAccessException e) {
+ existingKeyEntity = null;
+ }
+
+ if (existingKeyEntity == null) {
+ logger.debug("No key found with identity='" + tenantIdentity + "'. Creating new key.");
+
+ final KeyEntity newKeyEntity = new KeyEntity();
+ newKeyEntity.setId(UUID.randomUUID().toString());
+ newKeyEntity.setTenantIdentity(tenantIdentity);
+ newKeyEntity.setKeyValue(UUID.randomUUID().toString());
+
+ final String insertSql = "INSERT INTO signing_key (ID, TENANT_IDENTITY, KEY_VALUE) VALUES (?, ?, ?)";
+ jdbcTemplate.update(insertSql, newKeyEntity.getId(), newKeyEntity.getTenantIdentity(), newKeyEntity.getKeyValue());
+
+ key = DataModelMapper.map(newKeyEntity);
+ } else {
+ key = DataModelMapper.map(existingKeyEntity);
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ return key;
+ }
+
+ @Override
+ public void deleteKey(String tenantIdentity) {
+ if (tenantIdentity == null) {
+ throw new IllegalArgumentException("Identity cannot be null");
+ }
+
+ writeLock.lock();
+ try {
+ logger.debug("Deleting key with identity='" + tenantIdentity + "'.");
+ final String deleteSql = "DELETE FROM signing_key WHERE tenant_identity = ?";
+ jdbcTemplate.update(deleteSql, tenantIdentity);
+ } finally {
+ writeLock.unlock();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
new file mode 100644
index 0000000..4d32790
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
@@ -0,0 +1,441 @@
+/*
+ * 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.db;
+
+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.db.mapper.BucketEntityRowMapper;
+import org.apache.nifi.registry.db.mapper.BucketItemEntityRowMapper;
+import org.apache.nifi.registry.db.mapper.FlowEntityRowMapper;
+import org.apache.nifi.registry.db.mapper.FlowSnapshotEntityRowMapper;
+import org.apache.nifi.registry.service.MetadataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@Repository
+public class DatabaseMetadataService implements MetadataService {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ @Autowired
+ public DatabaseMetadataService(final JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ //----------------- Buckets ---------------------------------
+
+ @Override
+ public BucketEntity createBucket(final BucketEntity b) {
+ final String sql = "INSERT INTO bucket (ID, NAME, DESCRIPTION, CREATED) VALUES (?, ?, ?, ?)";
+ jdbcTemplate.update(sql, b.getId(), b.getName(), b.getDescription(), b.getCreated());
+ return b;
+ }
+
+ @Override
+ public BucketEntity getBucketById(final String bucketIdentifier) {
+ final String sql = "SELECT * FROM bucket WHERE id = ?";
+ try {
+ return jdbcTemplate.queryForObject(sql, new BucketEntityRowMapper(), bucketIdentifier);
+ } catch (EmptyResultDataAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public List<BucketEntity> getBucketsByName(final String name) {
+ final String sql = "SELECT * FROM bucket WHERE name = ? ORDER BY name ASC";
+ return jdbcTemplate.query(sql, new Object[] {name} , new BucketEntityRowMapper());
+ }
+
+ @Override
+ public BucketEntity updateBucket(final BucketEntity bucket) {
+ final String sql = "UPDATE bucket SET name = ?, description = ? WHERE id = ?";
+ jdbcTemplate.update(sql, bucket.getName(), bucket.getDescription(), bucket.getId());
+ return bucket;
+ }
+
+ @Override
+ public void deleteBucket(final BucketEntity bucket) {
+ final String snapshotDeleteSql = "DELETE FROM flow_snapshot WHERE flow_id IN ( " +
+ "SELECT f.id FROM flow f, bucket_item item WHERE f.id = item.id AND item.bucket_id = ?" +
+ ")";
+ jdbcTemplate.update(snapshotDeleteSql, bucket.getId());
+
+ final String flowDeleteSql = "DELETE FROM flow WHERE id IN ( " +
+ "SELECT f.id FROM flow f, bucket_item item WHERE f.id = item.id AND item.bucket_id = ?" +
+ ")";
+ jdbcTemplate.update(flowDeleteSql, bucket.getId());
+
+ final String itemDeleteSql = "DELETE FROM bucket_item WHERE bucket_id = ?";
+ jdbcTemplate.update(itemDeleteSql, bucket.getId());
+
+ final String sql = "DELETE FROM bucket WHERE id = ?";
+ jdbcTemplate.update(sql, bucket.getId());
+ }
+
+ @Override
+ public List<BucketEntity> getBuckets(final Set<String> bucketIds) {
+ if (bucketIds == null || bucketIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM bucket WHERE id IN (");
+ for (int i=0; i < bucketIds.size(); i++) {
+ if (i > 0) {
+ sqlBuilder.append(", ");
+ }
+ sqlBuilder.append("?");
+ }
+ sqlBuilder.append(") ");
+ sqlBuilder.append("ORDER BY name ASC");
+
+ return jdbcTemplate.query(sqlBuilder.toString(), bucketIds.toArray(), new BucketEntityRowMapper());
+ }
+
+ @Override
+ public List<BucketEntity> getAllBuckets() {
+ final String sql = "SELECT * FROM bucket ORDER BY name ASC";
+ return jdbcTemplate.query(sql, new BucketEntityRowMapper());
+ }
+
+ //----------------- BucketItems ---------------------------------
+
+ @Override
+ public List<BucketItemEntity> getBucketItems(final String bucketIdentifier) {
+ final String sql =
+ "SELECT " +
+ "item.id as ID, " +
+ "item.name as NAME, " +
+ "item.description as DESCRIPTION, " +
+ "item.created as CREATED, " +
+ "item.modified as MODIFIED, " +
+ "item.item_type as ITEM_TYPE, " +
+ "b.id as BUCKET_ID, " +
+ "b.name as BUCKET_NAME " +
+ "FROM " +
+ "bucket_item item, bucket b " +
+ "WHERE " +
+ "item.bucket_id = b.id " +
+ "AND " +
+ "item.bucket_id = ?";
+
+ final List<BucketItemEntity> items = jdbcTemplate.query(sql, new Object[] { bucketIdentifier }, new BucketItemEntityRowMapper());
+ return getItemsWithCounts(items);
+ }
+
+ @Override
+ public List<BucketItemEntity> getBucketItems(final Set<String> bucketIds) {
+ if (bucketIds == null || bucketIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final StringBuilder sqlBuilder = new StringBuilder(
+ "SELECT " +
+ "item.id as ID, " +
+ "item.name as NAME, " +
+ "item.description as DESCRIPTION, " +
+ "item.created as CREATED, " +
+ "item.modified as MODIFIED, " +
+ "item.item_type as ITEM_TYPE, " +
+ "b.id as BUCKET_ID, " +
+ "b.name as BUCKET_NAME " +
+ "FROM " +
+ "bucket_item item, bucket b " +
+ "WHERE " +
+ "item.bucket_id = b.id " +
+ "AND " +
+ "item.bucket_id IN (");
+
+ for (int i=0; i < bucketIds.size(); i++) {
+ if (i > 0) {
+ sqlBuilder.append(", ");
+ }
+ sqlBuilder.append("?");
+ }
+ sqlBuilder.append(")");
+
+ final List<BucketItemEntity> items = jdbcTemplate.query(sqlBuilder.toString(), bucketIds.toArray(), new BucketItemEntityRowMapper());
+ return getItemsWithCounts(items);
+ }
+
+ private List<BucketItemEntity> getItemsWithCounts(final Iterable<BucketItemEntity> items) {
+ final Map<String,Long> snapshotCounts = getFlowSnapshotCounts();
+
+ final List<BucketItemEntity> itemWithCounts = new ArrayList<>();
+ for (final BucketItemEntity item : items) {
+ if (item.getType() == BucketItemEntityType.FLOW) {
+ final Long snapshotCount = snapshotCounts.get(item.getId());
+ if (snapshotCount != null) {
+ final FlowEntity flowEntity = (FlowEntity) item;
+ flowEntity.setSnapshotCount(snapshotCount);
+ }
+ }
+
+ itemWithCounts.add(item);
+ }
+
+ return itemWithCounts;
+ }
+
+ private Map<String,Long> getFlowSnapshotCounts() {
+ final String sql = "SELECT flow_id, count(*) FROM flow_snapshot GROUP BY flow_id";
+
+ final Map<String,Long> results = new HashMap<>();
+ jdbcTemplate.query(sql, (rs) -> {
+ results.put(rs.getString(1), rs.getLong(2));
+ });
+ return results;
+ }
+
+ private Long getFlowSnapshotCount(final String flowIdentifier) {
+ final String sql = "SELECT count(*) FROM flow_snapshot WHERE flow_id = ?";
+
+ return jdbcTemplate.queryForObject(sql, new Object[] {flowIdentifier}, (rs, num) -> {
+ return rs.getLong(1);
+ });
+ }
+
+ //----------------- Flows ---------------------------------
+
+ @Override
+ public FlowEntity createFlow(final FlowEntity flow) {
+ final String itemSql = "INSERT INTO bucket_item (ID, NAME, DESCRIPTION, CREATED, MODIFIED, ITEM_TYPE, BUCKET_ID) VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+ jdbcTemplate.update(itemSql,
+ flow.getId(),
+ flow.getName(),
+ flow.getDescription(),
+ flow.getCreated(),
+ flow.getModified(),
+ flow.getType().toString(),
+ flow.getBucketId());
+
+ final String flowSql = "INSERT INTO flow (ID) VALUES (?)";
+
+ jdbcTemplate.update(flowSql, flow.getId());
+
+ return flow;
+ }
+
+ @Override
+ public FlowEntity getFlowById(final String flowIdentifier) {
+ final String sql = "SELECT * FROM flow f, bucket_item item WHERE f.id = ? AND item.id = f.id";
+ try {
+ return jdbcTemplate.queryForObject(sql, new FlowEntityRowMapper(), flowIdentifier);
+ } catch (EmptyResultDataAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public FlowEntity getFlowByIdWithSnapshotCounts(final String flowIdentifier) {
+ final FlowEntity flowEntity = getFlowById(flowIdentifier);
+ if (flowEntity == null) {
+ return flowEntity;
+ }
+
+ final Long snapshotCount = getFlowSnapshotCount(flowIdentifier);
+ if (snapshotCount != null) {
+ flowEntity.setSnapshotCount(snapshotCount);
+ }
+
+ return flowEntity;
+ }
+
+ @Override
+ public List<FlowEntity> getFlowsByName(final String name) {
+ final String sql = "SELECT * FROM flow f, bucket_item item WHERE item.name = ? AND item.id = f.id";
+ return jdbcTemplate.query(sql, new Object[] {name}, new FlowEntityRowMapper());
+ }
+
+ @Override
+ public List<FlowEntity> getFlowsByName(final String bucketIdentifier, final String name) {
+ final String sql = "SELECT * FROM flow f, bucket_item item WHERE item.name = ? AND item.id = f.id AND item.bucket_id = ?";
+ return jdbcTemplate.query(sql, new Object[] {name, bucketIdentifier}, new FlowEntityRowMapper());
+ }
+
+ @Override
+ public List<FlowEntity> getFlowsByBucket(final String bucketIdentifier) {
+ final String sql = "SELECT * FROM flow f, bucket_item item WHERE item.bucket_id = ? AND item.id = f.id";
+ final List<FlowEntity> flows = jdbcTemplate.query(sql, new Object[] {bucketIdentifier}, new FlowEntityRowMapper());
+
+ final Map<String,Long> snapshotCounts = getFlowSnapshotCounts();
+ for (final FlowEntity flowEntity : flows) {
+ final Long snapshotCount = snapshotCounts.get(flowEntity.getId());
+ if (snapshotCount != null) {
+ flowEntity.setSnapshotCount(snapshotCount);
+ }
+ }
+
+ return flows;
+ }
+
+ @Override
+ public FlowEntity updateFlow(final FlowEntity flow) {
+ flow.setModified(new Date());
+
+ final String sql = "UPDATE bucket_item SET name = ?, description = ?, modified = ? WHERE id = ?";
+ jdbcTemplate.update(sql, flow.getName(), flow.getDescription(), flow.getModified(), flow.getId());
+ return flow;
+ }
+
+ @Override
+ public void deleteFlow(final FlowEntity flow) {
+ final String snapshotDeleteSql = "DELETE FROM flow_snapshot WHERE flow_id = ?";
+ jdbcTemplate.update(snapshotDeleteSql, flow.getId());
+
+ final String flowDeleteSql = "DELETE FROM flow WHERE id = ?";
+ jdbcTemplate.update(flowDeleteSql, flow.getId());
+
+ final String itemDeleteSql = "DELETE FROM bucket_item WHERE id = ?";
+ jdbcTemplate.update(itemDeleteSql, flow.getId());
+ }
+
+ //----------------- Flow Snapshots ---------------------------------
+
+ @Override
+ public FlowSnapshotEntity createFlowSnapshot(final FlowSnapshotEntity flowSnapshot) {
+ final String sql = "INSERT INTO flow_snapshot (FLOW_ID, VERSION, CREATED, CREATED_BY, COMMENTS) VALUES (?, ?, ?, ?, ?)";
+
+ jdbcTemplate.update(sql,
+ flowSnapshot.getFlowId(),
+ flowSnapshot.getVersion(),
+ flowSnapshot.getCreated(),
+ flowSnapshot.getCreatedBy(),
+ flowSnapshot.getComments());
+
+ return flowSnapshot;
+ }
+
+ @Override
+ public FlowSnapshotEntity getFlowSnapshot(final String flowIdentifier, final Integer version) {
+ final String sql =
+ "SELECT " +
+ "fs.flow_id, " +
+ "fs.version, " +
+ "fs.created, " +
+ "fs.created_by, " +
+ "fs.comments " +
+ "FROM " +
+ "flow_snapshot fs, " +
+ "flow f, " +
+ "bucket_item item " +
+ "WHERE " +
+ "item.id = f.id AND " +
+ "f.id = ? AND " +
+ "f.id = fs.flow_id AND " +
+ "fs.version = ?";
+
+ try {
+ return jdbcTemplate.queryForObject(sql, new FlowSnapshotEntityRowMapper(),
+ flowIdentifier, version);
+ } catch (EmptyResultDataAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public FlowSnapshotEntity getLatestSnapshot(final String flowIdentifier) {
+ final String sql = "SELECT * FROM flow_snapshot WHERE flow_id = ? ORDER BY version DESC LIMIT 1";
+
+ try {
+ return jdbcTemplate.queryForObject(sql, new FlowSnapshotEntityRowMapper(), flowIdentifier);
+ } catch (EmptyResultDataAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public List<FlowSnapshotEntity> getSnapshots(final String flowIdentifier) {
+ final String sql =
+ "SELECT " +
+ "fs.flow_id, " +
+ "fs.version, " +
+ "fs.created, " +
+ "fs.created_by, " +
+ "fs.comments " +
+ "FROM " +
+ "flow_snapshot fs, " +
+ "flow f, " +
+ "bucket_item item " +
+ "WHERE " +
+ "item.id = f.id AND " +
+ "f.id = ? AND " +
+ "f.id = fs.flow_id";
+
+ final Object[] args = new Object[] { flowIdentifier };
+ return jdbcTemplate.query(sql, args, new FlowSnapshotEntityRowMapper());
+ }
+
+ @Override
+ public void deleteFlowSnapshot(final FlowSnapshotEntity flowSnapshot) {
+ final String sql = "DELETE FROM flow_snapshot WHERE flow_id = ? AND version = ?";
+ jdbcTemplate.update(sql, flowSnapshot.getFlowId(), flowSnapshot.getVersion());
+ }
+
+ //----------------- BucketItems ---------------------------------
+
+ @Override
+ public Set<String> getBucketFields() {
+ final Set<String> fields = new LinkedHashSet<>();
+ fields.add("ID");
+ fields.add("NAME");
+ fields.add("DESCRIPTION");
+ fields.add("CREATED");
+ return fields;
+ }
+
+ @Override
+ public Set<String> getBucketItemFields() {
+ final Set<String> fields = new LinkedHashSet<>();
+ fields.add("ID");
+ fields.add("NAME");
+ fields.add("DESCRIPTION");
+ fields.add("CREATED");
+ fields.add("MODIFIED");
+ fields.add("ITEM_TYPE");
+ fields.add("BUCKET_ID");
+ return fields;
+ }
+
+ @Override
+ public Set<String> getFlowFields() {
+ final Set<String> fields = new LinkedHashSet<>();
+ fields.add("ID");
+ fields.add("NAME");
+ fields.add("DESCRIPTION");
+ fields.add("CREATED");
+ fields.add("MODIFIED");
+ fields.add("ITEM_TYPE");
+ fields.add("BUCKET_ID");
+ return fields;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketEntity.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketEntity.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketEntity.java
new file mode 100644
index 0000000..71d5a92
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketEntity.java
@@ -0,0 +1,83 @@
+/*
+ * 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.db.entity;
+
+import java.util.Date;
+import java.util.Objects;
+
+public class BucketEntity {
+
+ private String id;
+
+ private String name;
+
+ private String description;
+
+ private Date created;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.id);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final BucketEntity other = (BucketEntity) obj;
+ return Objects.equals(this.id, other.id);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntity.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntity.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntity.java
new file mode 100644
index 0000000..cdfa963
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntity.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.db.entity;
+
+import java.util.Date;
+import java.util.Objects;
+
+public class BucketItemEntity {
+
+ private String id;
+
+ private String name;
+
+ private String description;
+
+ private Date created;
+
+ private Date modified;
+
+ // NOTE: sub-classes should ensure that the type is set appropriately by overriding the getter/setter
+ private BucketItemEntityType type;
+
+ private String bucketId;
+
+ private String bucketName;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getModified() {
+ return modified;
+ }
+
+ public void setModified(Date modified) {
+ this.modified = modified;
+ }
+
+ public BucketItemEntityType getType() {
+ return type;
+ }
+
+ public void setType(BucketItemEntityType type) {
+ this.type = type;
+ }
+
+ public String getBucketId() {
+ return bucketId;
+ }
+
+ public void setBucketId(String bucketId) {
+ this.bucketId = bucketId;
+ }
+
+ public String getBucketName() {
+ return bucketName;
+ }
+
+ public void setBucketName(String bucketName) {
+ this.bucketName = bucketName;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.id);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final BucketItemEntity other = (BucketItemEntity) obj;
+ return Objects.equals(this.id, other.id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntityType.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntityType.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntityType.java
new file mode 100644
index 0000000..e78b2b1
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/BucketItemEntityType.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.db.entity;
+
+/**
+ * Possible types of BucketItemEntity.
+ */
+public enum BucketItemEntityType {
+
+ FLOW(Values.FLOW);
+
+ private final String value;
+
+ BucketItemEntityType(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ // need these constants to reference from @DiscriminatorValue
+ public static class Values {
+ public static final String FLOW = "FLOW";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowEntity.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowEntity.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowEntity.java
new file mode 100644
index 0000000..b978168
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowEntity.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.db.entity;
+
+public class FlowEntity extends BucketItemEntity {
+
+ private long snapshotCount;
+
+ public FlowEntity() {
+ setType(BucketItemEntityType.FLOW);
+ }
+
+ public long getSnapshotCount() {
+ return snapshotCount;
+ }
+
+ public void setSnapshotCount(long snapshotCount) {
+ this.snapshotCount = snapshotCount;
+ }
+
+ @Override
+ public void setType(BucketItemEntityType type) {
+ if (BucketItemEntityType.FLOW != type) {
+ throw new IllegalStateException("Must set type to FLOW");
+ }
+ super.setType(type);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowSnapshotEntity.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowSnapshotEntity.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowSnapshotEntity.java
new file mode 100644
index 0000000..3143a6e
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/FlowSnapshotEntity.java
@@ -0,0 +1,93 @@
+/*
+ * 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.db.entity;
+
+import java.util.Date;
+import java.util.Objects;
+
+public class FlowSnapshotEntity {
+
+ private String flowId;
+
+ private Integer version;
+
+ private Date created;
+
+ private String createdBy;
+
+ private String comments;
+
+ public String getFlowId() {
+ return flowId;
+ }
+
+ public void setFlowId(String flowId) {
+ this.flowId = flowId;
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public String getComments() {
+ return comments;
+ }
+
+ public void setComments(String comments) {
+ this.comments = comments;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.flowId, this.version);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (!(obj instanceof FlowSnapshotEntity)) {
+ return false;
+ }
+
+ final FlowSnapshotEntity other = (FlowSnapshotEntity) obj;
+ return Objects.equals(this.flowId, other.flowId) && Objects.equals(this.version, other.version);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/KeyEntity.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/KeyEntity.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/KeyEntity.java
new file mode 100644
index 0000000..494867f
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/entity/KeyEntity.java
@@ -0,0 +1,51 @@
+/*
+ * 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.db.entity;
+
+public class KeyEntity {
+
+ private String id;
+
+ private String tenantIdentity;
+
+ private String keyValue;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTenantIdentity() {
+ return tenantIdentity;
+ }
+
+ public void setTenantIdentity(String tenantIdentity) {
+ this.tenantIdentity = tenantIdentity;
+ }
+
+ public String getKeyValue() {
+ return keyValue;
+ }
+
+ public void setKeyValue(String keyValue) {
+ this.keyValue = keyValue;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketEntityRowMapper.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketEntityRowMapper.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketEntityRowMapper.java
new file mode 100644
index 0000000..6c5bc2e
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketEntityRowMapper.java
@@ -0,0 +1,39 @@
+/*
+ * 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.db.mapper;
+
+import org.apache.nifi.registry.db.entity.BucketEntity;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.lang.Nullable;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class BucketEntityRowMapper implements RowMapper<BucketEntity> {
+
+ @Nullable
+ @Override
+ public BucketEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+ final BucketEntity b = new BucketEntity();
+ b.setId(rs.getString("ID"));
+ b.setName(rs.getString("NAME"));
+ b.setDescription(rs.getString("DESCRIPTION"));
+ b.setCreated(rs.getTimestamp("CREATED"));
+ return b;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketItemEntityRowMapper.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketItemEntityRowMapper.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketItemEntityRowMapper.java
new file mode 100644
index 0000000..7b3df05
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/BucketItemEntityRowMapper.java
@@ -0,0 +1,58 @@
+/*
+ * 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.db.mapper;
+
+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.springframework.jdbc.core.RowMapper;
+import org.springframework.lang.Nullable;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class BucketItemEntityRowMapper implements RowMapper<BucketItemEntity> {
+
+ @Nullable
+ @Override
+ public BucketItemEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+ final BucketItemEntityType type = BucketItemEntityType.valueOf(rs.getString("ITEM_TYPE"));
+
+ // Create the appropriate type of sub-class, eventually populate specific data for each type
+ final BucketItemEntity item;
+ switch (type) {
+ case FLOW:
+ item = new FlowEntity();
+ break;
+ default:
+ // should never happen
+ item = new BucketItemEntity();
+ break;
+ }
+
+ // populate fields common to all bucket items
+ item.setId(rs.getString("ID"));
+ item.setName(rs.getString("NAME"));
+ item.setDescription(rs.getString("DESCRIPTION"));
+ item.setCreated(rs.getTimestamp("CREATED"));
+ item.setModified(rs.getTimestamp("MODIFIED"));
+ item.setBucketId(rs.getString("BUCKET_ID"));
+ item.setBucketName(rs.getString("BUCKET_NAME"));
+ item.setType(type);
+ return item;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowEntityRowMapper.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowEntityRowMapper.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowEntityRowMapper.java
new file mode 100644
index 0000000..acaf343
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowEntityRowMapper.java
@@ -0,0 +1,43 @@
+/*
+ * 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.db.mapper;
+
+import org.apache.nifi.registry.db.entity.BucketItemEntityType;
+import org.apache.nifi.registry.db.entity.FlowEntity;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.lang.Nullable;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class FlowEntityRowMapper implements RowMapper<FlowEntity> {
+
+ @Nullable
+ @Override
+ public FlowEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+ final FlowEntity flowEntity = new FlowEntity();
+ flowEntity.setId(rs.getString("ID"));
+ flowEntity.setName(rs.getString("NAME"));
+ flowEntity.setDescription(rs.getString("DESCRIPTION"));
+ flowEntity.setCreated(rs.getTimestamp("CREATED"));
+ flowEntity.setModified(rs.getTimestamp("MODIFIED"));
+ flowEntity.setBucketId(rs.getString("BUCKET_ID"));
+ flowEntity.setType(BucketItemEntityType.FLOW);
+ return flowEntity;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowSnapshotEntityRowMapper.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowSnapshotEntityRowMapper.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowSnapshotEntityRowMapper.java
new file mode 100644
index 0000000..07a59b3
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/FlowSnapshotEntityRowMapper.java
@@ -0,0 +1,39 @@
+/*
+ * 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.db.mapper;
+
+import org.apache.nifi.registry.db.entity.FlowSnapshotEntity;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.lang.Nullable;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class FlowSnapshotEntityRowMapper implements RowMapper<FlowSnapshotEntity> {
+
+ @Nullable
+ @Override
+ public FlowSnapshotEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+ final FlowSnapshotEntity entity = new FlowSnapshotEntity();
+ entity.setFlowId(rs.getString("FLOW_ID"));
+ entity.setVersion(rs.getInt("VERSION"));
+ entity.setCreated(rs.getTimestamp("CREATED"));
+ entity.setCreatedBy(rs.getString("CREATED_BY"));
+ entity.setComments(rs.getString("COMMENTS"));
+ return entity;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/KeyEntityRowMapper.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/KeyEntityRowMapper.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/KeyEntityRowMapper.java
new file mode 100644
index 0000000..6e190a5
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/mapper/KeyEntityRowMapper.java
@@ -0,0 +1,37 @@
+/*
+ * 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.db.mapper;
+
+import org.apache.nifi.registry.db.entity.KeyEntity;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.lang.Nullable;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class KeyEntityRowMapper implements RowMapper<KeyEntity> {
+
+ @Nullable
+ @Override
+ public KeyEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+ final KeyEntity keyEntity = new KeyEntity();
+ keyEntity.setId(rs.getString("ID"));
+ keyEntity.setTenantIdentity(rs.getString("TENANT_IDENTITY"));
+ keyEntity.setKeyValue(rs.getString("KEY_VALUE"));
+ return keyEntity;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/BucketEntityV1.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/BucketEntityV1.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/BucketEntityV1.java
new file mode 100644
index 0000000..94000a5
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/BucketEntityV1.java
@@ -0,0 +1,86 @@
+/*
+ * 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.db.migration;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * Bucket DB entity from the original database schema in 0.1.0, used for migration purposes.
+ */
+public class BucketEntityV1 {
+
+ private String id;
+
+ private String name;
+
+ private String description;
+
+ private Date created;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.id);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final BucketEntityV1 other = (BucketEntityV1) obj;
+ return Objects.equals(this.id, other.id);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/FlowEntityV1.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/FlowEntityV1.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/FlowEntityV1.java
new file mode 100644
index 0000000..961c3bd
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/migration/FlowEntityV1.java
@@ -0,0 +1,106 @@
+/*
+ * 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.db.migration;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * Flow DB entity from the original database schema in 0.1.0, used for migration purposes.
+ */
+public class FlowEntityV1 {
+
+ private String id;
+
+ private String name;
+
+ private String description;
+
+ private Date created;
+
+ private Date modified;
+
+ private String bucketId;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getModified() {
+ return modified;
+ }
+
+ public void setModified(Date modified) {
+ this.modified = modified;
+ }
+
+ public String getBucketId() {
+ return bucketId;
+ }
+
+ public void setBucketId(String bucketId) {
+ this.bucketId = bucketId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.id);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final FlowEntityV1 other = (FlowEntityV1) obj;
+ return Objects.equals(this.id, other.id);
+ }
+
+}