Java tutorial
/* * 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.service.extension; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.nifi.registry.bucket.Bucket; import org.apache.nifi.registry.db.entity.BucketEntity; import org.apache.nifi.registry.db.entity.ExtensionBundleEntity; import org.apache.nifi.registry.db.entity.ExtensionBundleEntityType; import org.apache.nifi.registry.db.entity.ExtensionBundleVersionDependencyEntity; import org.apache.nifi.registry.db.entity.ExtensionBundleVersionEntity; import org.apache.nifi.registry.exception.ResourceNotFoundException; import org.apache.nifi.registry.extension.BundleCoordinate; import org.apache.nifi.registry.extension.BundleDetails; import org.apache.nifi.registry.extension.BundleExtractor; import org.apache.nifi.registry.extension.ExtensionBundle; import org.apache.nifi.registry.extension.ExtensionBundleContext; import org.apache.nifi.registry.extension.ExtensionBundlePersistenceProvider; import org.apache.nifi.registry.extension.ExtensionBundleType; import org.apache.nifi.registry.extension.ExtensionBundleVersion; import org.apache.nifi.registry.extension.ExtensionBundleVersionDependency; import org.apache.nifi.registry.extension.ExtensionBundleVersionMetadata; import org.apache.nifi.registry.extension.filter.ExtensionBundleFilterParams; import org.apache.nifi.registry.extension.filter.ExtensionBundleVersionFilterParams; import org.apache.nifi.registry.extension.repo.ExtensionRepoArtifact; import org.apache.nifi.registry.extension.repo.ExtensionRepoBucket; import org.apache.nifi.registry.extension.repo.ExtensionRepoGroup; import org.apache.nifi.registry.extension.repo.ExtensionRepoVersionSummary; import org.apache.nifi.registry.properties.NiFiRegistryProperties; import org.apache.nifi.registry.provider.extension.StandardExtensionBundleContext; import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils; import org.apache.nifi.registry.service.DataModelMapper; import org.apache.nifi.registry.service.MetadataService; import org.apache.nifi.registry.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Validator; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.DigestInputStream; import java.security.MessageDigest; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; import java.util.stream.Collectors; @Service public class StandardExtensionService implements ExtensionService { private static final Logger LOGGER = LoggerFactory.getLogger(StandardExtensionService.class); static final String SNAPSHOT_VERSION_SUFFIX = "SNAPSHOT"; private final MetadataService metadataService; private final Map<ExtensionBundleType, BundleExtractor> extractors; private final ExtensionBundlePersistenceProvider bundlePersistenceProvider; private final Validator validator; private final File extensionsWorkingDir; @Autowired public StandardExtensionService(final MetadataService metadataService, final Map<ExtensionBundleType, BundleExtractor> extractors, final ExtensionBundlePersistenceProvider bundlePersistenceProvider, final Validator validator, final NiFiRegistryProperties properties) { this.metadataService = metadataService; this.extractors = extractors; this.bundlePersistenceProvider = bundlePersistenceProvider; this.validator = validator; this.extensionsWorkingDir = properties.getExtensionsWorkingDirectory(); Validate.notNull(this.metadataService); Validate.notNull(this.extractors); Validate.notNull(this.bundlePersistenceProvider); Validate.notNull(this.validator); Validate.notNull(this.extensionsWorkingDir); } private <T> void validate(T t, String invalidMessage) { final Set<ConstraintViolation<T>> violations = validator.validate(t); if (violations.size() > 0) { throw new ConstraintViolationException(invalidMessage, violations); } } @Override public ExtensionBundleVersion createExtensionBundleVersion(final String bucketIdentifier, final ExtensionBundleType bundleType, final InputStream inputStream, final String clientSha256) throws IOException { if (StringUtils.isBlank(bucketIdentifier)) { throw new IllegalArgumentException("Bucket identifier cannot be null or blank"); } if (bundleType == null) { throw new IllegalArgumentException("Bundle type cannot be null"); } if (inputStream == null) { throw new IllegalArgumentException("Extension bundle input stream cannot be null"); } if (!extractors.containsKey(bundleType)) { throw new IllegalArgumentException( "No metadata extractor is registered for bundle-type: " + bundleType); } // ensure the bucket exists final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier); if (existingBucket == null) { LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier); throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry."); } // ensure the extensions directory exists and we can read and write to it FileUtils.ensureDirectoryExistAndCanReadAndWrite(extensionsWorkingDir); final String extensionWorkingFilename = UUID.randomUUID().toString(); final File extensionWorkingFile = new File(extensionsWorkingDir, extensionWorkingFilename); LOGGER.debug("Writing bundle contents to working directory at {}", new Object[] { extensionWorkingFile.getAbsolutePath() }); try { // write the contents of the input stream to a temporary file in the extensions working directory final MessageDigest sha256Digest = DigestUtils.getSha256Digest(); try (final DigestInputStream digestInputStream = new DigestInputStream(inputStream, sha256Digest); final OutputStream out = new FileOutputStream(extensionWorkingFile)) { IOUtils.copy(digestInputStream, out); } // get the hex of the SHA-256 computed by the server and compare to the client provided SHA-256, if one was provided final String sha256Hex = Hex.encodeHexString(sha256Digest.digest()); final boolean sha256Supplied = !StringUtils.isBlank(clientSha256); if (sha256Supplied && !sha256Hex.equalsIgnoreCase(clientSha256)) { LOGGER.error("Client provided SHA-256 of '{}', but server calculated '{}'", new Object[] { clientSha256, sha256Hex }); throw new IllegalStateException( "The SHA-256 of the received extension bundle does not match the SHA-256 provided by the client"); } // extract the details of the bundle from the temp file in the working directory final BundleDetails bundleDetails; try (final InputStream in = new FileInputStream(extensionWorkingFile)) { final BundleExtractor extractor = extractors.get(bundleType); bundleDetails = extractor.extract(in); } final BundleCoordinate bundleCoordinate = bundleDetails.getBundleCoordinate(); final Set<BundleCoordinate> dependencyCoordinates = bundleDetails.getDependencyBundleCoordinates(); final String groupId = bundleCoordinate.getGroupId(); final String artifactId = bundleCoordinate.getArtifactId(); final String version = bundleCoordinate.getVersion(); final boolean isSnapshotVersion = version.endsWith(SNAPSHOT_VERSION_SUFFIX); final boolean overwriteBundleVersion = isSnapshotVersion || existingBucket.isAllowExtensionBundleRedeploy(); LOGGER.debug("Extracted bundle details - '{}' - '{}' - '{}'", new Object[] { groupId, artifactId, version }); // a bundle with the same group, artifact, and version can exist in multiple buckets, but only if it contains the same binary content, or if its a snapshot version // we can determine that by comparing the SHA-256 digest of the incoming bundle against existing bundles with the same group, artifact, version final List<ExtensionBundleVersionEntity> allExistingVersions = metadataService .getExtensionBundleVersionsGlobal(groupId, artifactId, version); for (final ExtensionBundleVersionEntity existingVersionEntity : allExistingVersions) { if (!existingVersionEntity.getSha256Hex().equals(sha256Hex) && !isSnapshotVersion) { throw new IllegalStateException( "Found existing extension bundle with same group, artifact, and version, but different SHA-256 checksums"); } } // get the existing extension bundle entity, or create a new one if one does not exist in the bucket with the group + artifact final long currentTime = System.currentTimeMillis(); final ExtensionBundleEntity extensionBundle = getOrCreateExtensionBundle(bucketIdentifier, groupId, artifactId, bundleType, currentTime); // check if the version of incoming bundle already exists in the bucket // if it exists and it is a snapshot version or the bucket allows redeploying, then first delete the row in the extension_bundle_version table so we can create a new one // otherwise we throw an exception because we don't allow the same version in the same bucket final ExtensionBundleVersionEntity existingVersion = metadataService .getExtensionBundleVersion(bucketIdentifier, groupId, artifactId, version); if (existingVersion != null) { if (overwriteBundleVersion) { metadataService.deleteExtensionBundleVersion(existingVersion); } else { LOGGER.warn("The specified version [{}] already exists for extension bundle [{}].", new Object[] { version, extensionBundle.getId() }); throw new IllegalStateException( "The specified version already exists for the given extension bundle"); } } // create the version metadata instance and validate it has all the required fields final String userIdentity = NiFiUserUtils.getNiFiUserIdentity(); final ExtensionBundleVersionMetadata versionMetadata = new ExtensionBundleVersionMetadata(); versionMetadata.setId(UUID.randomUUID().toString()); versionMetadata.setExtensionBundleId(extensionBundle.getId()); versionMetadata.setBucketId(bucketIdentifier); versionMetadata.setVersion(version); versionMetadata.setTimestamp(currentTime); versionMetadata.setAuthor(userIdentity); versionMetadata.setSha256(sha256Hex); versionMetadata.setSha256Supplied(sha256Supplied); versionMetadata.setContentSize(extensionWorkingFile.length()); validate(versionMetadata, "Cannot create extension bundle version"); // create the version dependency instances and validate they have the required fields final Set<ExtensionBundleVersionDependency> versionDependencies = new HashSet<>(); for (final BundleCoordinate dependencyCoordinate : dependencyCoordinates) { final ExtensionBundleVersionDependency versionDependency = new ExtensionBundleVersionDependency(); versionDependency.setGroupId(dependencyCoordinate.getGroupId()); versionDependency.setArtifactId(dependencyCoordinate.getArtifactId()); versionDependency.setVersion(dependencyCoordinate.getVersion()); validate(versionDependency, "Cannot create extension bundle version dependency"); versionDependencies.add(versionDependency); } // create the bundle version in the metadata db final ExtensionBundleVersionEntity versionEntity = DataModelMapper.map(versionMetadata); metadataService.createExtensionBundleVersion(versionEntity); // create the bundle version dependencies in the metadata db for (final ExtensionBundleVersionDependency versionDependency : versionDependencies) { final ExtensionBundleVersionDependencyEntity versionDependencyEntity = DataModelMapper .map(versionDependency); versionDependencyEntity.setId(UUID.randomUUID().toString()); versionDependencyEntity.setExtensionBundleVersionId(versionEntity.getId()); metadataService.createDependency(versionDependencyEntity); } // persist the content of the bundle to the persistence provider final ExtensionBundleContext context = new StandardExtensionBundleContext.Builder() .bundleType(getProviderBundleType(bundleType)).bucketId(existingBucket.getId()) .bucketName(existingBucket.getName()).bundleId(extensionBundle.getId()) .bundleGroupId(extensionBundle.getGroupId()).bundleArtifactId(extensionBundle.getArtifactId()) .bundleVersion(versionMetadata.getVersion()).author(versionMetadata.getAuthor()) .timestamp(versionMetadata.getTimestamp()).build(); try (final InputStream in = new FileInputStream(extensionWorkingFile); final InputStream bufIn = new BufferedInputStream(in)) { bundlePersistenceProvider.saveBundleVersion(context, bufIn, overwriteBundleVersion); LOGGER.debug("Bundle saved to persistence provider - '{}' - '{}' - '{}'", new Object[] { groupId, artifactId, version }); } // get the updated extension bundle so it contains the correct version count final ExtensionBundleEntity updatedBundle = metadataService.getExtensionBundle(bucketIdentifier, groupId, artifactId); // create the full ExtensionBundleVersion instance to return final ExtensionBundleVersion extensionBundleVersion = new ExtensionBundleVersion(); extensionBundleVersion.setVersionMetadata(versionMetadata); extensionBundleVersion.setExtensionBundle(DataModelMapper.map(existingBucket, updatedBundle)); extensionBundleVersion.setBucket(DataModelMapper.map(existingBucket)); extensionBundleVersion.setDependencies(versionDependencies); return extensionBundleVersion; } finally { if (extensionWorkingFile.exists()) { try { extensionWorkingFile.delete(); } catch (Exception e) { LOGGER.warn("Error removing temporary extension bundle file at {}", new Object[] { extensionWorkingFile.getAbsolutePath() }); } } } } private ExtensionBundleEntity getOrCreateExtensionBundle(final String bucketId, final String groupId, final String artifactId, final ExtensionBundleType bundleType, final long currentTime) { ExtensionBundleEntity existingBundleEntity = metadataService.getExtensionBundle(bucketId, groupId, artifactId); if (existingBundleEntity == null) { final ExtensionBundle bundle = new ExtensionBundle(); bundle.setIdentifier(UUID.randomUUID().toString()); bundle.setBucketIdentifier(bucketId); bundle.setName(groupId + ":" + artifactId); bundle.setGroupId(groupId); bundle.setArtifactId(artifactId); bundle.setBundleType(bundleType); bundle.setCreatedTimestamp(currentTime); bundle.setModifiedTimestamp(currentTime); validate(bundle, "Cannot create extension bundle"); existingBundleEntity = metadataService.createExtensionBundle(DataModelMapper.map(bundle)); } else { final ExtensionBundleEntityType bundleEntityType = DataModelMapper.map(bundleType); if (bundleEntityType != existingBundleEntity.getBundleType()) { throw new IllegalStateException( "A bundle already exists with the same group id and artifact id, but a different bundle type"); } } return existingBundleEntity; } private ExtensionBundleContext.BundleType getProviderBundleType(final ExtensionBundleType bundleType) { switch (bundleType) { case NIFI_NAR: return ExtensionBundleContext.BundleType.NIFI_NAR; case MINIFI_CPP: return ExtensionBundleContext.BundleType.MINIFI_CPP; default: throw new IllegalArgumentException("Unknown bundle type: " + bundleType.toString()); } } @Override public List<ExtensionBundle> getExtensionBundles(final Set<String> bucketIdentifiers, final ExtensionBundleFilterParams filterParams) { if (bucketIdentifiers == null) { throw new IllegalArgumentException("Bucket identifiers cannot be null"); } final List<ExtensionBundleEntity> bundleEntities = metadataService.getExtensionBundles(bucketIdentifiers, filterParams == null ? ExtensionBundleFilterParams.empty() : filterParams); return bundleEntities.stream().map(b -> DataModelMapper.map(null, b)).collect(Collectors.toList()); } @Override public List<ExtensionBundle> getExtensionBundlesByBucket(final String bucketIdentifier) { if (StringUtils.isBlank(bucketIdentifier)) { throw new IllegalArgumentException("Bucket identifier cannot be null or blank"); } // ensure the bucket exists final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier); if (existingBucket == null) { LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier); throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry."); } final List<ExtensionBundleEntity> bundleEntities = metadataService .getExtensionBundlesByBucket(bucketIdentifier); return bundleEntities.stream().map(b -> DataModelMapper.map(existingBucket, b)) .collect(Collectors.toList()); } @Override public ExtensionBundle getExtensionBundle(final String extensionBundleIdentifier) { if (StringUtils.isBlank(extensionBundleIdentifier)) { throw new IllegalArgumentException("Extension bundle identifier cannot be null or blank"); } final ExtensionBundleEntity existingBundle = metadataService.getExtensionBundle(extensionBundleIdentifier); if (existingBundle == null) { LOGGER.warn("The specified extension bundle id [{}] does not exist.", extensionBundleIdentifier); throw new ResourceNotFoundException("The specified extension bundle ID does not exist."); } final BucketEntity existingBucket = metadataService.getBucketById(existingBundle.getBucketId()); return DataModelMapper.map(existingBucket, existingBundle); } @Override public ExtensionBundle deleteExtensionBundle(final ExtensionBundle extensionBundle) { if (extensionBundle == null) { throw new IllegalArgumentException("Extension bundle cannot be null"); } // delete the bundle from the database metadataService.deleteExtensionBundle(extensionBundle.getIdentifier()); // delete all content associated with the bundle in the persistence provider bundlePersistenceProvider.deleteAllBundleVersions(extensionBundle.getBucketIdentifier(), extensionBundle.getBucketName(), extensionBundle.getGroupId(), extensionBundle.getArtifactId()); return extensionBundle; } @Override public SortedSet<ExtensionBundleVersionMetadata> getExtensionBundleVersions(final Set<String> bucketIdentifiers, final ExtensionBundleVersionFilterParams filterParams) { if (bucketIdentifiers == null) { throw new IllegalArgumentException("Bucket identifiers cannot be null"); } final SortedSet<ExtensionBundleVersionMetadata> sortedVersions = new TreeSet<>( Comparator.comparing(ExtensionBundleVersionMetadata::getExtensionBundleId) .thenComparing(ExtensionBundleVersionMetadata::getVersion)); final List<ExtensionBundleVersionEntity> bundleVersionEntities = metadataService.getExtensionBundleVersions( bucketIdentifiers, filterParams == null ? ExtensionBundleVersionFilterParams.empty() : filterParams); if (bundleVersionEntities != null) { bundleVersionEntities.forEach(bv -> sortedVersions.add(DataModelMapper.map(bv))); } return sortedVersions; } @Override public SortedSet<ExtensionBundleVersionMetadata> getExtensionBundleVersions( final String extensionBundleIdentifier) { if (StringUtils.isBlank(extensionBundleIdentifier)) { throw new IllegalArgumentException("Extension bundle identifier cannot be null or blank"); } // ensure the bundle exists final ExtensionBundleEntity existingBundle = metadataService.getExtensionBundle(extensionBundleIdentifier); if (existingBundle == null) { LOGGER.warn("The specified extension bundle id [{}] does not exist.", extensionBundleIdentifier); throw new ResourceNotFoundException("The specified extension bundle ID does not exist in this bucket."); } return getExtensionBundleVersionsSet(existingBundle); } private SortedSet<ExtensionBundleVersionMetadata> getExtensionBundleVersionsSet( final ExtensionBundleEntity existingBundle) { final SortedSet<ExtensionBundleVersionMetadata> sortedVersions = new TreeSet<>(Collections.reverseOrder()); final List<ExtensionBundleVersionEntity> existingVersions = metadataService .getExtensionBundleVersions(existingBundle.getId()); if (existingVersions != null) { existingVersions.stream().forEach(s -> sortedVersions.add(DataModelMapper.map(s))); } return sortedVersions; } @Override public ExtensionBundleVersion getExtensionBundleVersion(ExtensionBundleVersionCoordinate versionCoordinate) { if (versionCoordinate == null) { throw new IllegalArgumentException("Extension bundle version coordinate cannot be null"); } // ensure the bucket exists final BucketEntity existingBucket = metadataService.getBucketById(versionCoordinate.getBucketId()); if (existingBucket == null) { LOGGER.warn("The specified bucket id [{}] does not exist.", versionCoordinate.getBucketId()); throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry."); } // ensure the bundle exists final ExtensionBundleEntity existingBundle = metadataService.getExtensionBundle( versionCoordinate.getBucketId(), versionCoordinate.getGroupId(), versionCoordinate.getArtifactId()); if (existingBundle == null) { LOGGER.warn("The specified extension bundle [{}] does not exist.", versionCoordinate.toString()); throw new ResourceNotFoundException("The specified extension bundle does not exist in this bucket."); } //ensure the version of the bundle exists final ExtensionBundleVersionEntity existingVersion = metadataService.getExtensionBundleVersion( versionCoordinate.getBucketId(), versionCoordinate.getGroupId(), versionCoordinate.getArtifactId(), versionCoordinate.getVersion()); if (existingVersion == null) { LOGGER.warn("The specified extension bundle version [{}] does not exist.", versionCoordinate.toString()); throw new ResourceNotFoundException( "The specified extension bundle version does not exist in this bucket."); } // get the dependencies for the bundle version final List<ExtensionBundleVersionDependencyEntity> existingVersionDependencies = metadataService .getDependenciesForBundleVersion(existingVersion.getId()); // convert the dependency db entities final Set<ExtensionBundleVersionDependency> dependencies = existingVersionDependencies.stream() .map(d -> DataModelMapper.map(d)).collect(Collectors.toSet()); // create the full ExtensionBundleVersion instance to return final ExtensionBundleVersion extensionBundleVersion = new ExtensionBundleVersion(); extensionBundleVersion.setVersionMetadata(DataModelMapper.map(existingVersion)); extensionBundleVersion.setExtensionBundle(DataModelMapper.map(existingBucket, existingBundle)); extensionBundleVersion.setBucket(DataModelMapper.map(existingBucket)); extensionBundleVersion.setDependencies(dependencies); return extensionBundleVersion; } @Override public void writeExtensionBundleVersionContent(final ExtensionBundleVersion bundleVersion, final OutputStream out) { // get the content from the persistence provider and write it to the output stream final ExtensionBundleContext context = getExtensionBundleContext(bundleVersion); bundlePersistenceProvider.getBundleVersion(context, out); } @Override public ExtensionBundleVersion deleteExtensionBundleVersion(final ExtensionBundleVersion bundleVersion) { if (bundleVersion == null) { throw new IllegalArgumentException("Extension bundle version cannot be null"); } // delete from the metadata db final String extensionBundleVersionId = bundleVersion.getVersionMetadata().getId(); metadataService.deleteExtensionBundleVersion(extensionBundleVersionId); // delete content associated with the bundle version in the persistence provider final ExtensionBundleContext context = new StandardExtensionBundleContext.Builder() .bundleType(getProviderBundleType(bundleVersion.getExtensionBundle().getBundleType())) .bucketId(bundleVersion.getBucket().getIdentifier()).bucketName(bundleVersion.getBucket().getName()) .bundleId(bundleVersion.getExtensionBundle().getIdentifier()) .bundleGroupId(bundleVersion.getExtensionBundle().getGroupId()) .bundleArtifactId(bundleVersion.getExtensionBundle().getArtifactId()) .bundleVersion(bundleVersion.getVersionMetadata().getVersion()) .author(bundleVersion.getVersionMetadata().getAuthor()) .timestamp(bundleVersion.getVersionMetadata().getTimestamp()).build(); bundlePersistenceProvider.deleteBundleVersion(context); return bundleVersion; } // ------ Extension Repository Methods ------- @Override public SortedSet<ExtensionRepoBucket> getExtensionRepoBuckets(final Set<String> bucketIds) { if (bucketIds == null) { throw new IllegalArgumentException("Bucket ids cannot be null"); } if (bucketIds.isEmpty()) { return new TreeSet<>(); } final SortedSet<ExtensionRepoBucket> repoBuckets = new TreeSet<>(); final List<BucketEntity> buckets = metadataService.getBuckets(bucketIds); buckets.forEach(b -> { final ExtensionRepoBucket repoBucket = new ExtensionRepoBucket(); repoBucket.setBucketName(b.getName()); repoBuckets.add(repoBucket); }); return repoBuckets; } @Override public SortedSet<ExtensionRepoGroup> getExtensionRepoGroups(final Bucket bucket) { if (bucket == null) { throw new IllegalArgumentException("Bucket cannot be null"); } final SortedSet<ExtensionRepoGroup> repoGroups = new TreeSet<>(); final List<ExtensionBundleEntity> bundleEntities = metadataService .getExtensionBundlesByBucket(bucket.getIdentifier()); bundleEntities.forEach(b -> { final ExtensionRepoGroup repoGroup = new ExtensionRepoGroup(); repoGroup.setBucketName(bucket.getName()); repoGroup.setGroupId(b.getGroupId()); repoGroups.add(repoGroup); }); return repoGroups; } @Override public SortedSet<ExtensionRepoArtifact> getExtensionRepoArtifacts(final Bucket bucket, final String groupId) { if (bucket == null) { throw new IllegalArgumentException("Bucket cannot be null"); } if (StringUtils.isBlank(groupId)) { throw new IllegalArgumentException("Group id cannot be null or blank"); } final SortedSet<ExtensionRepoArtifact> repoArtifacts = new TreeSet<>(); final List<ExtensionBundleEntity> bundleEntities = metadataService .getExtensionBundlesByBucketAndGroup(bucket.getIdentifier(), groupId); bundleEntities.forEach(b -> { final ExtensionRepoArtifact repoArtifact = new ExtensionRepoArtifact(); repoArtifact.setBucketName(bucket.getName()); repoArtifact.setGroupId(b.getGroupId()); repoArtifact.setArtifactId(b.getArtifactId()); repoArtifacts.add(repoArtifact); }); return repoArtifacts; } @Override public SortedSet<ExtensionRepoVersionSummary> getExtensionRepoVersions(final Bucket bucket, final String groupId, final String artifactId) { if (bucket == null) { throw new IllegalArgumentException("Bucket cannot be null"); } if (StringUtils.isBlank(groupId)) { throw new IllegalArgumentException("Group id cannot be null or blank"); } if (StringUtils.isBlank(artifactId)) { throw new IllegalArgumentException("Artifact id cannot be null or blank"); } final SortedSet<ExtensionRepoVersionSummary> repoVersions = new TreeSet<>(); final List<ExtensionBundleVersionEntity> versionEntities = metadataService .getExtensionBundleVersions(bucket.getIdentifier(), groupId, artifactId); if (!versionEntities.isEmpty()) { final ExtensionBundleEntity bundleEntity = metadataService.getExtensionBundle(bucket.getIdentifier(), groupId, artifactId); if (bundleEntity == null) { // should never happen if the list of versions is not empty, but just in case throw new ResourceNotFoundException("The specified extension bundle does not exist in this bucket"); } versionEntities.forEach(v -> { final ExtensionRepoVersionSummary repoVersion = new ExtensionRepoVersionSummary(); repoVersion.setBucketName(bucket.getName()); repoVersion.setGroupId(bundleEntity.getGroupId()); repoVersion.setArtifactId(bundleEntity.getArtifactId()); repoVersion.setVersion(v.getVersion()); repoVersions.add(repoVersion); }); } return repoVersions; } // ------ Helper Methods ------- private ExtensionBundleContext getExtensionBundleContext(final ExtensionBundleVersion bundleVersion) { return getExtensionBundleContext(bundleVersion.getBucket(), bundleVersion.getExtensionBundle(), bundleVersion.getVersionMetadata()); } private ExtensionBundleContext getExtensionBundleContext(final Bucket bucket, final ExtensionBundle bundle, final ExtensionBundleVersionMetadata bundleVersionMetadata) { return new StandardExtensionBundleContext.Builder() .bundleType(getProviderBundleType(bundle.getBundleType())).bucketId(bucket.getIdentifier()) .bucketName(bucket.getName()).bundleId(bundle.getIdentifier()).bundleGroupId(bundle.getGroupId()) .bundleArtifactId(bundle.getArtifactId()).bundleVersion(bundleVersionMetadata.getVersion()) .author(bundleVersionMetadata.getAuthor()).timestamp(bundleVersionMetadata.getTimestamp()).build(); } }