http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ExtensionResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ExtensionResource.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ExtensionResource.java new file mode 100644 index 0000000..62c4c08 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ExtensionResource.java @@ -0,0 +1,366 @@ +/* + * 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.web.api; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.event.EventFactory; +import org.apache.nifi.registry.event.EventService; +import org.apache.nifi.registry.extension.ExtensionBundle; +import org.apache.nifi.registry.extension.ExtensionBundleVersion; +import org.apache.nifi.registry.extension.ExtensionBundleVersionMetadata; +import org.apache.nifi.registry.security.authorization.RequestAction; +import org.apache.nifi.registry.service.AuthorizationService; +import org.apache.nifi.registry.service.RegistryService; +import org.apache.nifi.registry.service.extension.ExtensionBundleVersionCoordinate; +import org.apache.nifi.registry.web.link.LinkService; +import org.apache.nifi.registry.web.security.PermissionsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; + +@Component +@Path("/extensions") +@Api( + value = "extensions", + description = "Gets metadata about extension bundles and extensions.", + authorizations = { @Authorization("Authorization") } +) +public class ExtensionResource extends AuthorizableApplicationResource { + + public static final String CONTENT_DISPOSITION_HEADER = "content-disposition"; + private final RegistryService registryService; + private final LinkService linkService; + private final PermissionsService permissionsService; + + @Autowired + public ExtensionResource(final RegistryService registryService, + final LinkService linkService, + final PermissionsService permissionsService, + final AuthorizationService authorizationService, + final EventService eventService) { + super(authorizationService, eventService); + this.registryService = registryService; + this.linkService = linkService; + this.permissionsService = permissionsService; + } + + @GET + @Path("bundles") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Get extension bundles across all authorized buckets", + notes = "The returned items will include only items from buckets for which the user is authorized. " + + "If the user is not authorized to any buckets, an empty list will be returned.", + response = ExtensionBundle.class, + responseContainer = "List" + ) + @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401) }) + public Response getExtensionBundles() { + + final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ); + if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { + // not authorized for any bucket, return empty list of items + return Response.status(Response.Status.OK).entity(new ArrayList<BucketItem>()).build(); + } + + List<ExtensionBundle> bundles = registryService.getExtensionBundles(authorizedBucketIds); + if (bundles == null) { + bundles = Collections.emptyList(); + } + permissionsService.populateItemPermissions(bundles); + linkService.populateLinks(bundles); + + return Response.status(Response.Status.OK).entity(bundles).build(); + } + + @GET + @Path("bundles/{bundleId}") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Gets the metadata about an extension bundle", + nickname = "globalGetExtensionBundle", + response = ExtensionBundle.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getExtensionBundle( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + permissionsService.populateItemPermissions(extensionBundle); + linkService.populateLinks(extensionBundle); + + return Response.status(Response.Status.OK).entity(extensionBundle).build(); + } + + @DELETE + @Path("bundles/{bundleId}") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Deletes the given extension bundle and all of it's versions", + nickname = "globalDeleteExtensionBundle", + response = ExtensionBundle.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response deleteExtensionBundle( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + final ExtensionBundle deletedExtensionBundle = registryService.deleteExtensionBundle(extensionBundle); + publish(EventFactory.extensionBundleDeleted(deletedExtensionBundle)); + + permissionsService.populateItemPermissions(deletedExtensionBundle); + linkService.populateLinks(deletedExtensionBundle); + + return Response.status(Response.Status.OK).entity(deletedExtensionBundle).build(); + } + + @GET + @Path("bundles/{bundleId}/versions") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Gets the metadata about the versions of an extension bundle", + nickname = "globalGetExtensionBundleVersions", + response = ExtensionBundleVersionMetadata.class, + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getExtensionBundleVersions( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + final SortedSet<ExtensionBundleVersionMetadata> bundleVersions = registryService.getExtensionBundleVersions(extensionBundle.getIdentifier()); + linkService.populateLinks(bundleVersions); + + return Response.status(Response.Status.OK).entity(bundleVersions).build(); + } + + @GET + @Path("bundles/{bundleId}/versions/{version}") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Gets the descriptor for the specified version of the extension bundle", + nickname = "globalGetExtensionBundleVersionDescriptor", + response = ExtensionBundleVersion.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getExtensionBundleVersion( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId, + @PathParam("version") + @ApiParam("The version of the bundle") + final String version) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + final ExtensionBundleVersionCoordinate versionCoordinate = new ExtensionBundleVersionCoordinate( + extensionBundle.getBucketIdentifier(), + extensionBundle.getGroupId(), + extensionBundle.getArtifactId(), + version); + + final ExtensionBundleVersion bundleVersion = registryService.getExtensionBundleVersion(versionCoordinate); + linkService.populateLinks(bundleVersion); + + return Response.ok(bundleVersion).build(); + } + + @GET + @Path("bundles/{bundleId}/versions/{version}/content") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation( + value = "Gets the binary content for the specified version of the extension bundle", + nickname = "globalGetExtensionBundleVersion", + response = byte[].class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getExtensionBundleVersionContent( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId, + @PathParam("version") + @ApiParam("The version of the bundle") + final String version) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + final ExtensionBundleVersionCoordinate versionCoordinate = new ExtensionBundleVersionCoordinate( + extensionBundle.getBucketIdentifier(), + extensionBundle.getGroupId(), + extensionBundle.getArtifactId(), + version); + + final ExtensionBundleVersion bundleVersion = registryService.getExtensionBundleVersion(versionCoordinate); + final StreamingOutput streamingOutput = (output) -> registryService.writeExtensionBundleVersionContent(bundleVersion, output); + + return Response.ok(streamingOutput) + .header(CONTENT_DISPOSITION_HEADER,"attachment; filename = " + bundleVersion.getFilename()) + .build(); + } + + @DELETE + @Path("bundles/{bundleId}/versions/{version}") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Deletes the given extension bundle version", + nickname = "globalDeleteExtensionBundleVersion", + response = ExtensionBundleVersion.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response deleteExtensionBundleVersion( + @PathParam("bundleId") + @ApiParam("The extension bundle identifier") + final String bundleId, + @PathParam("version") + @ApiParam("The version of the bundle") + final String version) { + + final ExtensionBundle extensionBundle = getExtensionBundleWithBucketReadAuthorization(bundleId); + + final ExtensionBundleVersionCoordinate versionCoordinate = new ExtensionBundleVersionCoordinate( + extensionBundle.getBucketIdentifier(), + extensionBundle.getGroupId(), + extensionBundle.getArtifactId(), + version); + + final ExtensionBundleVersion bundleVersion = registryService.getExtensionBundleVersion(versionCoordinate); + + final ExtensionBundleVersion deletedBundleVersion = registryService.deleteExtensionBundleVersion(bundleVersion); + publish(EventFactory.extensionBundleVersionDeleted(deletedBundleVersion)); + linkService.populateLinks(deletedBundleVersion); + + return Response.status(Response.Status.OK).entity(deletedBundleVersion).build(); + } + + /** + * Retrieves the extension bundle with the given id and ensures the current user has authorization to read the bucket it belongs to. + * + * @param bundleId the bundle id + * @return the extension bundle + */ + private ExtensionBundle getExtensionBundleWithBucketReadAuthorization(final String bundleId) { + final ExtensionBundle extensionBundle = registryService.getExtensionBundle(bundleId); + + // this should never happen, but if somehow the back-end didn't populate the bucket id let's make sure the flow isn't returned + if (StringUtils.isBlank(extensionBundle.getBucketIdentifier())) { + throw new IllegalStateException("Unable to authorize access because bucket identifier is null or blank"); + } + + authorizeBucketAccess(RequestAction.READ, extensionBundle.getBucketIdentifier()); + return extensionBundle; + } + +}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java index afb8e11..9a1fe55 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java @@ -123,7 +123,7 @@ public class FlowResource extends AuthorizableApplicationResource { authorizeBucketAccess(RequestAction.READ, flow.getBucketIdentifier()); permissionsService.populateItemPermissions(flow); - linkService.populateFlowLinks(flow); + linkService.populateLinks(flow); return Response.status(Response.Status.OK).entity(flow).build(); } @@ -164,7 +164,7 @@ public class FlowResource extends AuthorizableApplicationResource { final SortedSet<VersionedFlowSnapshotMetadata> snapshots = registryService.getFlowSnapshots(bucketId, flowId); if (snapshots != null ) { - linkService.populateSnapshotLinks(snapshots); + linkService.populateLinks(snapshots); } return Response.status(Response.Status.OK).entity(snapshots).build(); @@ -284,7 +284,7 @@ public class FlowResource extends AuthorizableApplicationResource { authorizeBucketAccess(RequestAction.READ, bucketId); - linkService.populateSnapshotLinks(latestMetadata); + linkService.populateLinks(latestMetadata); return Response.status(Response.Status.OK).entity(latestMetadata).build(); } @@ -299,16 +299,16 @@ public class FlowResource extends AuthorizableApplicationResource { private void populateLinksAndPermissions(VersionedFlowSnapshot snapshot) { if (snapshot.getSnapshotMetadata() != null) { - linkService.populateSnapshotLinks(snapshot.getSnapshotMetadata()); + linkService.populateLinks(snapshot.getSnapshotMetadata()); } if (snapshot.getFlow() != null) { - linkService.populateFlowLinks(snapshot.getFlow()); + linkService.populateLinks(snapshot.getFlow()); } if (snapshot.getBucket() != null) { permissionsService.populateBucketPermissions(snapshot.getBucket()); - linkService.populateBucketLinks(snapshot.getBucket()); + linkService.populateLinks(snapshot.getBucket()); } } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java index 02b63d2..b137569 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java @@ -115,7 +115,7 @@ public class ItemResource extends AuthorizableApplicationResource { items = Collections.emptyList(); } permissionsService.populateItemPermissions(items); - linkService.populateItemLinks(items); + linkService.populateLinks(items); return Response.status(Response.Status.OK).entity(items).build(); } @@ -149,7 +149,7 @@ public class ItemResource extends AuthorizableApplicationResource { final List<BucketItem> items = registryService.getBucketItems(bucketId); permissionsService.populateItemPermissions(items); - linkService.populateItemLinks(items); + linkService.populateLinks(items); return Response.status(Response.Status.OK).entity(items).build(); } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkBuilder.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkBuilder.java new file mode 100644 index 0000000..1e2bc29 --- /dev/null +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkBuilder.java @@ -0,0 +1,30 @@ +/* + * 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.web.link; + +import javax.ws.rs.core.Link; + +/** + * Creates a Link for a given type. + * + * @param <T> the type to create a link for + */ +public interface LinkBuilder<T> { + + Link createLink(T t); + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkService.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkService.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkService.java index 19e2168..9b2e818 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkService.java +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/LinkService.java @@ -17,94 +17,239 @@ package org.apache.nifi.registry.web.link; import org.apache.nifi.registry.bucket.Bucket; -import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.extension.ExtensionBundle; +import org.apache.nifi.registry.extension.ExtensionBundleVersion; +import org.apache.nifi.registry.extension.ExtensionBundleVersionMetadata; +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.flow.VersionedFlow; import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; -import org.apache.nifi.registry.web.link.builder.BucketLinkBuilder; -import org.apache.nifi.registry.web.link.builder.LinkBuilder; -import org.apache.nifi.registry.web.link.builder.VersionedFlowLinkBuilder; -import org.apache.nifi.registry.web.link.builder.VersionedFlowSnapshotLinkBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.nifi.registry.link.LinkableEntity; import org.springframework.stereotype.Service; import javax.ws.rs.core.Link; +import javax.ws.rs.core.UriBuilder; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; @Service public class LinkService { - private static final Logger LOGGER = LoggerFactory.getLogger(LinkService.class); + private static final String BUCKET_PATH = "buckets/{id}"; - private final LinkBuilder<Bucket> bucketLinkBuilder = new BucketLinkBuilder(); + private static final String FLOW_PATH = "buckets/{bucketId}/flows/{flowId}"; + private static final String FLOW_SNAPSHOT_PATH = "buckets/{bucketId}/flows/{flowId}/versions/{versionNumber}"; - private final LinkBuilder<VersionedFlow> versionedFlowLinkBuilder = new VersionedFlowLinkBuilder(); + private static final String EXTENSION_BUNDLE_PATH = "extensions/bundles/{bundleId}"; + private static final String EXTENSION_BUNDLE_VERSION_PATH = "extensions/bundles/{bundleId}/versions/{version}"; + private static final String EXTENSION_BUNDLE_VERSION_CONTENT_PATH = "extensions/bundles/{bundleId}/versions/{version}/content"; - private final LinkBuilder<VersionedFlowSnapshotMetadata> snapshotMetadataLinkBuilder = new VersionedFlowSnapshotLinkBuilder(); + private static final String EXTENSION_REPO_BUCKET_PATH = "extensions/repo/{bucketName}"; + private static final String EXTENSION_REPO_GROUP_PATH = "extensions/repo/{bucketName}/{groupId}"; + private static final String EXTENSION_REPO_ARTIFACT_PATH = "extensions/repo/{bucketName}/{groupId}/{artifactId}"; + private static final String EXTENSION_REPO_VERSION_PATH = "extensions/repo/{bucketName}/{groupId}/{artifactId}/{version}"; - // ---- Bucket Links - public void populateBucketLinks(final Iterable<Bucket> buckets) { - if (buckets == null) { - return; + private static final LinkBuilder<Bucket> BUCKET_LINK_BUILDER = (bucket) -> { + if (bucket == null) { + return null; } - buckets.forEach(b -> populateBucketLinks(b)); - } + final URI uri = UriBuilder.fromPath(BUCKET_PATH) + .resolveTemplate("id", bucket.getIdentifier()) + .build(); - public void populateBucketLinks(final Bucket bucket) { - final Link bucketLink = bucketLinkBuilder.createLink(bucket); - bucket.setLink(bucketLink); - } + return Link.fromUri(uri).rel("self").build(); + }; - // ---- Flow Links + private static final LinkBuilder<VersionedFlow> FLOW_LINK_BUILDER = (versionedFlow -> { + if (versionedFlow == null) { + return null; + } - public void populateFlowLinks(final Iterable<VersionedFlow> versionedFlows) { - if (versionedFlows == null) { - return; + final URI uri = UriBuilder.fromPath(FLOW_PATH) + .resolveTemplate("bucketId", versionedFlow.getBucketIdentifier()) + .resolveTemplate("flowId", versionedFlow.getIdentifier()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<VersionedFlowSnapshotMetadata> FLOW_SNAPSHOT_LINK_BUILDER = (snapshotMetadata) -> { + if (snapshotMetadata == null) { + return null; } - versionedFlows.forEach(f -> populateFlowLinks(f)); - } + final URI uri = UriBuilder.fromPath(FLOW_SNAPSHOT_PATH) + .resolveTemplate("bucketId", snapshotMetadata.getBucketIdentifier()) + .resolveTemplate("flowId", snapshotMetadata.getFlowIdentifier()) + .resolveTemplate("versionNumber", snapshotMetadata.getVersion()) + .build(); - public void populateFlowLinks(final VersionedFlow versionedFlow) { - final Link flowLink = versionedFlowLinkBuilder.createLink(versionedFlow); - versionedFlow.setLink(flowLink); - } + return Link.fromUri(uri).rel("content").build(); + }; - // ---- Flow Snapshot Links + private static final LinkBuilder<ExtensionBundle> EXTENSION_BUNDLE_LINK_BUILDER = (extensionBundle -> { + if (extensionBundle == null) { + return null; + } - public void populateSnapshotLinks(final Iterable<VersionedFlowSnapshotMetadata> snapshotMetadatas) { - if (snapshotMetadatas == null) { - return; + final URI uri = UriBuilder.fromPath(EXTENSION_BUNDLE_PATH) + .resolveTemplate("bundleId", extensionBundle.getIdentifier()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionBundleVersionMetadata> EXTENSION_BUNDLE_VERSION_LINK_BUILDER = (bundleVersion -> { + if (bundleVersion == null) { + return null; } - snapshotMetadatas.forEach(s -> populateSnapshotLinks(s)); - } + final URI uri = UriBuilder.fromPath(EXTENSION_BUNDLE_VERSION_PATH) + .resolveTemplate("bundleId", bundleVersion.getExtensionBundleId()) + .resolveTemplate("version", bundleVersion.getVersion()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionBundleVersion> EXTENSION_BUNDLE_VERSION_CONTENT_LINK_BUILDER = (bundleVersion -> { + if (bundleVersion == null) { + return null; + } + + final URI uri = UriBuilder.fromPath(EXTENSION_BUNDLE_VERSION_CONTENT_PATH) + .resolveTemplate("bundleId", bundleVersion.getExtensionBundle().getIdentifier()) + .resolveTemplate("version", bundleVersion.getVersionMetadata().getVersion()) + .build(); - public void populateSnapshotLinks(final VersionedFlowSnapshotMetadata snapshotMetadata) { - final Link snapshotLink = snapshotMetadataLinkBuilder.createLink(snapshotMetadata); - snapshotMetadata.setLink(snapshotLink); + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionRepoBucket> EXTENSION_REPO_BUCKET_LINK_BUILDER = (extensionRepoBucket -> { + if (extensionRepoBucket == null) { + return null; + } + + final URI uri = UriBuilder.fromPath(EXTENSION_REPO_BUCKET_PATH) + .resolveTemplate("bucketName", extensionRepoBucket.getBucketName()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionRepoGroup> EXTENSION_REPO_GROUP_LINK_BUILDER = (extensionRepoGroup -> { + if (extensionRepoGroup == null) { + return null; + } + + final URI uri = UriBuilder.fromPath(EXTENSION_REPO_GROUP_PATH) + .resolveTemplate("bucketName", extensionRepoGroup.getBucketName()) + .resolveTemplate("groupId", extensionRepoGroup.getGroupId()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionRepoArtifact> EXTENSION_REPO_ARTIFACT_LINK_BUILDER = (extensionRepoArtifact -> { + if (extensionRepoArtifact == null) { + return null; + } + + final URI uri = UriBuilder.fromPath(EXTENSION_REPO_ARTIFACT_PATH) + .resolveTemplate("bucketName", extensionRepoArtifact.getBucketName()) + .resolveTemplate("groupId", extensionRepoArtifact.getGroupId()) + .resolveTemplate("artifactId", extensionRepoArtifact.getArtifactId()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + private static final LinkBuilder<ExtensionRepoVersionSummary> EXTENSION_REPO_VERSION_LINK_BUILDER = (extensionRepoVersion -> { + if (extensionRepoVersion == null) { + return null; + } + + final URI uri = UriBuilder.fromPath(EXTENSION_REPO_VERSION_PATH) + .resolveTemplate("bucketName", extensionRepoVersion.getBucketName()) + .resolveTemplate("groupId", extensionRepoVersion.getGroupId()) + .resolveTemplate("artifactId", extensionRepoVersion.getArtifactId()) + .resolveTemplate("version", extensionRepoVersion.getVersion()) + .build(); + + return Link.fromUri(uri).rel("self").build(); + }); + + + private static final Map<Class,LinkBuilder> LINK_BUILDERS; + static { + final Map<Class,LinkBuilder> builderMap = new HashMap<>(); + builderMap.put(Bucket.class, BUCKET_LINK_BUILDER); + builderMap.put(VersionedFlow.class, FLOW_LINK_BUILDER); + builderMap.put(VersionedFlowSnapshotMetadata.class, FLOW_SNAPSHOT_LINK_BUILDER); + builderMap.put(ExtensionBundle.class, EXTENSION_BUNDLE_LINK_BUILDER); + builderMap.put(ExtensionBundleVersionMetadata.class, EXTENSION_BUNDLE_VERSION_LINK_BUILDER); + builderMap.put(ExtensionBundleVersion.class, EXTENSION_BUNDLE_VERSION_CONTENT_LINK_BUILDER); + builderMap.put(ExtensionRepoBucket.class, EXTENSION_REPO_BUCKET_LINK_BUILDER); + builderMap.put(ExtensionRepoGroup.class, EXTENSION_REPO_GROUP_LINK_BUILDER); + builderMap.put(ExtensionRepoArtifact.class, EXTENSION_REPO_ARTIFACT_LINK_BUILDER); + builderMap.put(ExtensionRepoVersionSummary.class, EXTENSION_REPO_VERSION_LINK_BUILDER); + LINK_BUILDERS = Collections.unmodifiableMap(builderMap); } - // ---- BucketItem Links + public <E extends LinkableEntity> void populateLinks(final E entity) { + final LinkBuilder linkBuilder = LINK_BUILDERS.get(entity.getClass()); + if (linkBuilder == null) { + throw new IllegalArgumentException("No LinkBuilder found for " + entity.getClass().getCanonicalName()); + } + + final Link link = linkBuilder.createLink(entity); + entity.setLink(link); + } - public void populateItemLinks(final Iterable<BucketItem> items) { - if (items == null) { + public <E extends LinkableEntity> void populateLinks(final Iterable<E> entities) { + if (entities == null) { return; } - items.forEach(i -> populateItemLinks(i)); + entities.forEach(e -> populateLinks(e)); } - public void populateItemLinks(final BucketItem bucketItem) { - if (bucketItem == null) { - return; + public <E extends LinkableEntity> void populateFullLinks(final E entity, final URI baseUri) { + final LinkBuilder linkBuilder = LINK_BUILDERS.get(entity.getClass()); + if (linkBuilder == null) { + throw new IllegalArgumentException("No LinkBuilder found for " + entity.getClass().getCanonicalName()); } - if (bucketItem instanceof VersionedFlow) { - populateFlowLinks((VersionedFlow)bucketItem); - } else { - LOGGER.error("Unable to create link for BucketItem with type: " + bucketItem.getClass().getCanonicalName()); + if (baseUri == null) { + throw new IllegalArgumentException("Base URI cannot be null"); } + + final Link relativeLink = linkBuilder.createLink(entity); + final URI relativeUri = relativeLink.getUri(); + + final URI fullUri = UriBuilder.fromUri(baseUri) + .path(relativeUri.getPath()) + .build(); + + final Link fullLink = Link.fromUri(fullUri) + .rel(relativeLink.getRel()) + .build(); + + entity.setLink(fullLink); } + + public <E extends LinkableEntity> void populateFullLinks(final Iterable<E> entities, final URI baseUri) { + if (entities == null) { + return; + } + + entities.forEach(e -> populateFullLinks(e, baseUri)); + } + } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/BucketLinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/BucketLinkBuilder.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/BucketLinkBuilder.java deleted file mode 100644 index f0409c7..0000000 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/BucketLinkBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.registry.web.link.builder; - -import org.apache.nifi.registry.bucket.Bucket; - -import javax.ws.rs.core.Link; -import javax.ws.rs.core.UriBuilder; -import java.net.URI; - -/** - * LinkBuilder that builds "self" links for Buckets. - */ -public class BucketLinkBuilder implements LinkBuilder<Bucket> { - - private static final String PATH = "buckets/{id}"; - - @Override - public Link createLink(final Bucket bucket) { - if (bucket == null) { - return null; - } - - final URI uri = UriBuilder.fromPath(PATH) - .resolveTemplate("id", bucket.getIdentifier()) - .build(); - - return Link.fromUri(uri).rel("self").build(); - } - -} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/LinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/LinkBuilder.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/LinkBuilder.java deleted file mode 100644 index ec356fd..0000000 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/LinkBuilder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.registry.web.link.builder; - -import javax.ws.rs.core.Link; - -/** - * Creates a Link for a given type. - * - * @param <T> the type to create a link for - */ -public interface LinkBuilder<T> { - - Link createLink(T t); - -} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java deleted file mode 100644 index 38d3d0e..0000000 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.registry.web.link.builder; - -import org.apache.nifi.registry.flow.VersionedFlow; - -import javax.ws.rs.core.Link; -import javax.ws.rs.core.UriBuilder; -import java.net.URI; - -/** - * LinkBuilder that builds "self" links for VersionedFlows. - */ -public class VersionedFlowLinkBuilder implements LinkBuilder<VersionedFlow> { - - private static final String PATH = "buckets/{bucketId}/flows/{flowId}"; - - @Override - public Link createLink(final VersionedFlow versionedFlow) { - if (versionedFlow == null) { - return null; - } - - final URI uri = UriBuilder.fromPath(PATH) - .resolveTemplate("bucketId", versionedFlow.getBucketIdentifier()) - .resolveTemplate("flowId", versionedFlow.getIdentifier()) - .build(); - - return Link.fromUri(uri).rel("self").build(); - } - -} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java deleted file mode 100644 index 4085c6d..0000000 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.registry.web.link.builder; - -import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; - -import javax.ws.rs.core.Link; -import javax.ws.rs.core.UriBuilder; -import java.net.URI; - -/** - * LinkBuilder that builds "self" links for VersionedFlowSnapshotMetadata. - */ -public class VersionedFlowSnapshotLinkBuilder implements LinkBuilder<VersionedFlowSnapshotMetadata> { - - private static final String PATH = "buckets/{bucketId}/flows/{flowId}/versions/{versionNumber}"; - - @Override - public Link createLink(final VersionedFlowSnapshotMetadata snapshotMetadata) { - if (snapshotMetadata == null) { - return null; - } - - final URI uri = UriBuilder.fromPath(PATH) - .resolveTemplate("bucketId", snapshotMetadata.getBucketIdentifier()) - .resolveTemplate("flowId", snapshotMetadata.getFlowIdentifier()) - .resolveTemplate("versionNumber", snapshotMetadata.getVersion()) - .build(); - - return Link.fromUri(uri).rel("content").build(); - } - -} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/authentication/kerberos/KerberosSpnegoIdentityProvider.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/authentication/kerberos/KerberosSpnegoIdentityProvider.java b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/authentication/kerberos/KerberosSpnegoIdentityProvider.java index e611b53..f44d766 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/authentication/kerberos/KerberosSpnegoIdentityProvider.java +++ b/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/authentication/kerberos/KerberosSpnegoIdentityProvider.java @@ -39,13 +39,11 @@ import org.springframework.security.crypto.codec.Base64; import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; import org.springframework.security.kerberos.authentication.KerberosServiceRequestToken; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; -@Component public class KerberosSpnegoIdentityProvider implements IdentityProvider { private static final Logger logger = LoggerFactory.getLogger(KerberosSpnegoIdentityProvider.class); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java index 2410234..2fb2f4a 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java @@ -16,11 +16,17 @@ */ package org.apache.nifi.registry.web.api; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.authorization.CurrentUser; import org.apache.nifi.registry.authorization.Permissions; import org.apache.nifi.registry.bucket.Bucket; import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.bucket.BucketItemType; import org.apache.nifi.registry.client.BucketClient; +import org.apache.nifi.registry.client.ExtensionBundleClient; +import org.apache.nifi.registry.client.ExtensionBundleVersionClient; +import org.apache.nifi.registry.client.ExtensionRepoClient; import org.apache.nifi.registry.client.FlowClient; import org.apache.nifi.registry.client.FlowSnapshotClient; import org.apache.nifi.registry.client.ItemsClient; @@ -30,6 +36,16 @@ import org.apache.nifi.registry.client.NiFiRegistryException; import org.apache.nifi.registry.client.UserClient; import org.apache.nifi.registry.client.impl.JerseyNiFiRegistryClient; import org.apache.nifi.registry.diff.VersionedFlowDifference; +import org.apache.nifi.registry.extension.ExtensionBundle; +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.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.ExtensionRepoVersion; +import org.apache.nifi.registry.extension.repo.ExtensionRepoVersionSummary; import org.apache.nifi.registry.field.Fields; import org.apache.nifi.registry.flow.VersionedFlow; import org.apache.nifi.registry.flow.VersionedFlowSnapshot; @@ -37,6 +53,9 @@ import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; import org.apache.nifi.registry.flow.VersionedProcessGroup; import org.apache.nifi.registry.flow.VersionedProcessor; import org.apache.nifi.registry.flow.VersionedPropertyDescriptor; +import org.apache.nifi.registry.util.FileUtils; +import org.bouncycastle.util.encoders.Hex; +import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -44,11 +63,21 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * Test all basic functionality of JerseyNiFiRegistryClient. @@ -60,7 +89,7 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { private NiFiRegistryClient client; @Before - public void setup() { + public void setup() throws IOException { final String baseUrl = createBaseURL(); LOGGER.info("Using base url = " + baseUrl); @@ -76,6 +105,16 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { Assert.assertNotNull(client); this.client = client; + + // Clear the extension bundles storage directory in case previous tests left data + final File extensionsStorageDir = new File("./target/test-classes/extension_bundles"); + if (extensionsStorageDir.exists()) { + try { + FileUtils.deleteFile(extensionsStorageDir, true); + } catch (Exception e) { + LOGGER.warn("Unable to delete extensions storage dir due to: " + e.getMessage(), e); + } + } } @After @@ -103,7 +142,7 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { } @Test - public void testNiFiRegistryClient() throws IOException, NiFiRegistryException { + public void testNiFiRegistryClient() throws IOException, NiFiRegistryException, NoSuchAlgorithmException { // ---------------------- TEST BUCKETS --------------------------// final BucketClient bucketClient = client.getBucketClient(); @@ -281,7 +320,190 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { Assert.assertEquals(snapshotFlow.getIdentifier(), latestMetadataWithoutBucket.getFlowIdentifier()); Assert.assertEquals(2, latestMetadataWithoutBucket.getVersion()); - // ---------------------- TEST ITEMS --------------------------// + // ---------------------- TEST EXTENSIONS ----------------------// + + // verify we have no bundles yet + final ExtensionBundleClient bundleClient = client.getExtensionBundleClient(); + final List<ExtensionBundle> allBundles = bundleClient.getAll(); + Assert.assertEquals(0, allBundles.size()); + + final Bucket bundlesBucket = createdBuckets.get(1); + final ExtensionBundleVersionClient bundleVersionClient = client.getExtensionBundleVersionClient(); + + // create version 1.0.0 of nifi-test-nar + final String testNar1 = "src/test/resources/extensions/nars/nifi-test-nar-1.0.0.nar"; + final ExtensionBundleVersion createdTestNarV1 = createExtensionBundleVersionWithStream(bundlesBucket, bundleVersionClient, testNar1, null); + + final ExtensionBundle testNarV1Bundle = createdTestNarV1.getExtensionBundle(); + LOGGER.info("Created bundle with id {}", new Object[]{testNarV1Bundle.getIdentifier()}); + + Assert.assertEquals("org.apache.nifi", testNarV1Bundle.getGroupId()); + Assert.assertEquals("nifi-test-nar", testNarV1Bundle.getArtifactId()); + Assert.assertEquals(ExtensionBundleType.NIFI_NAR, testNarV1Bundle.getBundleType()); + Assert.assertEquals(1, testNarV1Bundle.getVersionCount()); + + Assert.assertEquals("org.apache.nifi:nifi-test-nar", testNarV1Bundle.getName()); + Assert.assertEquals(bundlesBucket.getIdentifier(), testNarV1Bundle.getBucketIdentifier()); + Assert.assertEquals(bundlesBucket.getName(), testNarV1Bundle.getBucketName()); + Assert.assertNotNull(testNarV1Bundle.getPermissions()); + Assert.assertTrue(testNarV1Bundle.getCreatedTimestamp() > 0); + Assert.assertTrue(testNarV1Bundle.getModifiedTimestamp() > 0); + + final ExtensionBundleVersionMetadata testNarV1Metadata = createdTestNarV1.getVersionMetadata(); + Assert.assertEquals("1.0.0", testNarV1Metadata.getVersion()); + Assert.assertNotNull(testNarV1Metadata.getId()); + Assert.assertNotNull(testNarV1Metadata.getSha256()); + Assert.assertNotNull(testNarV1Metadata.getAuthor()); + Assert.assertEquals(testNarV1Bundle.getIdentifier(), testNarV1Metadata.getExtensionBundleId()); + Assert.assertEquals(bundlesBucket.getIdentifier(), testNarV1Metadata.getBucketId()); + Assert.assertTrue(testNarV1Metadata.getTimestamp() > 0); + Assert.assertFalse(testNarV1Metadata.getSha256Supplied()); + + final Set<ExtensionBundleVersionDependency> dependencies = createdTestNarV1.getDependencies(); + Assert.assertNotNull(dependencies); + Assert.assertEquals(1, dependencies.size()); + + final ExtensionBundleVersionDependency testNarV1Dependency = dependencies.stream().findFirst().get(); + Assert.assertEquals("org.apache.nifi", testNarV1Dependency.getGroupId()); + Assert.assertEquals("nifi-test-api-nar", testNarV1Dependency.getArtifactId()); + Assert.assertEquals("1.0.0", testNarV1Dependency.getVersion()); + + final String testNar2 = "src/test/resources/extensions/nars/nifi-test-nar-2.0.0.nar"; + + // try to create version 2.0.0 of nifi-test-nar when the supplied SHA-256 does not match server's + final String madeUpSha256 = "MADE-UP-SHA-256"; + try { + createExtensionBundleVersionWithStream(bundlesBucket, bundleVersionClient, testNar2, madeUpSha256); + Assert.fail("Should have thrown exception"); + } catch (Exception e) { + // should have thrown exception from mismatched SHA-256 + } + + // create version 2.0.0 of nifi-test-nar using correct supplied SHA-256 + final String testNar2Sha256 = calculateSha256Hex(testNar2); + final ExtensionBundleVersion createdTestNarV2 = createExtensionBundleVersionWithStream(bundlesBucket, bundleVersionClient, testNar2, testNar2Sha256); + Assert.assertTrue(createdTestNarV2.getVersionMetadata().getSha256Supplied()); + + final ExtensionBundle testNarV2Bundle = createdTestNarV2.getExtensionBundle(); + LOGGER.info("Created bundle with id {}", new Object[]{testNarV2Bundle.getIdentifier()}); + + // create version 1.0.0 of nifi-foo-nar, use the file variant + final String fooNar = "src/test/resources/extensions/nars/nifi-foo-nar-1.0.0.nar"; + final ExtensionBundleVersion createdFooNarV1 = createExtensionBundleVersionWithFile(bundlesBucket, bundleVersionClient, fooNar, null); + Assert.assertFalse(createdFooNarV1.getVersionMetadata().getSha256Supplied()); + + final ExtensionBundle fooNarV1Bundle = createdFooNarV1.getExtensionBundle(); + LOGGER.info("Created bundle with id {}", new Object[]{fooNarV1Bundle.getIdentifier()}); + + // verify there are 2 bundles now + final List<ExtensionBundle> allBundlesAfterCreate = bundleClient.getAll(); + Assert.assertEquals(2, allBundlesAfterCreate.size()); + + // verify getting bundles by bucket + Assert.assertEquals(2, bundleClient.getByBucket(bundlesBucket.getIdentifier()).size()); + Assert.assertEquals(0, bundleClient.getByBucket(flowsBucket.getIdentifier()).size()); + + // verify getting bundles by id + final ExtensionBundle retrievedBundle = bundleClient.get(testNarV1Bundle.getIdentifier()); + Assert.assertNotNull(retrievedBundle); + Assert.assertEquals(testNarV1Bundle.getIdentifier(), retrievedBundle.getIdentifier()); + Assert.assertEquals(testNarV1Bundle.getGroupId(), retrievedBundle.getGroupId()); + Assert.assertEquals(testNarV1Bundle.getArtifactId(), retrievedBundle.getArtifactId()); + + // verify getting list of version metadata for a bundle + final List<ExtensionBundleVersionMetadata> bundleVersions = bundleVersionClient.getBundleVersions(testNarV1Bundle.getIdentifier()); + Assert.assertNotNull(bundleVersions); + Assert.assertEquals(2, bundleVersions.size()); + + // verify getting a bundle version by the bundle id + version string + final ExtensionBundleVersion bundleVersion1 = bundleVersionClient.getBundleVersion(testNarV1Bundle.getIdentifier(), "1.0.0"); + Assert.assertNotNull(bundleVersion1); + Assert.assertEquals("1.0.0", bundleVersion1.getVersionMetadata().getVersion()); + Assert.assertNotNull(bundleVersion1.getDependencies()); + Assert.assertEquals(1, bundleVersion1.getDependencies().size()); + + final ExtensionBundleVersion bundleVersion2 = bundleVersionClient.getBundleVersion(testNarV1Bundle.getIdentifier(), "2.0.0"); + Assert.assertNotNull(bundleVersion2); + Assert.assertEquals("2.0.0", bundleVersion2.getVersionMetadata().getVersion()); + + // verify getting the input stream for a bundle version + try (final InputStream bundleVersion1InputStream = bundleVersionClient.getBundleVersionContent(testNarV1Bundle.getIdentifier(), "1.0.0")) { + final String sha256Hex = DigestUtils.sha256Hex(bundleVersion1InputStream); + Assert.assertEquals(testNarV1Metadata.getSha256(), sha256Hex); + } + + // verify writing a bundle version to an output stream + final File targetDir = new File("./target"); + final File bundleFile = bundleVersionClient.writeBundleVersionContent(testNarV1Bundle.getIdentifier(), "1.0.0", targetDir); + Assert.assertNotNull(bundleFile); + + try (final InputStream bundleInputStream = new FileInputStream(bundleFile)) { + final String sha256Hex = DigestUtils.sha256Hex(bundleInputStream); + Assert.assertEquals(testNarV1Metadata.getSha256(), sha256Hex); + } + + // Verify deleting a bundle version + final ExtensionBundleVersion deletedBundleVersion2 = bundleVersionClient.delete(testNarV1Bundle.getIdentifier(), "2.0.0"); + Assert.assertNotNull(deletedBundleVersion2); + Assert.assertEquals(testNarV1Bundle.getIdentifier(), deletedBundleVersion2.getExtensionBundle().getIdentifier()); + Assert.assertEquals("2.0.0", deletedBundleVersion2.getVersionMetadata().getVersion()); + + try { + bundleVersionClient.getBundleVersion(testNarV1Bundle.getIdentifier(), "2.0.0"); + Assert.fail("Should have thrown exception"); + } catch (Exception e) { + // should catch exception + } + + // ---------------------- TEST EXTENSION REPO ----------------------// + + final ExtensionRepoClient extensionRepoClient = client.getExtensionRepoClient(); + + final List<ExtensionRepoBucket> repoBuckets = extensionRepoClient.getBuckets(); + Assert.assertEquals(createdBuckets.size(), repoBuckets.size()); + + final String bundlesBucketName = bundlesBucket.getName(); + final List<ExtensionRepoGroup> repoGroups = extensionRepoClient.getGroups(bundlesBucketName); + Assert.assertEquals(1, repoGroups.size()); + + final String repoGroupId = "org.apache.nifi"; + final ExtensionRepoGroup repoGroup = repoGroups.get(0); + Assert.assertEquals(repoGroupId, repoGroup.getGroupId()); + + final List<ExtensionRepoArtifact> repoArtifacts = extensionRepoClient.getArtifacts(bundlesBucketName, repoGroupId); + Assert.assertEquals(2, repoArtifacts.size()); + + final String repoArtifactId = "nifi-test-nar"; + final List<ExtensionRepoVersionSummary> repoVersions = extensionRepoClient.getVersions(bundlesBucketName, repoGroupId, repoArtifactId); + Assert.assertEquals(1, repoVersions.size()); + + final String repoVersionString = "1.0.0"; + final ExtensionRepoVersion repoVersion = extensionRepoClient.getVersion(bundlesBucketName, repoGroupId, repoArtifactId, repoVersionString); + Assert.assertNotNull(repoVersion); + Assert.assertNotNull(repoVersion.getDownloadLink()); + Assert.assertNotNull(repoVersion.getSha256Link()); + + // verify the version links for content and sha256 + final Client jerseyClient = ClientBuilder.newBuilder().register(MultiPartFeature.class).build(); + + final WebTarget downloadLinkTarget = jerseyClient.target(repoVersion.getDownloadLink().getUri()); + try (final InputStream downloadLinkInputStream = downloadLinkTarget.request() + .accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).get().readEntity(InputStream.class)) { + final String sha256DownloadResult = DigestUtils.sha256Hex(downloadLinkInputStream); + + final WebTarget sha256LinkTarget = jerseyClient.target(repoVersion.getSha256Link().getUri()); + final String sha256LinkResult = sha256LinkTarget.request().get(String.class); + Assert.assertEquals(sha256DownloadResult, sha256LinkResult); + } + + // verify the client methods for content input stream and content sha256 + try (final InputStream repoVersionInputStream = extensionRepoClient.getVersionContent(bundlesBucketName, repoGroupId, repoArtifactId, repoVersionString)) { + final String sha256Hex = DigestUtils.sha256Hex(repoVersionInputStream); + final String repoSha256Hex = extensionRepoClient.getVersionSha256(bundlesBucketName, repoGroupId, repoArtifactId, repoVersionString); + Assert.assertEquals(sha256Hex, repoSha256Hex); + } + + // ---------------------- TEST ITEMS -------------------------- // final ItemsClient itemsClient = client.getItemsClient(); @@ -292,10 +514,25 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { // get all items final List<BucketItem> allItems = itemsClient.getAll(); - Assert.assertEquals(2, allItems.size()); - allItems.stream().forEach(i -> Assert.assertNotNull(i.getBucketName())); + Assert.assertEquals(4, allItems.size()); + allItems.stream().forEach(i -> { + Assert.assertNotNull(i.getBucketName()); + Assert.assertNotNull(i.getLink()); + }); allItems.stream().forEach(i -> LOGGER.info("All items, item " + i.getIdentifier())); + // verify 2 flow items + final List<BucketItem> flowItems = allItems.stream() + .filter(i -> i.getType() == BucketItemType.Flow) + .collect(Collectors.toList()); + Assert.assertEquals(2, flowItems.size()); + + // verify 2 bundle items + final List<BucketItem> extensionBundleItems = allItems.stream() + .filter(i -> i.getType() == BucketItemType.Extension_Bundle) + .collect(Collectors.toList()); + Assert.assertEquals(2, extensionBundleItems.size()); + // get items for bucket final List<BucketItem> bucketItems = itemsClient.getByBucket(flowsBucket.getIdentifier()); Assert.assertEquals(2, bucketItems.size()); @@ -325,6 +562,14 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { Assert.assertNotNull(deletedFlow2); LOGGER.info("Deleted flow " + deletedFlow2.getIdentifier()); + final ExtensionBundle deletedBundle1 = bundleClient.delete(testNarV1Bundle.getIdentifier()); + Assert.assertNotNull(deletedBundle1); + LOGGER.info("Deleted extension bundle " + deletedBundle1.getIdentifier()); + + final ExtensionBundle deletedBundle2 = bundleClient.delete(fooNarV1Bundle.getIdentifier()); + Assert.assertNotNull(deletedBundle2); + LOGGER.info("Deleted extension bundle " + deletedBundle2.getIdentifier()); + // delete each bucket for (final Bucket bucket : createdBuckets) { final Bucket deletedBucket = bucketClient.delete(bucket.getIdentifier()); @@ -337,6 +582,58 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase { } + private ExtensionBundleVersion createExtensionBundleVersionWithStream(final Bucket bundlesBucket, + final ExtensionBundleVersionClient bundleVersionClient, + final String narFile, final String sha256) + throws IOException, NiFiRegistryException { + + final ExtensionBundleVersion createdBundleVersion; + try (final InputStream bundleInputStream = new FileInputStream(narFile)) { + if (StringUtils.isBlank(sha256)) { + createdBundleVersion = bundleVersionClient.create( + bundlesBucket.getIdentifier(), ExtensionBundleType.NIFI_NAR, bundleInputStream); + } else { + createdBundleVersion = bundleVersionClient.create( + bundlesBucket.getIdentifier(), ExtensionBundleType.NIFI_NAR, bundleInputStream, sha256); + } + } + + Assert.assertNotNull(createdBundleVersion); + Assert.assertNotNull(createdBundleVersion.getBucket()); + Assert.assertNotNull(createdBundleVersion.getExtensionBundle()); + Assert.assertNotNull(createdBundleVersion.getVersionMetadata()); + + return createdBundleVersion; + } + + private ExtensionBundleVersion createExtensionBundleVersionWithFile(final Bucket bundlesBucket, + final ExtensionBundleVersionClient bundleVersionClient, + final String narFile, final String sha256) + throws IOException, NiFiRegistryException { + + final ExtensionBundleVersion createdBundleVersion; + if (StringUtils.isBlank(sha256)) { + createdBundleVersion = bundleVersionClient.create( + bundlesBucket.getIdentifier(), ExtensionBundleType.NIFI_NAR, new File(narFile)); + } else { + createdBundleVersion = bundleVersionClient.create( + bundlesBucket.getIdentifier(), ExtensionBundleType.NIFI_NAR, new File(narFile), sha256); + } + + Assert.assertNotNull(createdBundleVersion); + Assert.assertNotNull(createdBundleVersion.getBucket()); + Assert.assertNotNull(createdBundleVersion.getExtensionBundle()); + Assert.assertNotNull(createdBundleVersion.getVersionMetadata()); + + return createdBundleVersion; + } + + private String calculateSha256Hex(final String narFile) throws IOException { + try (final InputStream bundleInputStream = new FileInputStream(narFile)) { + return Hex.toHexString(DigestUtils.sha256(bundleInputStream)); + } + } + private static Bucket createBucket(BucketClient bucketClient, int num) throws IOException, NiFiRegistryException { final Bucket bucket = new Bucket(); bucket.setName("Bucket #" + num); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java index bfc9a46..4e1f239 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java +++ b/nifi-registry-core/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/link/TestLinkService.java @@ -18,17 +18,29 @@ package org.apache.nifi.registry.web.link; import org.apache.nifi.registry.bucket.Bucket; import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.bucket.BucketItemType; +import org.apache.nifi.registry.extension.ExtensionBundle; +import org.apache.nifi.registry.extension.ExtensionBundleVersionMetadata; +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.flow.VersionedFlow; import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import javax.ws.rs.core.UriBuilder; +import java.net.URI; import java.util.ArrayList; import java.util.List; public class TestLinkService { + private static final String BASE_URI = "http://localhost:18080/nifi-registry-api"; + private URI baseUri = UriBuilder.fromUri(BASE_URI).build(); + private LinkService linkService; private List<Bucket> buckets; @@ -36,6 +48,14 @@ public class TestLinkService { private List<VersionedFlowSnapshotMetadata> snapshots; private List<BucketItem> items; + private List<ExtensionBundle> extensionBundles; + private List<ExtensionBundleVersionMetadata> extensionBundleVersionMetadata; + + private List<ExtensionRepoBucket> extensionRepoBuckets; + private List<ExtensionRepoGroup> extensionRepoGroups; + private List<ExtensionRepoArtifact> extensionRepoArtifacts; + private List<ExtensionRepoVersionSummary> extensionRepoVersions; + @Before public void setup() { linkService = new LinkService(); @@ -43,11 +63,11 @@ public class TestLinkService { // setup buckets final Bucket bucket1 = new Bucket(); bucket1.setIdentifier("b1"); - bucket1.setName("Bucket 1"); + bucket1.setName("Bucket_1"); final Bucket bucket2 = new Bucket(); bucket2.setIdentifier("b2"); - bucket2.setName("Bucket 2"); + bucket2.setName("Bucket_2"); buckets = new ArrayList<>(); buckets.add(bucket1); @@ -56,12 +76,12 @@ public class TestLinkService { // setup flows final VersionedFlow flow1 = new VersionedFlow(); flow1.setIdentifier("f1"); - flow1.setName("Flow 1"); + flow1.setName("Flow_1"); flow1.setBucketIdentifier(bucket1.getIdentifier()); final VersionedFlow flow2 = new VersionedFlow(); flow2.setIdentifier("f2"); - flow2.setName("Flow 2"); + flow2.setName("Flow_2"); flow2.setBucketIdentifier(bucket1.getIdentifier()); flows = new ArrayList<>(); @@ -83,42 +103,197 @@ public class TestLinkService { snapshots.add(snapshotMetadata1); snapshots.add(snapshotMetadata2); + // setup extension bundles + final ExtensionBundle bundle1 = new ExtensionBundle(); + bundle1.setIdentifier("eb1"); + + final ExtensionBundle bundle2 = new ExtensionBundle(); + bundle2.setIdentifier("eb2"); + + extensionBundles = new ArrayList<>(); + extensionBundles.add(bundle1); + extensionBundles.add(bundle2); + + // setup extension bundle versions + final ExtensionBundleVersionMetadata bundleVersion1 = new ExtensionBundleVersionMetadata(); + bundleVersion1.setExtensionBundleId(bundle1.getIdentifier()); + bundleVersion1.setVersion("1.0.0"); + + final ExtensionBundleVersionMetadata bundleVersion2 = new ExtensionBundleVersionMetadata(); + bundleVersion2.setExtensionBundleId(bundle1.getIdentifier()); + bundleVersion2.setVersion("2.0.0"); + + extensionBundleVersionMetadata = new ArrayList<>(); + extensionBundleVersionMetadata.add(bundleVersion1); + extensionBundleVersionMetadata.add(bundleVersion2); + + // setup extension repo buckets + final ExtensionRepoBucket rb1 = new ExtensionRepoBucket(); + rb1.setBucketName(bucket1.getName()); + + final ExtensionRepoBucket rb2 = new ExtensionRepoBucket(); + rb2.setBucketName(bucket2.getName()); + + extensionRepoBuckets = new ArrayList<>(); + extensionRepoBuckets.add(rb1); + extensionRepoBuckets.add(rb2); + + // setup extension repo groups + final ExtensionRepoGroup rg1 = new ExtensionRepoGroup(); + rg1.setBucketName(rb1.getBucketName()); + rg1.setGroupId("g1"); + + final ExtensionRepoGroup rg2 = new ExtensionRepoGroup(); + rg2.setBucketName(rb1.getBucketName()); + rg2.setGroupId("g2"); + + extensionRepoGroups = new ArrayList<>(); + extensionRepoGroups.add(rg1); + extensionRepoGroups.add(rg2); + + // setup extension repo artifacts + final ExtensionRepoArtifact ra1 = new ExtensionRepoArtifact(); + ra1.setBucketName(rb1.getBucketName()); + ra1.setGroupId(rg1.getGroupId()); + ra1.setArtifactId("a1"); + + final ExtensionRepoArtifact ra2 = new ExtensionRepoArtifact(); + ra2.setBucketName(rb1.getBucketName()); + ra2.setGroupId(rg1.getGroupId()); + ra2.setArtifactId("a2"); + + extensionRepoArtifacts = new ArrayList<>(); + extensionRepoArtifacts.add(ra1); + extensionRepoArtifacts.add(ra2); + + // setup extension repo versions + final ExtensionRepoVersionSummary rv1 = new ExtensionRepoVersionSummary(); + rv1.setBucketName(rb1.getBucketName()); + rv1.setGroupId(rg1.getGroupId()); + rv1.setArtifactId(ra1.getArtifactId()); + rv1.setVersion("1.0.0"); + + final ExtensionRepoVersionSummary rv2 = new ExtensionRepoVersionSummary(); + rv2.setBucketName(rb1.getBucketName()); + rv2.setGroupId(rg1.getGroupId()); + rv2.setArtifactId(ra1.getArtifactId()); + rv2.setVersion("2.0.0"); + + extensionRepoVersions = new ArrayList<>(); + extensionRepoVersions.add(rv1); + extensionRepoVersions.add(rv2); + // setup items items = new ArrayList<>(); items.add(flow1); items.add(flow2); + items.add(bundle1); + items.add(bundle2); } @Test public void testPopulateBucketLinks() { - buckets.stream().forEach(b -> Assert.assertNull(b.getLink())); - linkService.populateBucketLinks(buckets); - buckets.stream().forEach(b -> Assert.assertEquals( + buckets.forEach(b -> Assert.assertNull(b.getLink())); + linkService.populateLinks(buckets); + buckets.forEach(b -> Assert.assertEquals( "buckets/" + b.getIdentifier(), b.getLink().getUri().toString())); } @Test public void testPopulateFlowLinks() { - flows.stream().forEach(f -> Assert.assertNull(f.getLink())); - linkService.populateFlowLinks(flows); - flows.stream().forEach(f -> Assert.assertEquals( + flows.forEach(f -> Assert.assertNull(f.getLink())); + linkService.populateLinks(flows); + flows.forEach(f -> Assert.assertEquals( "buckets/" + f.getBucketIdentifier() + "/flows/" + f.getIdentifier(), f.getLink().getUri().toString())); } @Test public void testPopulateSnapshotLinks() { - snapshots.stream().forEach(s -> Assert.assertNull(s.getLink())); - linkService.populateSnapshotLinks(snapshots); - snapshots.stream().forEach(s -> Assert.assertEquals( + snapshots.forEach(s -> Assert.assertNull(s.getLink())); + linkService.populateLinks(snapshots); + snapshots.forEach(s -> Assert.assertEquals( "buckets/" + s.getBucketIdentifier() + "/flows/" + s.getFlowIdentifier() + "/versions/" + s.getVersion(), s.getLink().getUri().toString())); } @Test public void testPopulateItemLinks() { - items.stream().forEach(i -> Assert.assertNull(i.getLink())); - linkService.populateItemLinks(items); - items.stream().forEach(i -> Assert.assertEquals( - "buckets/" + i.getBucketIdentifier() + "/flows/" + i.getIdentifier(), i.getLink().getUri().toString())); + items.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(items); + items.forEach(i -> { + if (i.getType() == BucketItemType.Flow) { + Assert.assertEquals("buckets/" + i.getBucketIdentifier() + "/flows/" + i.getIdentifier(), i.getLink().getUri().toString()); + } else { + Assert.assertEquals("extensions/bundles/" + i.getIdentifier(), i.getLink().getUri().toString()); + } + }); } + @Test + public void testPopulateExtensionBundleLinks() { + extensionBundles.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionBundles); + extensionBundles.forEach(eb -> Assert.assertEquals("extensions/bundles/" + eb.getIdentifier(), eb.getLink().getUri().toString())); + } + + @Test + public void testPopulateExtensionBundleVersionLinks() { + extensionBundleVersionMetadata.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionBundleVersionMetadata); + extensionBundleVersionMetadata.forEach(eb -> Assert.assertEquals( + "extensions/bundles/" + eb.getExtensionBundleId() + "/versions/" + eb.getVersion(), eb.getLink().getUri().toString())); + } + + @Test + public void testPopulateExtensionRepoBucketLinks() { + extensionRepoBuckets.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionRepoBuckets); + extensionRepoBuckets.forEach(i -> Assert.assertEquals( + "extensions/repo/" + i.getBucketName(), + i.getLink().getUri().toString()) + ); + } + + @Test + public void testPopulateExtensionRepoGroupLinks() { + extensionRepoGroups.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionRepoGroups); + extensionRepoGroups.forEach(i -> { + Assert.assertEquals( + "extensions/repo/" + i.getBucketName() + "/" + i.getGroupId(), + i.getLink().getUri().toString()); } + ); + } + + @Test + public void testPopulateExtensionRepoArtifactLinks() { + extensionRepoArtifacts.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionRepoArtifacts); + extensionRepoArtifacts.forEach(i -> { + Assert.assertEquals( + "extensions/repo/" + i.getBucketName() + "/" + i.getGroupId() + "/" + i.getArtifactId(), + i.getLink().getUri().toString()); } + ); + } + + @Test + public void testPopulateExtensionRepoVersionLinks() { + extensionRepoVersions.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateLinks(extensionRepoVersions); + extensionRepoVersions.forEach(i -> { + Assert.assertEquals( + "extensions/repo/" + i.getBucketName() + "/" + i.getGroupId() + "/" + i.getArtifactId() + "/" + i.getVersion(), + i.getLink().getUri().toString()); } + ); + } + + @Test + public void testPopulateExtensionRepoVersionFullLinks() { + extensionRepoVersions.forEach(i -> Assert.assertNull(i.getLink())); + linkService.populateFullLinks(extensionRepoVersions, baseUri); + extensionRepoVersions.forEach(i -> { + Assert.assertEquals( + BASE_URI + "/extensions/repo/" + i.getBucketName() + "/" + i.getGroupId() + "/" + i.getArtifactId() + "/" + i.getVersion(), + i.getLink().getUri().toString()); } + ); + } } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties index efa0290..721b949 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/application.properties @@ -23,3 +23,6 @@ #logging.level.org.springframework.core.io.support: DEBUG #logging.level.org.springframework.context.annotation: DEBUG #logging.level.org.springframework.web: DEBUG + +# Need to allow overriding of beans in integration tests +spring.main.allow-bean-definition-overriding=true \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml index fd002be..c5609ec 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/providers.xml @@ -22,4 +22,9 @@ <property name="Flow Storage Directory">./target/test-classes/flow_storage</property> </flowPersistenceProvider> + <extensionBundlePersistenceProvider> + <class>org.apache.nifi.registry.provider.extension.FileSystemExtensionBundlePersistenceProvider</class> + <property name="Extension Bundle Storage Directory">./target/test-classes/extension_bundles</property> + </extensionBundlePersistenceProvider> + </providers> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties index 113773c..70ca5e3 100644 --- a/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties +++ b/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties @@ -21,5 +21,8 @@ nifi.registry.web.http.host=localhost # providers properties # nifi.registry.providers.configuration.file=./target/test-classes/conf/providers.xml +# extensions working dir # +nifi.registry.extensions.working.directory=./target/work/extensions + # database properties nifi.registry.db.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-foo-nar-1.0.0.nar ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-foo-nar-1.0.0.nar b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-foo-nar-1.0.0.nar new file mode 100644 index 0000000..4a91f31 Binary files /dev/null and b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-foo-nar-1.0.0.nar differ http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-1.0.0.nar ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-1.0.0.nar b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-1.0.0.nar new file mode 100644 index 0000000..c3fccf3 Binary files /dev/null and b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-1.0.0.nar differ http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-bad-manifest.nar ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-bad-manifest.nar b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-bad-manifest.nar new file mode 100644 index 0000000..4400589 Binary files /dev/null and b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-bad-manifest.nar differ http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/f1e5aef7/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-diff-checksum.nar ---------------------------------------------------------------------- diff --git a/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-diff-checksum.nar b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-diff-checksum.nar new file mode 100644 index 0000000..7055b64 Binary files /dev/null and b/nifi-registry-core/nifi-registry-web-api/src/test/resources/extensions/nars/nifi-test-nar-2.0.0-diff-checksum.nar differ
