blob: d80485d353ce9b239008c397d060ce47f38fb60d [file] [log] [blame]
/*
* 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.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.ExtensionBundleEntity;
import org.apache.nifi.registry.db.entity.ExtensionBundleVersionDependencyEntity;
import org.apache.nifi.registry.db.entity.ExtensionBundleVersionEntity;
import org.apache.nifi.registry.db.entity.ExtensionEntity;
import org.apache.nifi.registry.db.entity.ExtensionEntityCategory;
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.ExtensionBundleEntityRowMapper;
import org.apache.nifi.registry.db.mapper.ExtensionBundleEntityWithBucketNameRowMapper;
import org.apache.nifi.registry.db.mapper.ExtensionBundleVersionDependencyEntityRowMapper;
import org.apache.nifi.registry.db.mapper.ExtensionBundleVersionEntityRowMapper;
import org.apache.nifi.registry.db.mapper.ExtensionEntityRowMapper;
import org.apache.nifi.registry.db.mapper.FlowEntityRowMapper;
import org.apache.nifi.registry.db.mapper.FlowSnapshotEntityRowMapper;
import org.apache.nifi.registry.extension.filter.ExtensionBundleFilterParams;
import org.apache.nifi.registry.extension.filter.ExtensionBundleVersionFilterParams;
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.jdbc.core.RowCallbackHandler;
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, ALLOW_EXTENSION_BUNDLE_REDEPLOY) VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(sql,
b.getId(),
b.getName(),
b.getDescription(),
b.getCreated(),
b.isAllowExtensionBundleRedeploy() ? 1 : 0);
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 = ?, allow_extension_bundle_redeploy = ? WHERE id = ?";
jdbcTemplate.update(sql, bucket.getName(), bucket.getDescription(), bucket.isAllowExtensionBundleRedeploy() ? 1 : 0, bucket.getId());
return bucket;
}
@Override
public void deleteBucket(final BucketEntity bucket) {
// NOTE: Cascading deletes will delete from all child tables
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 ---------------------------------
private static final String BASE_BUCKET_ITEMS_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 ," +
"eb.bundle_type as BUNDLE_TYPE, " +
"eb.group_id as BUNDLE_GROUP_ID, " +
"eb.artifact_id as BUNDLE_ARTIFACT_ID " +
"FROM bucket_item item " +
"INNER JOIN bucket b ON item.bucket_id = b.id " +
"LEFT JOIN extension_bundle eb ON item.id = eb.id ";
@Override
public List<BucketItemEntity> getBucketItems(final String bucketIdentifier) {
final String sql = BASE_BUCKET_ITEMS_SQL + " WHERE 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(BASE_BUCKET_ITEMS_SQL + " WHERE 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 Map<String,Long> extensionBundleVersionCounts = getExtensionBundleVersionCounts();
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);
}
} else if (item.getType() == BucketItemEntityType.EXTENSION_BUNDLE) {
final Long versionCount = extensionBundleVersionCounts.get(item.getId());
if (versionCount != null) {
final ExtensionBundleEntity extensionBundleEntity = (ExtensionBundleEntity) item;
extensionBundleEntity.setVersionCount(versionCount);
}
}
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);
});
}
private Map<String,Long> getExtensionBundleVersionCounts() {
final String sql = "SELECT extension_bundle_id, count(*) FROM extension_bundle_version GROUP BY extension_bundle_id";
final Map<String,Long> results = new HashMap<>();
jdbcTemplate.query(sql, (rs) -> {
results.put(rs.getString(1), rs.getLong(2));
});
return results;
}
private Long getExtensionBundleVersionCount(final String extensionBundleIdentifier) {
final String sql = "SELECT count(*) FROM extension_bundle_version WHERE extension_bundle_id = ?";
return jdbcTemplate.queryForObject(sql, new Object[] {extensionBundleIdentifier}, (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) {
// NOTE: Cascading deletes will delete from child tables
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());
}
//----------------- Extension Bundles ---------------------------------
@Override
public ExtensionBundleEntity createExtensionBundle(final ExtensionBundleEntity extensionBundle) {
final String itemSql =
"INSERT INTO bucket_item (" +
"ID, " +
"NAME, " +
"DESCRIPTION, " +
"CREATED, " +
"MODIFIED, " +
"ITEM_TYPE, " +
"BUCKET_ID) " +
"VALUES (?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(itemSql,
extensionBundle.getId(),
extensionBundle.getName(),
extensionBundle.getDescription(),
extensionBundle.getCreated(),
extensionBundle.getModified(),
extensionBundle.getType().toString(),
extensionBundle.getBucketId());
final String bundleSql =
"INSERT INTO extension_bundle (" +
"ID, " +
"BUCKET_ID, " +
"BUNDLE_TYPE, " +
"GROUP_ID, " +
"ARTIFACT_ID) " +
"VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(bundleSql,
extensionBundle.getId(),
extensionBundle.getBucketId(),
extensionBundle.getBundleType().toString(),
extensionBundle.getGroupId(),
extensionBundle.getArtifactId());
return extensionBundle;
}
@Override
public ExtensionBundleEntity getExtensionBundle(final String extensionBundleId) {
final String sql =
"SELECT * " +
"FROM extension_bundle eb, bucket_item item " +
"WHERE eb.id = ? AND item.id = eb.id";
try {
final ExtensionBundleEntity entity = jdbcTemplate.queryForObject(sql, new ExtensionBundleEntityRowMapper(), extensionBundleId);
final Long versionCount = getExtensionBundleVersionCount(extensionBundleId);
if (versionCount != null) {
entity.setVersionCount(versionCount);
}
return entity;
} catch (EmptyResultDataAccessException e) {
return null;
}
}
@Override
public ExtensionBundleEntity getExtensionBundle(final String bucketId, final String groupId, final String artifactId) {
final String sql =
"SELECT * " +
"FROM " +
"extension_bundle eb, " +
"bucket_item item " +
"WHERE " +
"item.id = eb.id AND " +
"eb.bucket_id = ? AND " +
"eb.group_id = ? AND " +
"eb.artifact_id = ?";
try {
final ExtensionBundleEntity entity = jdbcTemplate.queryForObject(sql, new ExtensionBundleEntityRowMapper(), bucketId, groupId, artifactId);
final Long versionCount = getExtensionBundleVersionCount(entity.getId());
if (versionCount != null) {
entity.setVersionCount(versionCount);
}
return entity;
} catch (EmptyResultDataAccessException e) {
return null;
}
}
@Override
public List<ExtensionBundleEntity> getExtensionBundles(final Set<String> bucketIds, final ExtensionBundleFilterParams filterParams) {
if (bucketIds == null || bucketIds.isEmpty()) {
return Collections.emptyList();
}
final List<Object> args = new ArrayList<>();
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 ," +
"eb.bundle_type as BUNDLE_TYPE, " +
"eb.group_id as BUNDLE_GROUP_ID, " +
"eb.artifact_id as BUNDLE_ARTIFACT_ID " +
"FROM " +
"extension_bundle eb, " +
"bucket_item item, " +
"bucket b " +
"WHERE " +
"item.id = eb.id AND " +
"b.id = item.bucket_id");
if (filterParams != null) {
final String groupId = filterParams.getGroupId();
if (!StringUtils.isBlank(groupId)) {
sqlBuilder.append(" AND eb.group_id LIKE ? ");
args.add(groupId);
}
final String artifactId = filterParams.getArtifactId();
if (!StringUtils.isBlank(artifactId)) {
sqlBuilder.append(" AND eb.artifact_id LIKE ? ");
args.add(artifactId);
}
}
addBucketIdentifiersClause(sqlBuilder, "item.bucket_id", bucketIds);
sqlBuilder.append("ORDER BY eb.group_id ASC, eb.artifact_id ASC");
args.addAll(bucketIds);
final List<ExtensionBundleEntity> bundleEntities = jdbcTemplate.query(sqlBuilder.toString(), args.toArray(), new ExtensionBundleEntityWithBucketNameRowMapper());
return populateVersionCounts(bundleEntities);
}
@Override
public List<ExtensionBundleEntity> getExtensionBundlesByBucket(final String bucketId) {
final String sql =
"SELECT * " +
"FROM " +
"extension_bundle eb, " +
"bucket_item item " +
"WHERE " +
"item.id = eb.id AND " +
"item.bucket_id = ? " +
"ORDER BY eb.group_id ASC, eb.artifact_id ASC";
final List<ExtensionBundleEntity> bundles = jdbcTemplate.query(sql, new Object[]{bucketId}, new ExtensionBundleEntityRowMapper());
return populateVersionCounts(bundles);
}
@Override
public List<ExtensionBundleEntity> getExtensionBundlesByBucketAndGroup(String bucketId, String groupId) {
final String sql =
"SELECT * " +
"FROM " +
"extension_bundle eb, " +
"bucket_item item " +
"WHERE " +
"item.id = eb.id AND " +
"item.bucket_id = ? AND " +
"eb.group_id = ?" +
"ORDER BY eb.group_id ASC, eb.artifact_id ASC";
final List<ExtensionBundleEntity> bundles = jdbcTemplate.query(sql, new Object[]{bucketId, groupId}, new ExtensionBundleEntityRowMapper());
return populateVersionCounts(bundles);
}
private List<ExtensionBundleEntity> populateVersionCounts(final List<ExtensionBundleEntity> bundles) {
if (!bundles.isEmpty()) {
final Map<String, Long> versionCounts = getExtensionBundleVersionCounts();
for (final ExtensionBundleEntity entity : bundles) {
final Long versionCount = versionCounts.get(entity.getId());
if (versionCount != null) {
entity.setVersionCount(versionCount);
}
}
}
return bundles;
}
@Override
public void deleteExtensionBundle(final ExtensionBundleEntity extensionBundle) {
deleteExtensionBundle(extensionBundle.getId());
}
@Override
public void deleteExtensionBundle(final String extensionBundleId) {
// NOTE: All of the foreign key constraints for extension related tables are set to cascade on delete
final String itemDeleteSql = "DELETE FROM bucket_item WHERE id = ?";
jdbcTemplate.update(itemDeleteSql, extensionBundleId);
}
//----------------- Extension Bundle Versions ---------------------------------
@Override
public ExtensionBundleVersionEntity createExtensionBundleVersion(final ExtensionBundleVersionEntity extensionBundleVersion) {
final String sql =
"INSERT INTO extension_bundle_version (" +
"ID, " +
"EXTENSION_BUNDLE_ID, " +
"VERSION, " +
"CREATED, " +
"CREATED_BY, " +
"DESCRIPTION, " +
"SHA_256_HEX, " +
"SHA_256_SUPPLIED," +
"CONTENT_SIZE " +
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(sql,
extensionBundleVersion.getId(),
extensionBundleVersion.getExtensionBundleId(),
extensionBundleVersion.getVersion(),
extensionBundleVersion.getCreated(),
extensionBundleVersion.getCreatedBy(),
extensionBundleVersion.getDescription(),
extensionBundleVersion.getSha256Hex(),
extensionBundleVersion.getSha256Supplied() ? 1 : 0,
extensionBundleVersion.getContentSize());
return extensionBundleVersion;
}
private static final String BASE_EXTENSION_BUNDLE_VERSION_SQL =
"SELECT " +
"ebv.id AS ID," +
"ebv.extension_bundle_id AS EXTENSION_BUNDLE_ID, " +
"ebv.version AS VERSION, " +
"ebv.created AS CREATED, " +
"ebv.created_by AS CREATED_BY, " +
"ebv.description AS DESCRIPTION, " +
"ebv.sha_256_hex AS SHA_256_HEX, " +
"ebv.sha_256_supplied AS SHA_256_SUPPLIED ," +
"ebv.content_size AS CONTENT_SIZE, " +
"eb.bucket_id AS BUCKET_ID " +
"FROM extension_bundle eb, extension_bundle_version ebv " +
"WHERE eb.id = ebv.extension_bundle_id ";
@Override
public ExtensionBundleVersionEntity getExtensionBundleVersion(final String extensionBundleId, final String version) {
final String sql = BASE_EXTENSION_BUNDLE_VERSION_SQL +
" AND ebv.extension_bundle_id = ? AND ebv.version = ?";
try {
return jdbcTemplate.queryForObject(sql, new ExtensionBundleVersionEntityRowMapper(), extensionBundleId, version);
} catch (EmptyResultDataAccessException e) {
return null;
}
}
@Override
public ExtensionBundleVersionEntity getExtensionBundleVersion(final String bucketId, final String groupId, final String artifactId, final String version) {
final String sql = BASE_EXTENSION_BUNDLE_VERSION_SQL +
"AND eb.bucket_id = ? " +
"AND eb.group_id = ? " +
"AND eb.artifact_id = ? " +
"AND ebv.version = ?";
try {
return jdbcTemplate.queryForObject(sql, new ExtensionBundleVersionEntityRowMapper(), bucketId, groupId, artifactId, version);
} catch (EmptyResultDataAccessException e) {
return null;
}
}
@Override
public List<ExtensionBundleVersionEntity> getExtensionBundleVersions(final Set<String> bucketIdentifiers, final ExtensionBundleVersionFilterParams filterParams) {
if (bucketIdentifiers == null || bucketIdentifiers.isEmpty()) {
return Collections.emptyList();
}
final List<Object> args = new ArrayList<>();
final StringBuilder sqlBuilder = new StringBuilder(BASE_EXTENSION_BUNDLE_VERSION_SQL);
if (filterParams != null) {
final String groupId = filterParams.getGroupId();
if (!StringUtils.isBlank(groupId)) {
sqlBuilder.append(" AND eb.group_id LIKE ? ");
args.add(groupId);
}
final String artifactId = filterParams.getArtifactId();
if (!StringUtils.isBlank(artifactId)) {
sqlBuilder.append(" AND eb.artifact_id LIKE ? ");
args.add(artifactId);
}
final String version = filterParams.getVersion();
if (!StringUtils.isBlank(version)) {
sqlBuilder.append(" AND ebv.version LIKE ? ");
args.add(version);
}
}
addBucketIdentifiersClause(sqlBuilder, "eb.bucket_id", bucketIdentifiers);
args.addAll(bucketIdentifiers);
final List<ExtensionBundleVersionEntity> bundleVersionEntities = jdbcTemplate.query(
sqlBuilder.toString(), args.toArray(), new ExtensionBundleVersionEntityRowMapper());
return bundleVersionEntities;
}
private void addBucketIdentifiersClause(StringBuilder sqlBuilder, String bucketField, Set<String> bucketIdentifiers) {
sqlBuilder.append(" AND ").append(bucketField).append(" IN (");
for (int i = 0; i < bucketIdentifiers.size(); i++) {
if (i > 0) {
sqlBuilder.append(", ");
}
sqlBuilder.append("?");
}
sqlBuilder.append(") ");
}
@Override
public List<ExtensionBundleVersionEntity> getExtensionBundleVersions(final String extensionBundleId) {
final String sql = BASE_EXTENSION_BUNDLE_VERSION_SQL + " AND ebv.extension_bundle_id = ?";
return jdbcTemplate.query(sql, new Object[]{extensionBundleId}, new ExtensionBundleVersionEntityRowMapper());
}
@Override
public List<ExtensionBundleVersionEntity> getExtensionBundleVersions(final String bucketId, final String groupId, final String artifactId) {
final String sql = BASE_EXTENSION_BUNDLE_VERSION_SQL +
"AND eb.bucket_id = ? " +
"AND eb.group_id = ? " +
"AND eb.artifact_id = ? ";
final Object[] args = {bucketId, groupId, artifactId};
return jdbcTemplate.query(sql, args, new ExtensionBundleVersionEntityRowMapper());
}
@Override
public List<ExtensionBundleVersionEntity> getExtensionBundleVersionsGlobal(final String groupId, final String artifactId, final String version) {
final String sql = BASE_EXTENSION_BUNDLE_VERSION_SQL +
"AND eb.group_id = ? " +
"AND eb.artifact_id = ? " +
"AND ebv.version = ?";
final Object[] args = {groupId, artifactId, version};
return jdbcTemplate.query(sql, args, new ExtensionBundleVersionEntityRowMapper());
}
@Override
public void deleteExtensionBundleVersion(final ExtensionBundleVersionEntity extensionBundleVersion) {
deleteExtensionBundleVersion(extensionBundleVersion.getId());
}
@Override
public void deleteExtensionBundleVersion(final String extensionBundleVersionId) {
// NOTE: All of the foreign key constraints for extension related tables are set to cascade on delete
final String sql = "DELETE FROM extension_bundle_version WHERE id = ?";
jdbcTemplate.update(sql, extensionBundleVersionId);
}
//------------ Extension Bundle Version Dependencies ------------
@Override
public ExtensionBundleVersionDependencyEntity createDependency(final ExtensionBundleVersionDependencyEntity dependencyEntity) {
final String dependencySql =
"INSERT INTO extension_bundle_version_dependency (" +
"ID, " +
"EXTENSION_BUNDLE_VERSION_ID, " +
"GROUP_ID, " +
"ARTIFACT_ID, " +
"VERSION " +
") VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(dependencySql,
dependencyEntity.getId(),
dependencyEntity.getExtensionBundleVersionId(),
dependencyEntity.getGroupId(),
dependencyEntity.getArtifactId(),
dependencyEntity.getVersion());
return dependencyEntity;
}
@Override
public List<ExtensionBundleVersionDependencyEntity> getDependenciesForBundleVersion(final String extensionBundleVersionId) {
final String sql = "SELECT * FROM extension_bundle_version_dependency WHERE extension_bundle_version_id = ?";
final Object[] args = {extensionBundleVersionId};
return jdbcTemplate.query(sql, args, new ExtensionBundleVersionDependencyEntityRowMapper());
}
//----------------- Extensions ---------------------------------
@Override
public ExtensionEntity createExtension(final ExtensionEntity extension) {
final String insertExtensionSql =
"INSERT INTO extension (" +
"ID, " +
"EXTENSION_BUNDLE_VERSION_ID, " +
"TYPE, " +
"TYPE_DESCRIPTION, " +
"IS_RESTRICTED, " +
"CATEGORY, " +
"TAGS " +
") VALUES (?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(insertExtensionSql,
extension.getId(),
extension.getExtensionBundleVersionId(),
extension.getType(),
extension.getTypeDescription(),
extension.isRestricted() ? 1 : 0,
extension.getCategory().toString(),
extension.getTags()
);
final String insertTagSql = "INSERT INTO extension_tag (EXTENSION_ID, TAG) VALUES (?, ?);";
if (extension.getTags() != null) {
final String tags[] = extension.getTags().split("[,]");
for (final String tag : tags) {
if (tag != null) {
jdbcTemplate.update(insertTagSql, extension.getId(), tag.trim().toLowerCase());
}
}
}
return extension;
}
@Override
public ExtensionEntity getExtensionById(final String id) {
final String selectSql = "SELECT * FROM extension WHERE id = ?";
try {
return jdbcTemplate.queryForObject(selectSql, new ExtensionEntityRowMapper(), id);
} catch (EmptyResultDataAccessException e) {
return null;
}
}
@Override
public List<ExtensionEntity> getAllExtensions() {
final String selectSql = "SELECT * FROM extension ORDER BY type ASC";
return jdbcTemplate.query(selectSql, new ExtensionEntityRowMapper());
}
@Override
public List<ExtensionEntity> getExtensionsByBundleVersionId(final String extensionBundleVersionId) {
final String selectSql =
"SELECT * " +
"FROM extension " +
"WHERE extension_bundle_version_id = ?";
final Object[] args = { extensionBundleVersionId };
return jdbcTemplate.query(selectSql, args, new ExtensionEntityRowMapper());
}
@Override
public List<ExtensionEntity> getExtensionsByBundleCoordinate(final String bucketId, final String groupId, final String artifactId, final String version) {
final String sql =
"SELECT * " +
"FROM extension_bundle eb, extension_bundle_version ebv, extension e " +
"WHERE eb.id = ebv.extension_bundle_id " +
"AND ebv.id = e.extension_bundle_version_id " +
"AND eb.bucket_id = ? " +
"AND eb.group_id = ? " +
"AND eb.artifact_id = ? " +
"AND ebv.version = ?";
final Object[] args = { bucketId, groupId, artifactId, version };
return jdbcTemplate.query(sql, args, new ExtensionEntityRowMapper());
}
@Override
public List<ExtensionEntity> getExtensionsByCategory(final ExtensionEntityCategory category) {
final String selectSql = "SELECT * FROM extension WHERE category = ?";
final Object[] args = { category.toString() };
return jdbcTemplate.query(selectSql, args, new ExtensionEntityRowMapper());
}
@Override
public List<ExtensionEntity> getExtensionsByTag(final String tag) {
final String selectSql =
"SELECT * " +
"FROM extension e, extension_tag et " +
"WHERE e.id = et.extension_id AND et.tag = ?";
final Object[] args = { tag };
return jdbcTemplate.query(selectSql, args, new ExtensionEntityRowMapper());
}
@Override
public Set<String> getAllExtensionTags() {
final String selectSql = "SELECT DISTINCT tag FROM extension_tag ORDER BY tag ASC";
final Set<String> tags = new LinkedHashSet<>();
final RowCallbackHandler handler = (rs) -> tags.add(rs.getString(1));
jdbcTemplate.query(selectSql, handler);
return tags;
}
@Override
public void deleteExtension(final ExtensionEntity extension) {
// NOTE: All of the foreign key constraints for extension related tables are set to cascade on delete
final String deleteSql = "DELETE FROM extension WHERE id = ?";
jdbcTemplate.update(deleteSql, extension.getId());
}
//----------------- Fields ---------------------------------
@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;
}
}