From c046e13573779dbc868804960fe5e71c4b33e314 Mon Sep 17 00:00:00 2001 From: Marie Salm Date: Wed, 2 Dec 2020 12:10:42 +0100 Subject: [PATCH] Feature/packages and fileservice (#176) * delete url attribute * add models for ImplementationPackage * add implementation package * add repository and services * add dtos and copyright * fix wiring * add GET methods for implementation package * implement POST * implement GET * add update and delete for implementation packages * file: implementation dependency switched to implementation package * fix merging errors * use file instead of files (one-to-one mapping from implementationPackage to file) * minor fix * implement create of file service * make ImplementationPackage non-abstract * fix: avoid strange model mapper behaviour * implement POST and DELETE for a file of an ImplementationPackage * delete PUT method because we currently do not implement this operation * implement get Content (download) of file * allow to load up file with the same name for different implementation packages * rename defaultfile to file + join implementation package tables * adapt exception message * add implementation package service tests * fix one to one mapping between implementation package and file * add file service tests and fix deletion of file * add check for NPE, fix controller tests * controller tests for implementation packages * fix FileServiceCloudStorageServiceTest * don't store a foreign key in the file table delete unused upload/download methods * avoid IO exception caused by unclosed streamwriter * take foreign key constraint into account when deleting a file * adjust test to change in last commit * remove dependency from File to ImplementationPackage Co-authored-by: Manuela Weigold --- .../atlas/core/CloudStorageConfiguration.java | 19 + .../exceptions/CloudStorageException.java | 19 + .../org/planqk/atlas/core/model/File.java | 20 +- .../core/model/FileImplementationPackage.java | 27 + .../model/FunctionImplementationPackage.java | 27 + .../atlas/core/model/Implementation.java | 49 +- .../core/model/ImplementationPackage.java | 57 ++ .../core/model/ImplementationPackageType.java | 24 + .../model/TOSCAImplementationPackage.java | 27 + .../atlas/core/repository/FileRepository.java | 30 +- .../ImplementationPackageRepository.java | 37 + .../atlas/core/services/FileService.java | 23 +- .../services/FileServiceCloudStorageImpl.java | 29 +- .../atlas/core/services/FileServiceImpl.java | 97 +- .../ImplementationPackageService.java | 115 +++ .../ImplementationPackageServiceImpl.java | 126 +++ .../core/services/ImplementationService.java | 21 - .../services/ImplementationServiceImpl.java | 19 - .../services/FileServiceCloudStorageTest.java | 59 +- .../atlas/core/services/FileServiceTest.java | 110 +++ .../ImplementationPackageServiceTest.java | 205 ++++ .../services/ImplementationServiceTest.java | 5 - .../util/CloudStorageTestConfiguration.java | 19 + .../atlas/core/util/ServiceTestUtils.java | 1 - .../src/test/resources/application.properties | 19 + .../src/test/resources/db-test.properties | 1 - .../java/org/planqk/atlas/web/Constants.java | 5 + .../controller/ImplementationController.java | 753 ++++++++------- .../org/planqk/atlas/web/dtos/FileDto.java | 19 + .../dtos/FileImplementationPackageDto.java | 44 + .../FunctionImplementationPackageDto.java | 44 + .../atlas/web/dtos/ImplementationDto.java | 5 - .../web/dtos/ImplementationPackageDto.java | 57 ++ .../dtos/TOSCAImplementationPackageDto.java | 43 + .../web/linkassembler/FileAssembler.java | 19 + .../ImplementationPackageAssembler.java | 39 + .../atlas/web/utils/ModelMapperUtils.java | 53 +- .../ImplementationControllerTest.java | 904 ++++++++++++------ 38 files changed, 2427 insertions(+), 743 deletions(-) create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FileImplementationPackage.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FunctionImplementationPackage.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackage.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackageType.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/TOSCAImplementationPackage.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/ImplementationPackageRepository.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageService.java create mode 100644 org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageServiceImpl.java create mode 100644 org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceTest.java create mode 100644 org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationPackageServiceTest.java create mode 100644 org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileImplementationPackageDto.java create mode 100644 org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FunctionImplementationPackageDto.java create mode 100644 org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationPackageDto.java create mode 100644 org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/TOSCAImplementationPackageDto.java create mode 100644 org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/ImplementationPackageAssembler.java diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/CloudStorageConfiguration.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/CloudStorageConfiguration.java index 6cfadda04..a13286ab3 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/CloudStorageConfiguration.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/CloudStorageConfiguration.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core; import org.springframework.context.annotation.Bean; diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/exceptions/CloudStorageException.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/exceptions/CloudStorageException.java index eb69aec07..c47684bd4 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/exceptions/CloudStorageException.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/exceptions/CloudStorageException.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.exceptions; /** diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/File.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/File.java index 3cd1f65fd..bfbf49bcf 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/File.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/File.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; import javax.persistence.Column; @@ -21,5 +40,4 @@ public class File extends KnowledgeArtifact { @Column(unique = true) private String fileURL; - } diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FileImplementationPackage.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FileImplementationPackage.java new file mode 100644 index 000000000..9e7e3c317 --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FileImplementationPackage.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; + +import javax.persistence.Entity; + +@Entity +public class FileImplementationPackage extends ImplementationPackage { + +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FunctionImplementationPackage.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FunctionImplementationPackage.java new file mode 100644 index 000000000..8eb963687 --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/FunctionImplementationPackage.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; + +import javax.persistence.Entity; + +@Entity +public class FunctionImplementationPackage extends ImplementationPackage { + +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/Implementation.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/Implementation.java index 6dada1761..2c611a201 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/Implementation.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/Implementation.java @@ -19,7 +19,6 @@ package org.planqk.atlas.core.model; -import java.net.URL; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; @@ -57,8 +56,6 @@ public class Implementation extends KnowledgeArtifact { private String parameter; - private URL link; - private String dependencies; private String version; @@ -78,8 +75,8 @@ public class Implementation extends KnowledgeArtifact { @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable(name = "implementation_publication", - joinColumns = @JoinColumn(name = "implementation_id"), - inverseJoinColumns = @JoinColumn(name = "publication_id") + joinColumns = @JoinColumn(name = "implementation_id"), + inverseJoinColumns = @JoinColumn(name = "publication_id") ) @EqualsAndHashCode.Exclude @ToString.Exclude @@ -92,37 +89,35 @@ public class Implementation extends KnowledgeArtifact { @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable(name = "implementation_tag", - joinColumns = @JoinColumn(name = "implementation_id"), - inverseJoinColumns = @JoinColumn(name = "tag_value")) + joinColumns = @JoinColumn(name = "implementation_id"), + inverseJoinColumns = @JoinColumn(name = "tag_value")) @EqualsAndHashCode.Exclude @ToString.Exclude private Set tags = new HashSet<>(); @EqualsAndHashCode.Exclude @OneToMany(cascade = CascadeType.ALL, - mappedBy = "implementation", - orphanRemoval = true) + mappedBy = "implementation", + orphanRemoval = true) private Set requiredComputeResourceProperties = new HashSet<>(); @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable(name = "implementation_software_platforms", - joinColumns = @JoinColumn(name = "implementation_id"), - inverseJoinColumns = @JoinColumn(name = "software_platform_id") + joinColumns = @JoinColumn(name = "implementation_id"), + inverseJoinColumns = @JoinColumn(name = "software_platform_id") ) @EqualsAndHashCode.Exclude @ToString.Exclude private Set softwarePlatforms = new HashSet<>(); + + @OneToMany(mappedBy = "implementation", + cascade = CascadeType.ALL, + orphanRemoval = true) @EqualsAndHashCode.Exclude - @OneToMany(cascade = CascadeType.ALL, - orphanRemoval = true) - @JoinTable( - name = "ImplementationFiles", - joinColumns = @JoinColumn(name = "implementation_id"), - inverseJoinColumns = @JoinColumn(name = "file_id") - ) - private Set files = new HashSet<>(); + @ToString.Exclude + private Set implementationPackages = new HashSet<>(); public void addTag(@NonNull Tag tag) { if (tags.contains(tag)) { @@ -171,4 +166,20 @@ public void removeSoftwarePlatform(@NonNull SoftwarePlatform softwarePlatform) { softwarePlatforms.remove(softwarePlatform); softwarePlatform.removeImplementation(this); } + + public void addImplementationPackage(@NonNull ImplementationPackage implementationPackage) { + if (implementationPackages.contains(implementationPackage)) { + return; + } + this.implementationPackages.add(implementationPackage); + implementationPackage.setImplementation(this); + } + + public void removeImplementationPackage(@NonNull ImplementationPackage implementationPackage) { + if (!implementationPackages.contains(implementationPackage)) { + return; + } + this.implementationPackages.remove(implementationPackage); + implementationPackage.setImplementation(null); + } } diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackage.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackage.java new file mode 100644 index 000000000..18468639d --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackage.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class ImplementationPackage extends HasId { + + private String name; + + private String description; + + private ImplementationPackageType packageType; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "implementation_id") + private Implementation implementation; + + @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true) + @EqualsAndHashCode.Exclude + @JoinTable( + name = "ImplementationPackageFile", + joinColumns = @JoinColumn(name = "implementation_package_id"), + inverseJoinColumns = @JoinColumn(name = "file_id") + ) + private File file; +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackageType.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackageType.java new file mode 100644 index 000000000..0e0cdb1cb --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/ImplementationPackageType.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; + +public enum ImplementationPackageType { + FILE, TOSCA, FUNCTION +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/TOSCAImplementationPackage.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/TOSCAImplementationPackage.java new file mode 100644 index 000000000..b0a6c6c6c --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/model/TOSCAImplementationPackage.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.model; + +import javax.persistence.Entity; + +@Entity +public class TOSCAImplementationPackage extends ImplementationPackage { + +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/FileRepository.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/FileRepository.java index a875cb540..60a8cdc19 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/FileRepository.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/FileRepository.java @@ -1,27 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.repository; import java.util.Optional; import java.util.UUID; import org.planqk.atlas.core.model.File; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -@Repository public interface FileRepository extends JpaRepository { Optional findByFileURL(String fileURL); @Query(value = "SELECT * " + "FROM file " + - "INNER JOIN implementation_files on file.id = implementation_files.file_id " + + "INNER JOIN implementation_package_file on file.id = implementation_package_file.file_id " + "INNER JOIN knowledge_artifact ka on file.id = ka.id " + - "WHERE implementation_files.implementation_id = :implId", + "WHERE implementation_package_file.implementation_package_id = :implementationPackageId", nativeQuery = true) - Page findFilesByImplementation(@Param("implId") UUID implementationId, Pageable pageable); + Optional findByImplementationPackage_Id(@Param("implementationPackageId") UUID implementationPackageId); } - diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/ImplementationPackageRepository.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/ImplementationPackageRepository.java new file mode 100644 index 000000000..39d17df3f --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/repository/ImplementationPackageRepository.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.repository; + +import java.util.UUID; + +import org.planqk.atlas.core.model.ImplementationPackage; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.stereotype.Repository; + +@Repository +@RepositoryRestResource(exported = false) +public interface ImplementationPackageRepository extends JpaRepository { + + Page findImplementationPackagesByImplementationId(UUID implementation, Pageable pageable); + +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileService.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileService.java index c7722d89f..559dd9d72 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileService.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileService.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; import java.util.UUID; @@ -9,9 +28,7 @@ public interface FileService { File create(MultipartFile file); - File findById(UUID id); - - File update(UUID id, MultipartFile file); + File findById(UUID fileId); void delete(UUID id); diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceCloudStorageImpl.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceCloudStorageImpl.java index fb6e2723d..f4cc4f4e2 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceCloudStorageImpl.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceCloudStorageImpl.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; import java.io.IOException; @@ -47,7 +66,7 @@ public File create(MultipartFile file) { // check if file already exists. If so set the Id to avoid duplicates in DB fileRepository.findByFileURL(implementationFile.getFileURL()) - .ifPresent(persistedFile -> implementationFile.setId(persistedFile.getId())); + .ifPresent(persistedFile -> implementationFile.setId(persistedFile.getId())); return fileRepository.save(implementationFile); } catch (IOException e) { @@ -58,8 +77,8 @@ public File create(MultipartFile file) { } @Override - public File findById(UUID id) { - return ServiceUtils.findById(id, File.class, fileRepository); + public File findById(UUID fileId) { + return ServiceUtils.findById(fileId, File.class, fileRepository); } @Override @@ -77,10 +96,6 @@ public byte[] getFileContent(UUID id) { } } - @Override - public File update(UUID id, MultipartFile file) { - return null; - } @Override public void delete(UUID id) { diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceImpl.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceImpl.java index efd4e42e9..ac8f09224 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceImpl.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/FileServiceImpl.java @@ -1,41 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.NoSuchElementException; import java.util.UUID; import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.repository.FileRepository; +import org.planqk.atlas.core.util.ServiceUtils; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service @Profile("!google-cloud") @AllArgsConstructor public class FileServiceImpl implements FileService { + private final FileRepository fileRepository; + + private final String path = System.getProperty("java.io.tmpdir"); + + private final String storageFolder = path + java.io.File.separator + "qc-atlas"; + @Override public File create(MultipartFile file) { - return null; - } + final InputStream inputStream; + final OutputStream outputStream; + + final java.io.File dir = new java.io.File(storageFolder); + if (!dir.exists()) + dir.mkdirs(); + final java.io.File newFile = new java.io.File(dir.getAbsolutePath() + java.io.File.separator + file.getOriginalFilename()); + + try { + inputStream = file.getInputStream(); + + if (!newFile.exists()) { + newFile.createNewFile(); + } + outputStream = new FileOutputStream(newFile); + int read = 0; + final int maxSize = 1024; + final byte[] bytes = new byte[maxSize]; + + while ((read = inputStream.read(bytes)) != -1) { + outputStream.write(bytes, 0, read); + } + outputStream.close(); + + final File createdFile = new File(); + createdFile.setName(file.getOriginalFilename()); + createdFile.setMimeType(file.getContentType()); + createdFile.setFileURL(newFile.getAbsolutePath()); + + final File savedFile = fileRepository.save(createdFile); + return savedFile; + + + } catch (IOException e) { + e.printStackTrace(); + } - @Override - public File findById(UUID implementationId) { return null; } @Override - public File update(UUID artifactId, MultipartFile file) { - return null; + public File findById(UUID fileId) { + return ServiceUtils.findById(fileId, File.class, fileRepository); } @Override + @Transactional public void delete(UUID id) { - + final String url = findById(id).getFileURL(); + try { + Files.deleteIfExists(Paths.get(url)); + fileRepository.deleteById(id); + } catch (IOException e) { + e.printStackTrace(); + } } @Override public byte[] getFileContent(UUID id) { - return new byte[0]; + final File file = findById(id); + try { + return Files.readAllBytes(Paths.get(file.getFileURL())); + } catch (IOException e) { + throw new NoSuchElementException("File with URL \"" + file.getFileURL() + "\" does not exist"); + } } } diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageService.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageService.java new file mode 100644 index 000000000..89eda939a --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageService.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; + +import java.util.UUID; + +import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.model.FileImplementationPackage; +import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; +import org.planqk.atlas.core.repository.ImplementationPackageRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +public interface ImplementationPackageService { + + /** + * Creates a new database entry for a given {@link ImplementationPackage} and save it to the database. + *

+ * The ID of the {@link ImplementationPackageRepository} parameter should be null, since the ID will be generated by the database when creating + * the entry. The validation for this is done by the Controller layer, which will reject {@link ImplementationPackageRepository}s with a given ID + * in its create path. + * + * @param implementationPackage The {@link ImplementationPackage} that should be saved to the database + * @return The {@link ImplementationPackageRepository} object that represents the saved status from the database + */ + @Transactional + ImplementationPackage create(ImplementationPackage implementationPackage, UUID implementationId); + + /** + * Update an existing {@link ImplementationPackage} database entry by saving the updated {@link ImplementationPackage} + * object to the the database. + *

+ * The ID of the {@link ImplementationPackage} parameter has to be set to the ID of the database entry we want to update. The + * validation for this ID to be set is done by the Controller layer, which will reject {@link ImplementationPackage}s without a given + * ID in its update path. This ID will be used to query the existing {@link ImplementationPackage} entry we want to update. If no + * {@link ImplementationPackage} entry with the given ID is found this method will throw a {@link java.util.NoSuchElementException}. + * + * @param implementationPackage The {@link ImplementationPackageRepository} we want to update with its updated properties + * @return the updated {@link ImplementationPackageRepository} object that represents the updated status of the database + */ + @Transactional + ImplementationPackage update(ImplementationPackage implementationPackage); + + /** + * Delete an existing {@link ImplementationPackage} entry from the database. This deletion is based on the ID the database has given + * the {@link ImplementationPackage} when it was created and first saved to the database. + *

+ * When deleting an {@link ImplementationPackage} related {@link FileImplementationPackage}s will be + * deleted together with it. + *

+ * Objects that can be related to multiple {@link ImplementationPackage}s will not be deleted. Only the reference to the deleted {@link + * org.planqk.atlas.core.model.Implementation} will be removed from these objects. + *

+ * If no entry with the given ID is found this method will throw a {@link java.util.NoSuchElementException}. + *

+ * If the {@link ImplementationPackage} is still referenced by at least one {@link org.planqk.atlas.core.model.Implementation} a {@link + * org.planqk.atlas.core.exceptions.EntityReferenceConstraintViolationException} will be thrown. + * + * @param implementationPackageId The ID of the {@link ImplementationPackage} we want to delete + */ + @Transactional + void delete(UUID implementationPackageId); + + /** + * Find a database entry of a {@link ImplementationPackage} that is already saved in the database. + *

+ * If there is no entry found in the database this method will throw a {@link java.util.NoSuchElementException}. + * + * @param packageId The ID of the {@link ImplementationPackage} we want to find + * @return The {@link ImplementationPackage} with the given ID + */ + ImplementationPackage findById(UUID packageId); + + Page findImplementationPackagesByImplementationId(UUID implementationId, Pageable pageable); + + void checkIfImplementationPackageIsLinkedToImplementation(UUID packageId, UUID implementationId); + + /** + * Retrieve zero or one {@link File} entry from the database of {@link File}s that are linked to the given {@link ImplementationPackage} If + * no entries are found an empty page is returned. + * + * @param implementationPackageId The ID of the {@link ImplementationPackage} we want find the linked {@link File} for + * @return The page of queried {@link File} entries which are linked to the {@link Implementation} + */ + File findLinkedFile(UUID implementationPackageId); + + /** + * Creates a {@link File} entry in the database from a multipartfile and links it to a given {@link Implementation}. + * + * @param implementationPackageId The ID of the {@link Implementation} we want the {@link File} to be linked. + * @param multipartFile The multipart from which we want to create a File entity and link it to the {@link Implementation} + * @return The created and linked {@link File} + */ + File addFileToImplementationPackage(UUID implementationPackageId, MultipartFile multipartFile); +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageServiceImpl.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageServiceImpl.java new file mode 100644 index 000000000..c3dde0d2d --- /dev/null +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationPackageServiceImpl.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; + +import java.util.NoSuchElementException; +import java.util.UUID; +import javax.transaction.Transactional; +import javax.validation.constraints.NotNull; + +import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; +import org.planqk.atlas.core.repository.FileRepository; +import org.planqk.atlas.core.repository.ImplementationPackageRepository; +import org.planqk.atlas.core.repository.ImplementationRepository; +import org.planqk.atlas.core.util.ServiceUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import lombok.AllArgsConstructor; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@AllArgsConstructor +public class ImplementationPackageServiceImpl implements ImplementationPackageService { + + private final ImplementationPackageRepository implementationPackageRepository; + + private final ImplementationRepository implementationRepository; + + private final FileRepository fileRepository; + + private final FileService fileService; + + @Override + @Transactional + public ImplementationPackage create( + @NonNull ImplementationPackage implementationPackage, UUID implementationId) { + final Implementation implementation = ServiceUtils.findById(implementationId, Implementation.class, implementationRepository); + implementationPackage.setImplementation(implementation); + // reset file to null because the ModelMapper sometimes instanciates the file object + implementationPackage.setFile(null); + final ImplementationPackage persistedImplementationPackage = implementationPackageRepository.save(implementationPackage); + return persistedImplementationPackage; + } + + @Override + @Transactional + public ImplementationPackage update(@NotNull ImplementationPackage implementationPackage) { + final ImplementationPackage persistedImplementationPackage = findById(implementationPackage.getId()); + + persistedImplementationPackage.setName(implementationPackage.getName()); + persistedImplementationPackage.setDescription(implementationPackage.getDescription()); + persistedImplementationPackage.setPackageType(implementationPackage.getPackageType()); + return implementationPackageRepository.save(persistedImplementationPackage); + } + + @Override + @Transactional + public void delete(UUID implementationPackageId) { + // final ImplementationPackage implementationPackage = findById(implementationPackageId); + + // removeReferences(implementationPackage); + + implementationPackageRepository.deleteById(implementationPackageId); + } + + @Override + public ImplementationPackage findById(UUID packageId) { + return ServiceUtils.findById(packageId, ImplementationPackage.class, implementationPackageRepository); + } + + @Override + public Page findImplementationPackagesByImplementationId(UUID implementationId, @NonNull Pageable pageable) { + return implementationPackageRepository.findImplementationPackagesByImplementationId(implementationId, pageable); + } + + @Override + public void checkIfImplementationPackageIsLinkedToImplementation(UUID packageId, UUID implementationId) { + final ImplementationPackage implementationPackage = findById(packageId); + + if (!implementationPackage.getImplementation().getId().equals(implementationId)) { + throw new NoSuchElementException("ImplementationPackage with ID \"" + packageId + + "\" of Implementation with ID \"" + implementationId + "\" does not exist"); + } + } + + @Override + public File findLinkedFile(UUID implementationPackageId) { + ServiceUtils.throwIfNotExists(implementationPackageId, ImplementationPackage.class, implementationPackageRepository); + return fileRepository.findByImplementationPackage_Id(implementationPackageId) + .orElseThrow( + () -> new NoSuchElementException("File of ImplementationPackage with ID \"" + implementationPackageId + "\" does not exist")); + } + + @Override + public File addFileToImplementationPackage(UUID implementationPackageId, MultipartFile multipartFile) { + final ImplementationPackage implementationPackage = + ServiceUtils.findById(implementationPackageId, ImplementationPackage.class, implementationPackageRepository); + final File file = fileService.create(multipartFile); + implementationPackage.setFile(file); + implementationPackageRepository.save(implementationPackage); + return file; + } +} diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationService.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationService.java index b9e6ca326..330c3c03d 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationService.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationService.java @@ -22,14 +22,12 @@ import java.util.UUID; import org.planqk.atlas.core.model.Algorithm; -import org.planqk.atlas.core.model.File; import org.planqk.atlas.core.model.Implementation; import org.planqk.atlas.core.model.Publication; import org.planqk.atlas.core.model.SoftwarePlatform; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; /** * Service class for operations related to interacting and modifying {@link Implementation}s in the database. @@ -165,24 +163,5 @@ public interface ImplementationService { */ Page findLinkedPublications(UUID implementationId, Pageable pageable); - /** - * Retrieve multiple {@link File}s entries from the database of {@link File}s that are linked to the given {@link Implementation} If - * no entries are found an empty page is returned. - *

- * The amount of entries is based on the given {@link Pageable} parameter. If the {@link Pageable} is unpaged a {@link Page} with all entries is - * queried. - *

- * @param implementationId The ID of the {@link Implementation} we want find linked {@link File}s for - * @param pageable The page information, namely page size and page number, of the page we want to retrieve - * @return The page of queried {@link File} entries which are linked to the {@link Implementation} - */ - Page findLinkedFiles(UUID implementationId, Pageable pageable); - /** - * Creates a {@link File} entry in the database from a multipartfile and links it to a given {@link Implementation}. - * @param implementationId The ID of the {@link Implementation} we want the {@link File} to be linked. - * @param multipartFile The multipart from which we want to create a File entity and link it to the {@link Implementation} - * @return The created and linked {@link File} - */ - File addFileToImplementation(UUID implementationId, MultipartFile multipartFile); } diff --git a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationServiceImpl.java b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationServiceImpl.java index 825958dea..48d40c556 100644 --- a/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationServiceImpl.java +++ b/org.planqk.atlas.core/src/main/java/org/planqk/atlas/core/services/ImplementationServiceImpl.java @@ -23,7 +23,6 @@ import java.util.UUID; import org.planqk.atlas.core.model.Algorithm; -import org.planqk.atlas.core.model.File; import org.planqk.atlas.core.model.Implementation; import org.planqk.atlas.core.model.Publication; import org.planqk.atlas.core.model.SoftwarePlatform; @@ -39,7 +38,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; import lombok.AllArgsConstructor; import lombok.NonNull; @@ -96,7 +94,6 @@ public Implementation update(@NonNull Implementation implementation) { persistedImplementation.setInputFormat(implementation.getInputFormat()); persistedImplementation.setParameter(implementation.getParameter()); persistedImplementation.setOutputFormat(implementation.getOutputFormat()); - persistedImplementation.setLink(implementation.getLink()); persistedImplementation.setDependencies(implementation.getDependencies()); persistedImplementation.setVersion(implementation.getVersion()); persistedImplementation.setLicense(implementation.getLicense()); @@ -161,20 +158,4 @@ public Page findLinkedPublications(@NonNull UUID implementationId, return publicationRepository.findPublicationsByImplementationId(implementationId, pageable); } - - @Override - public Page findLinkedFiles(UUID implementationId, Pageable pageable) { - ServiceUtils.throwIfNotExists(implementationId, Implementation.class, implementationRepository); - return fileRepository.findFilesByImplementation(implementationId, pageable); - } - - @Override - public File addFileToImplementation(UUID implementationId, MultipartFile multipartFile) { - final Implementation implementation = ServiceUtils.findById(implementationId, Implementation.class, implementationRepository); - final File file = fileService.create(multipartFile); - implementation.getFiles().add(file); - implementationRepository.save(implementation); - return file; - } - } diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceCloudStorageTest.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceCloudStorageTest.java index 8cedf5d81..f2a658232 100644 --- a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceCloudStorageTest.java +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceCloudStorageTest.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; import static org.assertj.core.api.Assertions.assertThat; @@ -5,6 +24,7 @@ import java.util.NoSuchElementException; import java.util.Random; +import java.util.UUID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -12,13 +32,13 @@ import org.mockito.Mockito; import org.planqk.atlas.core.exceptions.CloudStorageException; import org.planqk.atlas.core.model.File; -import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.FileImplementationPackage; +import org.planqk.atlas.core.model.ImplementationPackage; +import org.planqk.atlas.core.model.ImplementationPackageType; import org.planqk.atlas.core.repository.FileRepository; -import org.planqk.atlas.core.repository.ImplementationRepository; +import org.planqk.atlas.core.repository.ImplementationPackageRepository; import org.planqk.atlas.core.util.AtlasDatabaseTestBase; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ActiveProfiles; import org.springframework.web.multipart.MultipartFile; @@ -45,18 +65,18 @@ public class FileServiceCloudStorageTest extends AtlasDatabaseTestBase { private FileRepository fileRepository; @Autowired - private ImplementationRepository implementationRepository; + private ImplementationPackageRepository implementationPackageRepository; @Test public void givenFileNotExists_WhenCreate_ThenShouldBeCreated() { // Given when(storage.create(Mockito.any(BlobInfo.class), Mockito.any(byte[].class))).thenReturn(mockBlob); - Implementation persistedImplementation = implementationRepository.save(getDummyImplementation()); + ImplementationPackage persistedImplementationPackage = implementationPackageRepository.save(getDummyImplementationPackage()); assertThat(fileRepository.findAll().size()).isEqualTo(0); //When File createdFile = - fileServiceCloudStorage.create(getMultipartFile()); + fileServiceCloudStorage.create(getMultipartFile()); //Then assertThat(fileRepository.findAll().size()).isEqualTo(1); @@ -66,12 +86,12 @@ public void givenFileNotExists_WhenCreate_ThenShouldBeCreated() { @Test public void givenNone_WhenCreateAndStorageExceptionIsThrown_ThenCatchAndThrowCloudStorageException() { // Given - Implementation persistedImplementation = implementationRepository.save(getDummyImplementation()); + ImplementationPackage persistedImplementationPackage = implementationPackageRepository.save(getDummyImplementationPackage()); when(storage.create(Mockito.any(BlobInfo.class), Mockito.any(byte[].class))).thenThrow(StorageException.class); // When Assertions.assertThrows(CloudStorageException.class, - () -> fileServiceCloudStorage.create(getMultipartFile())); + () -> fileServiceCloudStorage.create(getMultipartFile())); } @Test @@ -80,7 +100,7 @@ public void givenFileExists_whenFindById_ThenShouldReturnFile() { File persistedFile = fileRepository.save(getDummyFile()); // When Then assertThat(fileServiceCloudStorage.findById(persistedFile.getId())) - .isEqualToComparingFieldByField(persistedFile); + .isEqualToComparingFieldByField(persistedFile); } @Test @@ -106,7 +126,7 @@ public void delete_cloudStorageExceptionWasThrown() { // Call + Then Assertions.assertThrows(CloudStorageException.class, - () -> fileServiceCloudStorage.delete(persistedFile.getId())); + () -> fileServiceCloudStorage.delete(persistedFile.getId())); } @Test @@ -129,7 +149,7 @@ public void getFileContent_noSuchElementExceptionWasThrown() { // Call + Then Assertions.assertThrows(NoSuchElementException.class, - () -> fileServiceCloudStorage.getFileContent(persistedFile.getId())); + () -> fileServiceCloudStorage.getFileContent(persistedFile.getId())); } @Test @@ -142,7 +162,7 @@ public void getFileContent_cloudStorageExceptionWasThrown() { // Call + Then Assertions.assertThrows(CloudStorageException.class, - () -> fileServiceCloudStorage.getFileContent(persistedFile.getId())); + () -> fileServiceCloudStorage.getFileContent(persistedFile.getId())); } private File getDummyFile() { @@ -158,13 +178,16 @@ private MultipartFile getMultipartFile() { String contentType = "text/plain"; byte[] content = generateRandomByteArray(); return new MockMultipartFile(name, - originalFileName, contentType, content); + originalFileName, contentType, content); } - private Implementation getDummyImplementation() { - Implementation dummyImplementation = new Implementation(); - dummyImplementation.setName("dummy Impl"); - return dummyImplementation; + private ImplementationPackage getDummyImplementationPackage() { + ImplementationPackage dummyImplementationPackage = new FileImplementationPackage(); + dummyImplementationPackage.setId(UUID.randomUUID()); + dummyImplementationPackage.setName("dummy ImplPackage"); + dummyImplementationPackage.setPackageType(ImplementationPackageType.FILE); + dummyImplementationPackage.setFile(null); + return dummyImplementationPackage; } private byte[] generateRandomByteArray() { diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceTest.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceTest.java new file mode 100644 index 000000000..591d04b2f --- /dev/null +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/FileServiceTest.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.repository.FileRepository; +import org.planqk.atlas.core.util.AtlasDatabaseTestBase; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +public class FileServiceTest extends AtlasDatabaseTestBase { + + private final int page = 0; + + private final int size = 2; + + @Autowired + private FileService fileService; + + @Autowired + private FileRepository fileRepository; + + private MultipartFile multipartFile; + + @BeforeEach + public void initialize() { + MultipartFile file = new MockMultipartFile("file.txt", "file.txt", "text/plain", new byte[0]); + multipartFile = file; + } + + @Test + public void createFile() { + File file = fileService.create(multipartFile); + assertThat(new java.io.File(file.getFileURL()).isFile()).isTrue(); + assertThat(new java.io.File(file.getFileURL()).exists()).isTrue(); + assertThat(fileRepository.findAll().size()).isEqualTo(1); + } + + @Test + public void findFileById() { + var storedFile = fileService.create(multipartFile); + + var foundFile = fileService.findById(storedFile.getId()); + + assertThat(storedFile.getId()).isEqualTo(foundFile.getId()); + } + + @Test + void findFile_ElementNotFound() { + assertThrows(NoSuchElementException.class, () -> { + fileService.findById(UUID.randomUUID()); + }); + } + + @Test + void deleteFile_ElementFound() { + UUID persistedFileId = fileService.create(multipartFile).getId(); + fileService.delete(persistedFileId); + assertThat(fileRepository.findById(persistedFileId)).isNotPresent(); + } + + @Test + public void getFileContent() { + String name = "file.txt"; + String originalFileName = "file.txt"; + String contentType = "text/plain"; + byte[] content = generateRandomByteArray(); + + MultipartFile multipartFileWithContent = new MockMultipartFile(name, + originalFileName, contentType, content); + File persistedFile = fileService.create(multipartFileWithContent); + byte[] result = fileService.getFileContent(persistedFile.getId()); + + assertThat(result).isEqualTo(content); + } + + private byte[] generateRandomByteArray() { + Random rd = new Random(); + byte[] arr = new byte[7]; + rd.nextBytes(arr); + return arr; + } +} diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationPackageServiceTest.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationPackageServiceTest.java new file mode 100644 index 000000000..2db438ac4 --- /dev/null +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationPackageServiceTest.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.services; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.NoSuchElementException; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.planqk.atlas.core.model.Algorithm; +import org.planqk.atlas.core.model.ClassicAlgorithm; +import org.planqk.atlas.core.model.DiscussionTopic; +import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; +import org.planqk.atlas.core.model.ImplementationPackageType; +import org.planqk.atlas.core.model.Publication; +import org.planqk.atlas.core.repository.FileRepository; +import org.planqk.atlas.core.repository.ImplementationPackageRepository; +import org.planqk.atlas.core.util.AtlasDatabaseTestBase; +import org.planqk.atlas.core.util.ServiceTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +public class ImplementationPackageServiceTest extends AtlasDatabaseTestBase { + + private final int page = 0; + + private final int size = 2; + + private final Pageable pageable = PageRequest.of(page, size); + + @Autowired + private FileService fileService; + + @Autowired + private ImplementationService implementationService; + + @Autowired + private AlgorithmService algorithmService; + + @Autowired + private ImplementationPackageService implementationPackageService; + + @Autowired + private FileRepository fileRepository; + + @Autowired + private ImplementationPackageRepository implementationPackageRepository; + + private ImplementationPackage implementationPackage; + + private ImplementationPackage implementationPackage1; + + private Implementation implementation; + + private MultipartFile multipartFile; + + @BeforeEach + public void initialize() { + implementationPackage = new ImplementationPackage(); + implementationPackage.setName("Name"); + implementationPackage.setDescription("Description"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + + implementationPackage1 = new ImplementationPackage(); + implementationPackage1.setName("Name1"); + implementationPackage1.setDescription("Description1"); + implementationPackage1.setPackageType(ImplementationPackageType.TOSCA); + + var algo = new Algorithm(); + algo.setName("TestAlgo"); + algo = algorithmService.create(algo); + + var impl = new Implementation(); + impl.setName("TestImpl"); + impl = implementationService.create(impl, algo.getId()); + + implementationPackage.setImplementation(impl); + implementationPackage1.setImplementation(impl); + implementation = impl; + + MultipartFile file = new MockMultipartFile("file.txt", "file.txt", "text/plain", new byte[0]); + multipartFile = file; + } + + @Test + public void createImplementationPackage() { + ImplementationPackage implementationPackage = implementationPackageService.create(this.implementationPackage, implementation.getId()); + assertThat(implementationPackage.getId()).isNotNull(); + assertThat(implementationPackage.getName()).isEqualTo(this.implementationPackage.getName()); + assertThat(implementationPackage.getDescription()).isEqualTo(this.implementationPackage.getDescription()); + assertThat(implementationPackage.getPackageType()).isEqualTo(this.implementationPackage.getPackageType()); + assertThat(implementationPackage.getImplementation()).isEqualTo(this.implementationPackage.getImplementation()); + } + + @Test + public void findAllImplementationPackages() { + implementationPackageService.create(implementationPackage, implementation.getId()); + implementationPackageService.create(implementationPackage1, implementation.getId()); + + Page implementationPackages = implementationPackageService.findImplementationPackagesByImplementationId(implementation.getId(), pageable); + assertThat(implementationPackages.getTotalElements()).isEqualTo(2); + } + + @Test + void findImplementationPackageById_ElementNotFound() { + assertThrows(NoSuchElementException.class, () -> { + implementationPackageService.findById(UUID.randomUUID()); + }); + } + + @Test + void findImplementationPackageById_ElementFound() { + var storedImplementationPackage = implementationPackageService.create(implementationPackage, implementation.getId()); + + var foundImplementationPackage = implementationPackageService.findById(implementationPackage.getId()); + + assertThat(storedImplementationPackage.getId()).isEqualTo(foundImplementationPackage.getId()); + } + + @Test + void updateImplementationPackage_ElementFound() { + ImplementationPackage implementationPackage = implementationPackageService.create(this.implementationPackage, implementation.getId()); + implementationPackage.setName("New Title"); + ImplementationPackage update = implementationPackageService.update(implementationPackage); + + assertThat(update.getName()).isEqualTo(implementationPackage.getName()); + assertThat(update.getDescription()).isEqualTo(implementationPackage.getDescription()); + assertThat(update.getPackageType()).isEqualTo(implementationPackage.getPackageType()); + assertThat(implementationPackage.getImplementation()).isEqualTo(this.implementationPackage.getImplementation()); + } + + @Test + void updateImplementationPackage_ElementNotFound() { + implementationPackage.setId(UUID.randomUUID()); + assertThrows(NoSuchElementException.class, () -> { + implementationPackageService.update(this.implementationPackage); + }); + } + + @Test + void deleteImplementationPackage_ElementFound() { + ImplementationPackage implementationPackage = implementationPackageService.create(this.implementationPackage, implementation.getId()); + implementationPackageService.delete(implementationPackage.getId()); + assertThrows(NoSuchElementException.class, () -> { + implementationPackageService.findById(implementationPackage.getId()); + }); + } + + @Test + void checkIfImplementationPackageIsLinkedToImplementation() { + var algo = new Algorithm(); + algo.setName("TestAlgo"); + algo = algorithmService.create(algo); + + var impl = new Implementation(); + impl.setName("Impl"); + impl = implementationService.create(impl, algo.getId()); + + implementationPackage.setImplementation(impl); + implementationPackage = implementationPackageService.create(implementationPackage, impl.getId()); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackage.getId(), impl.getId()); + + Algorithm finalAlgo = algo; + assertThrows(NoSuchElementException.class, () -> { + var impl2 = new Implementation(); + impl2.setName("Impl2"); + impl2 = implementationService.create(impl2, finalAlgo.getId()); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackage.getId(), impl2.getId()); + }); + } + + @Test + void findLinkedFile() { + ImplementationPackage implementationPackage = implementationPackageService.create(this.implementationPackage, implementation.getId()); + File file = implementationPackageService.addFileToImplementationPackage(implementationPackage.getId(), this.multipartFile); + + assertThat(file).isEqualToComparingFieldByField(implementationPackageService.findLinkedFile(implementationPackage.getId())); + } +} diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationServiceTest.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationServiceTest.java index 4c14dedd8..453f1c767 100644 --- a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationServiceTest.java +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/services/ImplementationServiceTest.java @@ -168,7 +168,6 @@ void updateImplementation() { assertThat(editedImplementation.getContributors()).isEqualTo(compareImplementation.getContributors()); assertThat(editedImplementation.getAssumptions()).isEqualTo(compareImplementation.getAssumptions()); assertThat(editedImplementation.getParameter()).isEqualTo(compareImplementation.getParameter()); - assertThat(editedImplementation.getLink()).isEqualTo(compareImplementation.getLink()); assertThat(editedImplementation.getDependencies()).isEqualTo(compareImplementation.getDependencies()); assertThat(editedImplementation.getImplementedAlgorithm().getId()) .isEqualTo(compareImplementation.getImplementedAlgorithm().getId()); @@ -380,10 +379,6 @@ private Implementation getFullImplementation(String name, Algorithm implementedA implementation.setProblemStatement("problemStatement"); implementation.setInputFormat("inputFormat"); implementation.setOutputFormat("outputFormat"); - try { - implementation.setLink(new URL("http://www.example.com")); - } catch (MalformedURLException ignored) { - } return implementation; } diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/CloudStorageTestConfiguration.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/CloudStorageTestConfiguration.java index c31fd1040..f86f1a932 100644 --- a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/CloudStorageTestConfiguration.java +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/CloudStorageTestConfiguration.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.core.util; import org.mockito.Mockito; diff --git a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/ServiceTestUtils.java b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/ServiceTestUtils.java index ee984b219..c4e7e9091 100644 --- a/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/ServiceTestUtils.java +++ b/org.planqk.atlas.core/src/test/java/org/planqk/atlas/core/util/ServiceTestUtils.java @@ -84,7 +84,6 @@ public static void assertImplementationEquality(Implementation implementation1, assertThat(implementation1.getContributors()).isEqualTo(implementation2.getContributors()); assertThat(implementation1.getAssumptions()).isEqualTo(implementation2.getAssumptions()); assertThat(implementation1.getParameter()).isEqualTo(implementation2.getParameter()); - assertThat(implementation1.getLink()).isEqualTo(implementation2.getLink()); assertThat(implementation1.getDependencies()).isEqualTo(implementation2.getDependencies()); assertThat(implementation1.getImplementedAlgorithm().getId()) .isEqualTo(implementation2.getImplementedAlgorithm().getId()); diff --git a/org.planqk.atlas.core/src/test/resources/application.properties b/org.planqk.atlas.core/src/test/resources/application.properties index 5e97dd6e5..66af54eca 100644 --- a/org.planqk.atlas.core/src/test/resources/application.properties +++ b/org.planqk.atlas.core/src/test/resources/application.properties @@ -1 +1,20 @@ +################################################################################ +# Copyright (c) 2020 the qc-atlas contributors. +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# Licensed 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. +################################################################################# + cloud.storage.implementation-files-bucket-name=${IMPLEMENTATION_FILES_BUCKET_NAME:planqk-algo-artifacts} diff --git a/org.planqk.atlas.core/src/test/resources/db-test.properties b/org.planqk.atlas.core/src/test/resources/db-test.properties index f4a7c31cd..629775540 100644 --- a/org.planqk.atlas.core/src/test/resources/db-test.properties +++ b/org.planqk.atlas.core/src/test/resources/db-test.properties @@ -16,7 +16,6 @@ # See the License for the specific language governing permissions and # limitations under the License. ################################################################################# -# These values are set by Testcontainers DO NOT MODIFY! spring.datasource.url=${DB_JDBC_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWORD} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/Constants.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/Constants.java index 81735070b..162ca09b4 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/Constants.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/Constants.java @@ -43,6 +43,8 @@ public final class Constants { public static final String FILES = "files"; + public static final String FILE = "file"; + public static final String COMPUTE_RESOURCE_PROPERTY_TYPES = "compute-resource-property-types"; public static final String DISCUSSION_COMMENTS = "discussion-comments"; @@ -51,6 +53,8 @@ public final class Constants { public static final String IMPLEMENTATIONS = "implementations"; + public static final String IMPLEMENTATION_PACKAGES = "implementation-packages"; + public static final String PATTERN_RELATIONS = "pattern-relations"; public static final String PATTERN_RELATION_TYPES = "pattern-relation-types"; @@ -110,6 +114,7 @@ public final class Constants { public static final String TAG_TAG = "tag"; + private Constants() { } } diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/controller/ImplementationController.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/controller/ImplementationController.java index c632e8c49..8c4075c22 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/controller/ImplementationController.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/controller/ImplementationController.java @@ -24,10 +24,12 @@ import org.planqk.atlas.core.model.ComputeResourceProperty; import org.planqk.atlas.core.model.File; import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; import org.planqk.atlas.core.model.Publication; import org.planqk.atlas.core.model.Tag; import org.planqk.atlas.core.services.ComputeResourcePropertyService; import org.planqk.atlas.core.services.FileService; +import org.planqk.atlas.core.services.ImplementationPackageService; import org.planqk.atlas.core.services.ImplementationService; import org.planqk.atlas.core.services.LinkingService; import org.planqk.atlas.core.services.PublicationService; @@ -40,12 +42,14 @@ import org.planqk.atlas.web.dtos.DiscussionTopicDto; import org.planqk.atlas.web.dtos.FileDto; import org.planqk.atlas.web.dtos.ImplementationDto; +import org.planqk.atlas.web.dtos.ImplementationPackageDto; import org.planqk.atlas.web.dtos.PublicationDto; import org.planqk.atlas.web.dtos.SoftwarePlatformDto; import org.planqk.atlas.web.dtos.TagDto; import org.planqk.atlas.web.linkassembler.ComputeResourcePropertyAssembler; import org.planqk.atlas.web.linkassembler.FileAssembler; import org.planqk.atlas.web.linkassembler.ImplementationAssembler; +import org.planqk.atlas.web.linkassembler.ImplementationPackageAssembler; import org.planqk.atlas.web.linkassembler.PublicationAssembler; import org.planqk.atlas.web.linkassembler.SoftwarePlatformAssembler; import org.planqk.atlas.web.linkassembler.TagAssembler; @@ -53,7 +57,6 @@ import org.planqk.atlas.web.utils.ListParametersDoc; import org.planqk.atlas.web.utils.ModelMapperUtils; import org.planqk.atlas.web.utils.ValidationGroups; -import org.springframework.data.domain.Page; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.PagedModel; @@ -117,62 +120,66 @@ public class ImplementationController { private final DiscussionTopicController discussionTopicController; + private final ImplementationPackageService implementationPackageService; + private final FileService fileService; private final FileAssembler fileAssembler; + private final ImplementationPackageAssembler implementationPackageAssembler; + @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400", description = "Bad Request. Invalid request body."), - @ApiResponse(responseCode = "404", - description = "Algorithm with given ID doesn't exist") + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400", description = "Bad Request. Invalid request body."), + @ApiResponse(responseCode = "404", + description = "Algorithm with given ID doesn't exist") }, description = "Define the basic properties of an implementation for an algorithm. " + - "References to sub-objects (e.g. a software platform) can be added via sub-routes " + - "(e.g. POST on /" + Constants.SOFTWARE_PLATFORMS + ").") + "References to sub-objects (e.g. a software platform) can be added via sub-routes " + + "(e.g. POST on /" + Constants.SOFTWARE_PLATFORMS + ").") @PostMapping public ResponseEntity> createImplementation( - @PathVariable UUID algorithmId, - @Validated(ValidationGroups.Create.class) @RequestBody ImplementationDto implementationDto) { + @PathVariable UUID algorithmId, + @Validated(ValidationGroups.Create.class) @RequestBody ImplementationDto implementationDto) { final Implementation savedImplementation = implementationService.create( - ModelMapperUtils.convert(implementationDto, Implementation.class), algorithmId); + ModelMapperUtils.convert(implementationDto, Implementation.class), algorithmId); return new ResponseEntity<>(implementationAssembler.toModel(savedImplementation), HttpStatus.CREATED); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Update the basic properties of an implementation (e.g. name). " + - "References to sub-objects (e.g. a software platform) are not updated via this operation - " + - "use the corresponding sub-route for updating them (e.g. PUT on /" + Constants.SOFTWARE_PLATFORMS + "/{softwarePlatformId}).\n") + "References to sub-objects (e.g. a software platform) are not updated via this operation - " + + "use the corresponding sub-route for updating them (e.g. PUT on /" + Constants.SOFTWARE_PLATFORMS + "/{softwarePlatformId}).\n") @PutMapping("/{implementationId}") public ResponseEntity> updateImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated(ValidationGroups.Update.class) @RequestBody ImplementationDto implementationDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.Update.class) @RequestBody ImplementationDto implementationDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); implementationDto.setId(implementationId); implementationDto.setImplementedAlgorithmId(algorithmId); final Implementation updatedImplementation = implementationService.update( - ModelMapperUtils.convert(implementationDto, Implementation.class)); + ModelMapperUtils.convert(implementationDto, Implementation.class)); return ResponseEntity.ok(implementationAssembler.toModel(updatedImplementation)); } @Operation(responses = { - @ApiResponse(responseCode = "204"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Delete an implementation. " + - "This also removes all references to other entities (e.g. software platforms).") + "This also removes all references to other entities (e.g. software platforms).") @DeleteMapping("/{implementationId}") public ResponseEntity deleteImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); implementationService.delete(implementationId); @@ -180,16 +187,16 @@ public ResponseEntity deleteImplementation( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Retrieve a specific implementation and its basic properties of an algorithm.") @GetMapping("/{implementationId}") public ResponseEntity> getImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var implementation = implementationService.findById(implementationId); @@ -197,15 +204,15 @@ public ResponseEntity> getImplementation( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Retrieve all tags associated with a specific implementation.") @GetMapping("/{implementationId}/" + Constants.TAGS) public ResponseEntity>> getTagsOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final Implementation implementation = implementationService.findById(implementationId); @@ -213,17 +220,17 @@ public ResponseEntity>> getTagsOfImplementat } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Add a tag to an implementation. The tag does not have to exist before adding it.") @PostMapping("/{implementationId}/" + Constants.TAGS) public ResponseEntity addTagToImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated(ValidationGroups.Create.class) @RequestBody TagDto tagDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.Create.class) @RequestBody TagDto tagDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); tagService.addTagToImplementation(implementationId, ModelMapperUtils.convert(tagDto, Tag.class)); @@ -231,17 +238,17 @@ public ResponseEntity addTagToImplementation( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs or Tag don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs or Tag don't exist.") }, description = "Remove a tag from an implementation.") @DeleteMapping("/{implementationId}/" + Constants.TAGS) public ResponseEntity removeTagFromImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated(ValidationGroups.IDOnly.class) @RequestBody TagDto tagDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.IDOnly.class) @RequestBody TagDto tagDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); tagService.removeTagFromImplementation(implementationId, ModelMapperUtils.convert(tagDto, Tag.class)); @@ -249,18 +256,18 @@ public ResponseEntity removeTagFromImplementation( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Retrieve referenced publications of an implementation. If none are found an empty list is returned.") @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.PUBLICATIONS) public ResponseEntity>> getPublicationsOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var publications = implementationService.findLinkedPublications(implementationId, listParameters.getPageable()); @@ -268,20 +275,20 @@ public ResponseEntity>> getPublicationsOf } @Operation(responses = { - @ApiResponse(responseCode = "204"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or publication with given IDs don't exist or " + - "reference was already added.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or publication with given IDs don't exist or " + + "reference was already added.") }, description = "Add a reference to an existing publication " + - "(that was previously created via a POST on e.g. /" + Constants.PUBLICATIONS + "). " + - "Only the ID is required in the request body, other attributes will be ignored and not changed.") + "(that was previously created via a POST on e.g. /" + Constants.PUBLICATIONS + "). " + + "Only the ID is required in the request body, other attributes will be ignored and not changed.") @PostMapping("/{implementationId}/" + Constants.PUBLICATIONS) public ResponseEntity linkImplementationAndPublication( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated({ValidationGroups.IDOnly.class}) @RequestBody PublicationDto publicationDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated({ValidationGroups.IDOnly.class}) @RequestBody PublicationDto publicationDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); linkingService.linkImplementationAndPublication(implementationId, publicationDto.getId()); @@ -289,20 +296,20 @@ public ResponseEntity linkImplementationAndPublication( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or publication with given IDs don't exist or " + - "no reference exists."), + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or publication with given IDs don't exist or " + + "no reference exists."), }, description = "Delete a reference to a publication of an implementation. " + - "The reference has to be previously created via a POST on /" + Constants.ALGORITHMS + "/{algorithmId}/" + - Constants.IMPLEMENTATIONS + "/{implementationId}/" + Constants.PUBLICATIONS + ").") + "The reference has to be previously created via a POST on /" + Constants.ALGORITHMS + "/{algorithmId}/" + + Constants.IMPLEMENTATIONS + "/{implementationId}/" + Constants.PUBLICATIONS + ").") @DeleteMapping("/{implementationId}/" + Constants.PUBLICATIONS + "/{publicationId}") public ResponseEntity unlinkImplementationAndPublication( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID publicationId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID publicationId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); linkingService.unlinkImplementationAndPublication(implementationId, publicationId); @@ -310,17 +317,17 @@ public ResponseEntity unlinkImplementationAndPublication( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or publication with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or publication with given IDs don't exist.") }, description = "Retrieve a specific publication of an implementation") @GetMapping("/{implementationId}/" + Constants.PUBLICATIONS + "/{publicationId}") public ResponseEntity> getPublicationOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID publicationId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID publicationId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final Publication publication = publicationService.findById(publicationId); @@ -328,18 +335,18 @@ public ResponseEntity> getPublicationOfImplementatio } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Retrieve referenced software platform for an implementation. If none are found an empty list is returned.") @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.SOFTWARE_PLATFORMS) public ResponseEntity>> getSoftwarePlatformsOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var softwarePlatforms = implementationService.findLinkedSoftwarePlatforms(implementationId, listParameters.getPageable()); @@ -347,20 +354,20 @@ public ResponseEntity>> getSoft } @Operation(responses = { - @ApiResponse(responseCode = "204"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist or " + - "reference was already added.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist or " + + "reference was already added.") }, description = "Add a reference to an existing software platform " + - "(that was previously created via a POST on e.g. /" + Constants.SOFTWARE_PLATFORMS + "). " + - "Only the ID is required in the request body, other attributes will be ignored and not changed.") + "(that was previously created via a POST on e.g. /" + Constants.SOFTWARE_PLATFORMS + "). " + + "Only the ID is required in the request body, other attributes will be ignored and not changed.") @PostMapping("/{implementationId}/" + Constants.SOFTWARE_PLATFORMS) public ResponseEntity linkImplementationAndSoftwarePlatform( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated({ValidationGroups.IDOnly.class}) @RequestBody SoftwarePlatformDto softwarePlatformDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated({ValidationGroups.IDOnly.class}) @RequestBody SoftwarePlatformDto softwarePlatformDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); linkingService.linkImplementationAndSoftwarePlatform(implementationId, softwarePlatformDto.getId()); @@ -368,20 +375,20 @@ public ResponseEntity linkImplementationAndSoftwarePlatform( } @Operation(responses = { - @ApiResponse(responseCode = "204"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist or " + - "no reference exists.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist or " + + "no reference exists.") }, description = "Delete a reference to a software platform of an implementation. " + - "The reference has to be previously created via a POST on /" + Constants.ALGORITHMS + "/{algorithmId}/" + - Constants.IMPLEMENTATIONS + "/{implementationId}/" + Constants.SOFTWARE_PLATFORMS + ").") + "The reference has to be previously created via a POST on /" + Constants.ALGORITHMS + "/{algorithmId}/" + + Constants.IMPLEMENTATIONS + "/{implementationId}/" + Constants.SOFTWARE_PLATFORMS + ").") @DeleteMapping("/{implementationId}/" + Constants.SOFTWARE_PLATFORMS + "/{softwarePlatformId}") public ResponseEntity unlinkImplementationAndSoftwarePlatform( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID softwarePlatformId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID softwarePlatformId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); linkingService.unlinkImplementationAndSoftwarePlatform(implementationId, softwarePlatformId); @@ -389,17 +396,17 @@ public ResponseEntity unlinkImplementationAndSoftwarePlatform( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist."), + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or software platform with given IDs don't exist."), }, description = "Retrieve a specific software platform and its basic properties of an implementation.") @GetMapping("/{implementationId}/" + Constants.SOFTWARE_PLATFORMS + "/{softwarePlatformId}") public ResponseEntity> getSoftwarePlatformOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID softwarePlatformId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID softwarePlatformId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var softwarePlatform = softwarePlatformService.findById(softwarePlatformId); @@ -407,63 +414,64 @@ public ResponseEntity> getSoftwarePlatformOfImp } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm or implementation with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm or implementation with given IDs don't exist.") }, description = "Retrieve referenced compute resource properties of an implementation. If none are found an empty list is returned.") @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.COMPUTE_RESOURCE_PROPERTIES) public ResponseEntity>> getComputeResourcePropertiesOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var resources = computeResourcePropertyService.findComputeResourcePropertiesOfImplementation( - implementationId, listParameters.getPageable()); + implementationId, listParameters.getPageable()); return ResponseEntity.ok(computeResourcePropertyAssembler.toModel(resources)); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or compute resource property type with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or compute resource property type with given IDs don't exist.") }, description = "Add a compute resource property (e.g. a certain number of qubits) that is required by an implementation. " + - "The compute resource property type has to be already created (e.g. via POST on /" + Constants.COMPUTE_RESOURCE_PROPERTY_TYPES + "). " + - "As a result only the ID is required for the compute resource property type, other attributes will be ignored not changed.") + "The compute resource property type has to be already created (e.g. via POST on /" + Constants.COMPUTE_RESOURCE_PROPERTY_TYPES + "). " + + "As a result only the ID is required for the compute resource property type, other attributes will be ignored not changed.") @PostMapping("/{implementationId}/" + Constants.COMPUTE_RESOURCE_PROPERTIES) public ResponseEntity> createComputeResourcePropertyForImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated(ValidationGroups.Create.class) @RequestBody ComputeResourcePropertyDto computeResourcePropertyDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.Create.class) @RequestBody ComputeResourcePropertyDto computeResourcePropertyDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var computeResourceProperty = ModelMapperUtils.convert(computeResourcePropertyDto, ComputeResourceProperty.class); final var createdComputeResourceProperty = computeResourcePropertyService - .addComputeResourcePropertyToImplementation(implementationId, computeResourceProperty); + .addComputeResourcePropertyToImplementation(implementationId, computeResourceProperty); return ResponseEntity.status(HttpStatus.CREATED).body(computeResourcePropertyAssembler.toModel(createdComputeResourceProperty)); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation, compute resource property or compute resource type with given IDs don't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. " + + "Algorithm, implementation, compute resource property or compute resource type with given IDs don't exist.") }, description = "Update a Compute resource property of an implementation. " + - "For the compute resource property type only the ID is required, " + - "other compute resource property type attributes will be ignored and not changed.") + "For the compute resource property type only the ID is required, " + + "other compute resource property type attributes will be ignored and not changed.") @PutMapping("/{implementationId}/" + Constants.COMPUTE_RESOURCE_PROPERTIES + "/{computeResourcePropertyId}") public ResponseEntity> updateComputeResourcePropertyOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID computeResourcePropertyId, - @Validated(ValidationGroups.Update.class) @RequestBody ComputeResourcePropertyDto computeResourcePropertyDto) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID computeResourcePropertyId, + @Validated(ValidationGroups.Update.class) @RequestBody ComputeResourcePropertyDto computeResourcePropertyDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); computeResourcePropertyService.checkIfComputeResourcePropertyIsOfImplementation(implementationId, computeResourcePropertyId); @@ -474,18 +482,18 @@ public ResponseEntity> updateComputeReso } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or compute resource property with given IDs don't exist."), + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or compute resource property with given IDs don't exist."), }, description = "Delete a Compute resource property of an implementation. " + - "The compute resource property type is not affected by this.") + "The compute resource property type is not affected by this.") @DeleteMapping("/{implementationId}/" + Constants.COMPUTE_RESOURCE_PROPERTIES + "/{computeResourcePropertyId}") public HttpEntity deleteComputeResourcePropertyOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID computeResourcePropertyId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID computeResourcePropertyId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); computeResourcePropertyService.checkIfComputeResourcePropertyIsOfImplementation(implementationId, computeResourcePropertyId); @@ -494,17 +502,17 @@ public HttpEntity deleteComputeResourcePropertyOfImplementation( } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400", - description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), - @ApiResponse(responseCode = "404", - description = "Not Found. Algorithm, implementation or compute resource property with given IDs don't exist."), + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", + description = "Bad Request. Invalid request body or algorithm resource is not implemented algorithm of implementation."), + @ApiResponse(responseCode = "404", + description = "Not Found. Algorithm, implementation or compute resource property with given IDs don't exist."), }, description = "Retrieve a specific compute resource property of an implementation.") @GetMapping("/{implementationId}/" + Constants.COMPUTE_RESOURCE_PROPERTIES + "/{computeResourcePropertyId}") public HttpEntity> getComputeResourcePropertyOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID computeResourcePropertyId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID computeResourcePropertyId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); computeResourcePropertyService.checkIfComputeResourcePropertyIsOfImplementation(implementationId, computeResourcePropertyId); @@ -513,278 +521,373 @@ public HttpEntity> getComputeResourcePro } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation with given ID doesn't exist.") }, description = "Retrieve discussion topics of an implementation of an algorithm. If none are found an empty list is returned." ) @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS) public HttpEntity>> getDiscussionTopicsOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.getDiscussionTopics(implementationId, listParameters); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Retrieve discussion topic of an implementation of an algorithm." ) @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}") public HttpEntity> getDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.getDiscussionTopic(implementationId, topicId); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Delete discussion topic of an implementation of an algorithm." ) @ListParametersDoc @DeleteMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}") public HttpEntity deleteDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.deleteDiscussionTopic(implementationId, topicId); } @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Create a discussion topic of an implementation of an algorithm." ) @ListParametersDoc @PostMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS) public HttpEntity> createDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Validated(ValidationGroups.Create.class) @RequestBody DiscussionTopicDto discussionTopicDto, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.Create.class) @RequestBody DiscussionTopicDto discussionTopicDto, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var implementation = implementationService.findById(implementationId); return discussionTopicController.createDiscussionTopic(implementation, discussionTopicDto); } @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Update discussion topic of an implementation of an algorithm." ) @ListParametersDoc @PutMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}") public HttpEntity> updateDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @Validated(ValidationGroups.Update.class) @RequestBody DiscussionTopicDto discussionTopicDto, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @Validated(ValidationGroups.Update.class) @RequestBody DiscussionTopicDto discussionTopicDto, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); final var implementation = implementationService.findById(implementationId); return discussionTopicController.updateDiscussionTopic(implementation, topicId, discussionTopicDto); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Retrieve discussion comments of a discussion topic of an implementation of an algorithm." + - " If none are found an empty list is returned." + " If none are found an empty list is returned." ) @ListParametersDoc @GetMapping("/{implementationId}/" + - Constants.DISCUSSION_TOPICS + "/{topicId}/" + Constants.DISCUSSION_COMMENTS) + Constants.DISCUSSION_TOPICS + "/{topicId}/" + Constants.DISCUSSION_COMMENTS) public HttpEntity>> getDiscussionCommentsOfDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.getDiscussionComments(implementationId, topicId, listParameters); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation, discussion topic or discussion comment with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation, discussion topic or discussion comment with given ID doesn't exist.") }, description = "Retrieve discussion comment of a discussion topic of an implementation of an algorithm." ) @ListParametersDoc @GetMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}/" + - Constants.DISCUSSION_COMMENTS + "/{commentId}") + Constants.DISCUSSION_COMMENTS + "/{commentId}") public HttpEntity> getDiscussionCommentOfDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @PathVariable UUID commentId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @PathVariable UUID commentId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.getDiscussionComment(implementationId, topicId, commentId); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation, discussion topic or discussion comment with given ID doesn't exist.") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation, discussion topic or discussion comment with given ID doesn't exist.") }, description = "Delete discussion comment of a discussion topic of an implementation of an algorithm." ) @ListParametersDoc @DeleteMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}/" + - Constants.DISCUSSION_COMMENTS + "/{commentId}") + Constants.DISCUSSION_COMMENTS + "/{commentId}") public HttpEntity deleteDiscussionCommentOfDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @PathVariable UUID commentId, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @PathVariable UUID commentId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.deleteDiscussionComment(implementationId, topicId, commentId); } @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Create discussion comment of a discussion topic of an implementation of an algorithm." ) @ListParametersDoc @PostMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}/" + - Constants.DISCUSSION_COMMENTS) + Constants.DISCUSSION_COMMENTS) public HttpEntity> createDiscussionCommentOfDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @Validated(ValidationGroups.Create.class) @RequestBody DiscussionCommentDto discussionCommentDto, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @Validated(ValidationGroups.Create.class) @RequestBody DiscussionCommentDto discussionCommentDto, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.createDiscussionComment(implementationId, topicId, discussionCommentDto); } @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "Not Found. implementation or discussion topic with given ID doesn't exist.") + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or discussion topic with given ID doesn't exist.") }, description = "Update discussion comment of a discussion topic of an implementation of an algorithm." ) @ListParametersDoc @PutMapping("/{implementationId}/" + Constants.DISCUSSION_TOPICS + "/{topicId}/" + - Constants.DISCUSSION_COMMENTS + "/{commentId}") + Constants.DISCUSSION_COMMENTS + "/{commentId}") public HttpEntity> updateDiscussionCommentOfDiscussionTopicOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID topicId, - @PathVariable UUID commentId, - @Validated(ValidationGroups.Update.class) @RequestBody DiscussionCommentDto discussionCommentDto, - @Parameter(hidden = true) ListParameters listParameters) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID topicId, + @PathVariable UUID commentId, + @Validated(ValidationGroups.Update.class) @RequestBody DiscussionCommentDto discussionCommentDto, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); return discussionTopicController.updateDiscussionComment(implementationId, topicId, commentId, discussionCommentDto); } @Operation(responses = { - @ApiResponse(responseCode = "201"), - @ApiResponse(responseCode = "400", description = "Bad Request. Invalid request body."), - }, description = "Uploads and adds a file to a given implementation") - @PostMapping(value = "/{implementationId}/" + Constants.FILES, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity> createFileForImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @RequestParam("file") MultipartFile multipartFile) { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation with given ID doesn't exist.") + }, description = "Retrieve discussion topics of an implementation of an algorithm. If none are found an empty list is returned." + ) + @ListParametersDoc + @GetMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES) + public ResponseEntity>> getImplementationPackagesOfImplementation( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Parameter(hidden = true) ListParameters listParameters) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); - final File file = implementationService.addFileToImplementation(implementationId, multipartFile); - return ResponseEntity.status(HttpStatus.CREATED).body(fileAssembler.toModel(file)); + final var packages = + implementationPackageService.findImplementationPackagesByImplementationId(implementationId, listParameters.getPageable()); + return ResponseEntity.ok(implementationPackageAssembler.toModel(packages)); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - }, description = "Retrieve all files of an implementation") - @GetMapping("/{implementationId}/" + Constants.FILES) - public ResponseEntity>> getAllFilesOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @Parameter(hidden = true) ListParameters listParameters - ) { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation with given ID doesn't exist.") + }, description = "Retrieve implementation package of an implementation of an algorithm." + ) + @GetMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}") + public ResponseEntity> getImplementationPackageOfImplementation( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId) { + implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); + final var implementationPackage = + implementationPackageService.findById(implementationPackageId); + return ResponseEntity.ok(implementationPackageAssembler.toModel(implementationPackage)); + } + + @Operation(responses = { + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or implementation package with given ID doesn't exist.") + }, description = "Create a implementation package of an implementation of an algorithm." + ) + @PostMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES) + public HttpEntity> createImplementationPackageOfImplementation( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @Validated(ValidationGroups.Create.class) @RequestBody ImplementationPackageDto implementationPackageDto) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); - final Page files = - implementationService.findLinkedFiles(implementationId, listParameters.getPageable()); - return ResponseEntity.ok(fileAssembler.toModel(files)); + final ImplementationPackage implementationP = ModelMapperUtils.convert(implementationPackageDto, ImplementationPackage.class); + final ImplementationPackage implementationPackageToSave = + implementationPackageService.create(implementationP, implementationId); + return new ResponseEntity<>(implementationPackageAssembler.toModel(implementationPackageToSave), HttpStatus.CREATED); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", - description = "File of Implementation with given ID doesn't exist") - }, description = "Retrieves a specific file of an Implementation and its basic properties.") - @GetMapping("/{implementationId}/" + Constants.FILES + "/{fileId}") - public ResponseEntity> getFileOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID fileId + @ApiResponse(responseCode = "201"), + @ApiResponse(responseCode = "400", description = "Bad Request. Invalid request body."), + }, description = "Uploads and adds a file to a given implementation") + @PostMapping(value = "/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}/" + + Constants.FILE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity> createFileForImplementationPackage( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId, + @RequestParam("file") MultipartFile multipartFile) { + implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); + final File file = implementationPackageService.addFileToImplementationPackage(implementationPackageId, multipartFile); + return ResponseEntity.status(HttpStatus.CREATED).body(fileAssembler.toModel(file)); + } + + @Operation(responses = { + @ApiResponse(responseCode = "200"), + }, description = "Retrieve the file of an implementation package") + @GetMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}/" + Constants.FILE) + public ResponseEntity> getFileOfImplementationPackage( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId ) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); final File file = - fileService.findById(fileId); + implementationPackageService.findLinkedFile(implementationPackageId); return ResponseEntity.ok(fileAssembler.toModel(file)); } @Operation(responses = { - @ApiResponse(responseCode = "200"), - @ApiResponse(responseCode = "404", - description = "File of Implementation with given ID doesn't exist") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "404", + description = "File of Implementation with given ID doesn't exist") }, description = "Downloads a specific file content of an Implementation") - @GetMapping("/{implementationId}/" + Constants.FILES + "/{fileId}/content") + @GetMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}/" + Constants.FILE + "/content") public ResponseEntity downloadFileContent( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID fileId + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId ) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); final File file = - fileService.findById(fileId); + implementationPackageService.findLinkedFile(implementationPackageId); + if (file == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } return ResponseEntity - .ok() - .contentType(MediaType.parseMediaType(file.getMimeType())) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName()) - .body(fileService.getFileContent(fileId)); + .ok() + .contentType(MediaType.parseMediaType(file.getMimeType())) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName()) + .body(fileService.getFileContent(file.getId())); } @Operation(responses = { - @ApiResponse(responseCode = "204"), - @ApiResponse(responseCode = "400"), - @ApiResponse(responseCode = "404", description = "Not Found. Implementation or File with given IDs don't exist") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", description = "Not Found. Implementation or File with given IDs don't exist") }, description = "Delete a file of an implementation.") - @DeleteMapping("/{implementationId}/" + Constants.FILES + "/{fileId}") + @DeleteMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}/" + Constants.FILE) public ResponseEntity deleteFileOfImplementation( - @PathVariable UUID algorithmId, - @PathVariable UUID implementationId, - @PathVariable UUID fileId) { + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId) { implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); - fileService.delete(fileId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); + final File file = + implementationPackageService.findLinkedFile(implementationPackageId); + if (file == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + final ImplementationPackage implementationPackage = implementationPackageService.findById(implementationPackageId); + implementationPackage.setFile(null); + fileService.delete(file.getId()); + implementationPackageService.update(implementationPackage); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Operation(responses = { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation or implementation package with given ID doesn't exist.") + }, description = "Update implementation package of an implementation of an algorithm." + ) + @PutMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}") + public HttpEntity> updateImplementationPackageOfImplementation( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId, + @Validated(ValidationGroups.Update.class) @RequestBody ImplementationPackageDto implementationPackageDto) { + implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); + final ImplementationPackage implementationP = ModelMapperUtils.convert(implementationPackageDto, ImplementationPackage.class); + final ImplementationPackage implementationPackageToUpdate = + implementationPackageService.update(implementationP); + return new ResponseEntity<>(implementationPackageAssembler.toModel(implementationPackageToUpdate), HttpStatus.OK); + } + + @Operation(responses = { + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "400"), + @ApiResponse(responseCode = "404", + description = "Not Found. implementation, implementation package with given ID doesn't exist.") + }, description = "Delete implementation package of an implementation of an algorithm." + ) + @DeleteMapping("/{implementationId}/" + Constants.IMPLEMENTATION_PACKAGES + "/{implementationPackageId}") + public HttpEntity deleteImplementationPackageOfImplementation( + @PathVariable UUID algorithmId, + @PathVariable UUID implementationId, + @PathVariable UUID implementationPackageId) { + implementationService.checkIfImplementationIsOfAlgorithm(implementationId, algorithmId); + implementationPackageService.checkIfImplementationPackageIsLinkedToImplementation(implementationPackageId, implementationId); + implementationPackageService.delete(implementationPackageId); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } } diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileDto.java index 21a9f756c..27b6d896f 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileDto.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileDto.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.dtos; import java.util.UUID; diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileImplementationPackageDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileImplementationPackageDto.java new file mode 100644 index 000000000..bbd27eb0a --- /dev/null +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FileImplementationPackageDto.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.dtos; + +import org.planqk.atlas.core.model.ImplementationPackageType; +import org.springframework.hateoas.server.core.Relation; + +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Data +@JsonTypeName("FILE") +@Relation(itemRelation = "implementationPackage", collectionRelation = "implementationPackages") +public class FileImplementationPackageDto extends ImplementationPackageDto { + + @Override + @Schema(type = "string", allowableValues = {"FILE"}) + public ImplementationPackageType getPackageType() { + return super.getPackageType(); + } +} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FunctionImplementationPackageDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FunctionImplementationPackageDto.java new file mode 100644 index 000000000..acabe1c16 --- /dev/null +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/FunctionImplementationPackageDto.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.dtos; + + +import org.planqk.atlas.core.model.ImplementationPackageType; +import org.springframework.hateoas.server.core.Relation; + +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Data +@JsonTypeName("FUNCTION") +@Relation(itemRelation = "implementationPackage", collectionRelation = "implementationPackages") +public class FunctionImplementationPackageDto extends ImplementationPackageDto { + @Override + @Schema(type = "string", allowableValues = {"FUNCTION"}) + public ImplementationPackageType getPackageType() { + return super.getPackageType(); + } +} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationDto.java index 1d3edd5aa..ecc9eec8f 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationDto.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationDto.java @@ -19,7 +19,6 @@ package org.planqk.atlas.web.dtos; -import java.net.URL; import java.util.Set; import java.util.UUID; import javax.validation.constraints.NotNull; @@ -29,7 +28,6 @@ import org.planqk.atlas.web.utils.ValidationGroups; import org.springframework.hateoas.server.core.Relation; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -53,9 +51,6 @@ public class ImplementationDto implements Identifyable { message = "Implementation-Name must not be null!") private String name; - @Schema(description = "URL of implementation", example = "http://www.github.com/planqk", required = false) - private URL link; - private String inputFormat; private String outputFormat; diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationPackageDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationPackageDto.java new file mode 100644 index 000000000..477ac8b23 --- /dev/null +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/ImplementationPackageDto.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.dtos; + +import java.util.UUID; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; + +import org.planqk.atlas.core.model.ImplementationPackageType; +import org.planqk.atlas.web.utils.Identifyable; +import org.planqk.atlas.web.utils.ValidationGroups; +import org.springframework.hateoas.server.core.Relation; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "packageType", visible = true) +@JsonSubTypes({@JsonSubTypes.Type(value = FileImplementationPackageDto.class, name = "FILE"), + @JsonSubTypes.Type(value = TOSCAImplementationPackageDto.class, name = "TOSCA"), + @JsonSubTypes.Type(value = FunctionImplementationPackageDto.class, name = "FUNCTION")}) +@Relation(itemRelation = "implementationPackage", collectionRelation = "implementationPackages") +public class ImplementationPackageDto implements Identifyable { + + @NotNull(groups = {ValidationGroups.IDOnly.class}, message = "An id is required to perform an update") + @Null(groups = {ValidationGroups.Create.class}, message = "The id must be null for creating an implementation package") + private UUID id; + + private String name; + + private String description; + + @NotNull(groups = {ValidationGroups.Update.class, ValidationGroups.Create.class}, + message = "PackageType must not be null!") + private ImplementationPackageType packageType; +} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/TOSCAImplementationPackageDto.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/TOSCAImplementationPackageDto.java new file mode 100644 index 000000000..9de2e349a --- /dev/null +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/dtos/TOSCAImplementationPackageDto.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.dtos; + +import org.planqk.atlas.core.model.ImplementationPackageType; +import org.springframework.hateoas.server.core.Relation; + +import com.fasterxml.jackson.annotation.JsonTypeName; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Data +@JsonTypeName("TOSCA") +@Relation(itemRelation = "implementationPackage", collectionRelation = "implementationPackages") +public class TOSCAImplementationPackageDto extends ImplementationPackageDto { + @Override + @Schema(type = "string", allowableValues = {"TOSCA"}) + public ImplementationPackageType getPackageType() { + return super.getPackageType(); + } +} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/FileAssembler.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/FileAssembler.java index 35a11f573..6eddd162d 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/FileAssembler.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/FileAssembler.java @@ -1,3 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.linkassembler; import org.planqk.atlas.web.dtos.FileDto; diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/ImplementationPackageAssembler.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/ImplementationPackageAssembler.java new file mode 100644 index 000000000..7813ab77f --- /dev/null +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/linkassembler/ImplementationPackageAssembler.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020 the qc-atlas contributors. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed 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.planqk.atlas.web.linkassembler; + +import java.util.UUID; + +import org.planqk.atlas.web.dtos.ImplementationPackageDto; +import org.springframework.hateoas.EntityModel; +import org.springframework.stereotype.Component; + +@Component +public class ImplementationPackageAssembler extends GenericLinkAssembler { + + @Override + public void addLinks(EntityModel resource) { + } + + private UUID getID(EntityModel resource) { + return resource.getContent().getId(); + } + +} diff --git a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/utils/ModelMapperUtils.java b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/utils/ModelMapperUtils.java index a31505978..0c78553d9 100644 --- a/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/utils/ModelMapperUtils.java +++ b/org.planqk.atlas.web/src/main/java/org/planqk/atlas/web/utils/ModelMapperUtils.java @@ -26,20 +26,28 @@ import org.planqk.atlas.core.model.AlgorithmRelation; import org.planqk.atlas.core.model.ClassicAlgorithm; import org.planqk.atlas.core.model.ComputeResource; +import org.planqk.atlas.core.model.FileImplementationPackage; +import org.planqk.atlas.core.model.FunctionImplementationPackage; import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; import org.planqk.atlas.core.model.PatternRelation; import org.planqk.atlas.core.model.Qpu; import org.planqk.atlas.core.model.QuantumAlgorithm; import org.planqk.atlas.core.model.Simulator; +import org.planqk.atlas.core.model.TOSCAImplementationPackage; import org.planqk.atlas.web.dtos.AlgorithmDto; import org.planqk.atlas.web.dtos.AlgorithmRelationDto; import org.planqk.atlas.web.dtos.ClassicAlgorithmDto; import org.planqk.atlas.web.dtos.ComputeResourceDto; +import org.planqk.atlas.web.dtos.FileImplementationPackageDto; +import org.planqk.atlas.web.dtos.FunctionImplementationPackageDto; import org.planqk.atlas.web.dtos.ImplementationDto; +import org.planqk.atlas.web.dtos.ImplementationPackageDto; import org.planqk.atlas.web.dtos.PatternRelationDto; import org.planqk.atlas.web.dtos.QPUDto; import org.planqk.atlas.web.dtos.QuantumAlgorithmDto; import org.planqk.atlas.web.dtos.SimulatorDto; +import org.planqk.atlas.web.dtos.TOSCAImplementationPackageDto; import org.springframework.data.domain.Page; import lombok.NonNull; @@ -67,45 +75,58 @@ private static ModelMapper initModelMapper() { return mapper; } + private static void initializeConverters(ModelMapper mapper) { mapper.createTypeMap(ClassicAlgorithm.class, AlgorithmDto.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), ClassicAlgorithmDto.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), ClassicAlgorithmDto.class)); mapper.createTypeMap(QuantumAlgorithm.class, AlgorithmDto.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QuantumAlgorithmDto.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QuantumAlgorithmDto.class)); mapper.createTypeMap(ClassicAlgorithmDto.class, Algorithm.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), ClassicAlgorithm.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), ClassicAlgorithm.class)); mapper.createTypeMap(QuantumAlgorithmDto.class, Algorithm.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QuantumAlgorithm.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QuantumAlgorithm.class)); + mapper.createTypeMap(FileImplementationPackage.class, ImplementationPackageDto.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), FileImplementationPackageDto.class)); + mapper.createTypeMap(TOSCAImplementationPackage.class, ImplementationPackageDto.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), TOSCAImplementationPackageDto.class)); + mapper.createTypeMap(FunctionImplementationPackage.class, ImplementationPackageDto.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), FunctionImplementationPackageDto.class)); + mapper.createTypeMap(FileImplementationPackageDto.class, ImplementationPackage.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), FileImplementationPackage.class)); + mapper.createTypeMap(TOSCAImplementationPackageDto.class, ImplementationPackage.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), TOSCAImplementationPackage.class)); + mapper.createTypeMap(FunctionImplementationPackageDto.class, ImplementationPackage.class) + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), FunctionImplementationPackage.class)); mapper.createTypeMap(Qpu.class, ComputeResourceDto.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QPUDto.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), QPUDto.class)); mapper.createTypeMap(Simulator.class, ComputeResourceDto.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), SimulatorDto.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), SimulatorDto.class)); mapper.createTypeMap(QPUDto.class, ComputeResource.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), Qpu.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), Qpu.class)); mapper.createTypeMap(SimulatorDto.class, ComputeResource.class) - .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), Simulator.class)); + .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), Simulator.class)); } private static void initializeUUIDMappings(ModelMapper mapper) { // Algorithm Relations mapper.createTypeMap(AlgorithmRelation.class, AlgorithmRelationDto.class) - .addMapping(e -> e.getSourceAlgorithm().getId(), AlgorithmRelationDto::setSourceAlgorithmId) - .addMapping(e -> e.getTargetAlgorithm().getId(), AlgorithmRelationDto::setTargetAlgorithmId); + .addMapping(e -> e.getSourceAlgorithm().getId(), AlgorithmRelationDto::setSourceAlgorithmId) + .addMapping(e -> e.getTargetAlgorithm().getId(), AlgorithmRelationDto::setTargetAlgorithmId); mapper.createTypeMap(AlgorithmRelationDto.class, AlgorithmRelation.class) - .addMapping(e -> newAlgorithmWithId(e.getSourceAlgorithmId()), AlgorithmRelation::setSourceAlgorithm) - .addMapping(e -> newAlgorithmWithId(e.getTargetAlgorithmId()), AlgorithmRelation::setTargetAlgorithm); + .addMapping(e -> newAlgorithmWithId(e.getSourceAlgorithmId()), AlgorithmRelation::setSourceAlgorithm) + .addMapping(e -> newAlgorithmWithId(e.getTargetAlgorithmId()), AlgorithmRelation::setTargetAlgorithm); // Implementations mapper.createTypeMap(Implementation.class, ImplementationDto.class) - .addMapping(e -> e.getImplementedAlgorithm().getId(), ImplementationDto::setImplementedAlgorithmId); + .addMapping(e -> e.getImplementedAlgorithm().getId(), ImplementationDto::setImplementedAlgorithmId); mapper.createTypeMap(ImplementationDto.class, Implementation.class) - .addMapping(e -> newAlgorithmWithId(e.getImplementedAlgorithmId()), Implementation::setImplementedAlgorithm); + .addMapping(e -> newAlgorithmWithId(e.getImplementedAlgorithmId()), Implementation::setImplementedAlgorithm); // Pattern Relations mapper.createTypeMap(PatternRelation.class, PatternRelationDto.class) - .addMapping(e -> e.getAlgorithm().getId(), PatternRelationDto::setAlgorithmId); + .addMapping(e -> e.getAlgorithm().getId(), PatternRelationDto::setAlgorithmId); mapper.createTypeMap(PatternRelationDto.class, PatternRelation.class) - .addMapping(e -> newAlgorithmWithId(e.getAlgorithmId()), PatternRelation::setAlgorithm); + .addMapping(e -> newAlgorithmWithId(e.getAlgorithmId()), PatternRelation::setAlgorithm); } private static Algorithm newAlgorithmWithId(UUID id) { diff --git a/org.planqk.atlas.web/src/test/java/org/planqk/atlas/web/controller/ImplementationControllerTest.java b/org.planqk.atlas.web/src/test/java/org/planqk/atlas/web/controller/ImplementationControllerTest.java index 09272a6ae..e1438b80d 100644 --- a/org.planqk.atlas.web/src/test/java/org/planqk/atlas/web/controller/ImplementationControllerTest.java +++ b/org.planqk.atlas.web/src/test/java/org/planqk/atlas/web/controller/ImplementationControllerTest.java @@ -58,15 +58,20 @@ import org.planqk.atlas.core.model.DiscussionComment; import org.planqk.atlas.core.model.DiscussionTopic; import org.planqk.atlas.core.model.File; +import org.planqk.atlas.core.model.FileImplementationPackage; import org.planqk.atlas.core.model.Implementation; +import org.planqk.atlas.core.model.ImplementationPackage; +import org.planqk.atlas.core.model.ImplementationPackageType; import org.planqk.atlas.core.model.Publication; import org.planqk.atlas.core.model.SoftwarePlatform; import org.planqk.atlas.core.model.Status; +import org.planqk.atlas.core.model.TOSCAImplementationPackage; import org.planqk.atlas.core.model.Tag; import org.planqk.atlas.core.services.ComputeResourcePropertyService; import org.planqk.atlas.core.services.DiscussionCommentService; import org.planqk.atlas.core.services.DiscussionTopicService; import org.planqk.atlas.core.services.FileService; +import org.planqk.atlas.core.services.ImplementationPackageService; import org.planqk.atlas.core.services.ImplementationService; import org.planqk.atlas.core.services.LinkingService; import org.planqk.atlas.core.services.PublicationService; @@ -78,6 +83,7 @@ import org.planqk.atlas.web.dtos.DiscussionCommentDto; import org.planqk.atlas.web.dtos.DiscussionTopicDto; import org.planqk.atlas.web.dtos.ImplementationDto; +import org.planqk.atlas.web.dtos.ImplementationPackageDto; import org.planqk.atlas.web.dtos.PublicationDto; import org.planqk.atlas.web.dtos.SoftwarePlatformDto; import org.planqk.atlas.web.dtos.TagDto; @@ -122,6 +128,10 @@ public class ImplementationControllerTest { @MockBean private ImplementationService implementationService; + @MockBean + private ImplementationPackageService implementationPackageService; + + @MockBean private ComputeResourcePropertyService computeResourcePropertyService; @@ -256,14 +266,14 @@ void createImplementation_returnOk() { doReturn(impl).when(implementationService).create(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createImplementation(algo.getId(), null)); + .createImplementation(algo.getId(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(jsonPath("$.id").value(impl.getId().toString())) - .andExpect(jsonPath("$.name").value(impl.getName())) - .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) - .andExpect(status().isCreated()); + .andExpect(jsonPath("$.name").value(impl.getName())) + .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) + .andExpect(status().isCreated()); } @Test @@ -273,10 +283,10 @@ void createImplementation_returnBadRequest() { implDto.setName(null); implDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createImplementation(UUID.randomUUID(), null)); + .createImplementation(UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(status().isBadRequest()); } @@ -289,10 +299,10 @@ void createImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).create(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createImplementation(UUID.randomUUID(), null)); + .createImplementation(UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(status().isNotFound()); } @@ -314,14 +324,14 @@ void updateImplementation_returnOk() { doReturn(impl).when(implementationService).update(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateImplementation(algo.getId(), UUID.randomUUID(), null)); + .updateImplementation(algo.getId(), UUID.randomUUID(), null)); mockMvc.perform(put(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(jsonPath("$.id").value(impl.getId().toString())) - .andExpect(jsonPath("$.name").value(impl.getName())) - .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) - .andExpect(status().isOk()); + .andExpect(jsonPath("$.name").value(impl.getName())) + .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) + .andExpect(status().isOk()); } @Test @@ -331,10 +341,10 @@ void updateImplementation_returnBadRequest() { implDto.setName(null); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .updateImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(put(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(status().isBadRequest()); } @@ -347,10 +357,10 @@ void updateImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).update(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .updateImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(put(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(implDto)) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implDto)) ).andExpect(status().isNotFound()); } @@ -360,9 +370,9 @@ void deleteImplementation_returnNoContent() { doNothing().when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); doNothing().when(implementationService).delete(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteImplementation(UUID.randomUUID(), UUID.randomUUID())); + .deleteImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .andExpect(status().isNoContent()); } @Test @@ -370,9 +380,9 @@ void deleteImplementation_returnNoContent() { void deleteImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteImplementation(UUID.randomUUID(), UUID.randomUUID())); + .deleteImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -391,10 +401,10 @@ void getTagsOfImplementation_EmptyList_returnOk() { doReturn(impl).when(implementationService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); + .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$").isEmpty()) - .andExpect(status().isOk()); + .andExpect(jsonPath("$").isEmpty()) + .andExpect(status().isOk()); } @Test @@ -416,12 +426,12 @@ void getTagsOfImplementation_SingleElementList_returnOk() { doReturn(impl).when(implementationService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); + .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$._embedded.tags").isArray()) - .andExpect(jsonPath("$._embedded.tags[0].value").value(tag.getValue())) - .andExpect(jsonPath("$._embedded.tags[0].category").value(tag.getCategory())) - .andExpect(status().isOk()); + .andExpect(jsonPath("$._embedded.tags").isArray()) + .andExpect(jsonPath("$._embedded.tags[0].value").value(tag.getValue())) + .andExpect(jsonPath("$._embedded.tags[0].category").value(tag.getCategory())) + .andExpect(status().isOk()); } @Test @@ -429,9 +439,9 @@ void getTagsOfImplementation_SingleElementList_returnOk() { void getTagsOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); + .getTagsOfImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -445,11 +455,11 @@ void addTagToImplementation_returnCreated() { tagDto.setValue("test-v"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isCreated()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isCreated()); } @Test @@ -460,11 +470,11 @@ void addTagToImplementation_returnBadRequest() { tagDto.setValue(null); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isBadRequest()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isBadRequest()); } @Test @@ -477,11 +487,11 @@ void addTagToImplementation_returnNotFound() { tagDto.setValue("test-v"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .addTagToImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isNotFound()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isNotFound()); } @Test @@ -495,11 +505,11 @@ void removeTagFromImplementation_returnNoContent() { tagDto.setValue("test-v"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(delete(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isNoContent()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isNoContent()); } @Test @@ -510,11 +520,11 @@ void removeTagFromImplementation_returnBadRequest() { tagDto.setValue(null); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(delete(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isBadRequest()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isBadRequest()); } @Test @@ -527,11 +537,11 @@ void removeTagFromImplementation_NoImplementation_returnNotFound() { tagDto.setValue("test-v"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(delete(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isNotFound()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isNotFound()); } @Test @@ -545,11 +555,11 @@ void removeTagFromImplementation_NoTag_returnNotFound() { tagDto.setValue("test-v"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .removeTagFromImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(delete(url).accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(tagDto))) - .andExpect(status().isNotFound()); + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(tagDto))) + .andExpect(status().isNotFound()); } @Test @@ -567,12 +577,12 @@ void getImplementation_returnOk() { doReturn(impl).when(implementationService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getImplementation(algo.getId(), impl.getId())); + .getImplementation(algo.getId(), impl.getId())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(impl.getId().toString())) - .andExpect(jsonPath("$.name").value(impl.getName())) - .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) - .andExpect(status().isOk()); + .andExpect(jsonPath("$.id").value(impl.getId().toString())) + .andExpect(jsonPath("$.name").value(impl.getName())) + .andExpect(jsonPath("$.implementedAlgorithmId").value(algo.getId().toString())) + .andExpect(status().isOk()); } @Test @@ -581,9 +591,9 @@ void getImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getImplementation(UUID.randomUUID(), UUID.randomUUID())); + .getImplementation(UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -593,10 +603,10 @@ void getPublicationsOfImplementation_EmptyList_returnOk() { doReturn(new PageImpl<>(List.of())).when(implementationService).findLinkedPublications(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.publications").doesNotExist()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.publications").doesNotExist()) ; } @@ -612,11 +622,11 @@ void getPublicationsOfImplementation_SingleElement_returnOk() { doReturn(new PageImpl<>(List.of(pub))).when(implementationService).findLinkedPublications(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.publications").isArray()) - .andExpect(jsonPath("$._embedded.publications[0].id").value(pub.getId().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.publications").isArray()) + .andExpect(jsonPath("$._embedded.publications[0].id").value(pub.getId().toString())) ; } @@ -626,9 +636,9 @@ void getPublicationsOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getPublicationsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -643,13 +653,13 @@ void getPublicationOfImplementation_returnOk() { doReturn(pub).when(publicationService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getPublicationOfImplementation(UUID.randomUUID(), UUID.randomUUID(), pub.getId())); + .getPublicationOfImplementation(UUID.randomUUID(), UUID.randomUUID(), pub.getId())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.title").value(pub.getTitle())) - .andExpect(jsonPath("$.id").value(pub.getId().toString())) - .andExpect(jsonPath("$.authors").isArray()) - .andExpect(jsonPath("$.authors[0]").value(pub.getAuthors().get(0))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.title").value(pub.getTitle())) + .andExpect(jsonPath("$.id").value(pub.getId().toString())) + .andExpect(jsonPath("$.authors").isArray()) + .andExpect(jsonPath("$.authors[0]").value(pub.getAuthors().get(0))) ; } @@ -659,9 +669,9 @@ void getPublicationOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getPublicationOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .getPublicationOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -674,10 +684,10 @@ void linkImplementationAndPublication_returnNoContent() { pubDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNoContent()); } @Test @@ -687,10 +697,10 @@ void linkImplementationAndPublication_returnBadRequest() { pubDto.setId(null); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()); + .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()); } @Test @@ -702,10 +712,10 @@ void linkImplementationAndPublication_UnknownAlgorithm_returnNotFound() { pubDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test @@ -718,10 +728,10 @@ void linkImplementationAndPublication_UnknownPublication_returnNotFound() { pubDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(mapper.writeValueAsString(pubDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test @@ -731,9 +741,9 @@ void unlinkImplementationAndPublication_returnNoContent() { doNothing().when(linkingService).unlinkImplementationAndPublication(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .andExpect(status().isNoContent()); } @Test @@ -742,9 +752,9 @@ void unlinkImplementationAndPublication_UnknownAlgorithm_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -754,9 +764,9 @@ void unlinkImplementationAndPublication_UnknownPublication_returnNotFound() { doThrow(new NoSuchElementException()).when(linkingService).unlinkImplementationAndPublication(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndPublication(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -766,10 +776,10 @@ void getSoftwarePlatformsOfImplementation_EmptyList_returnOk() { doReturn(new PageImpl<>(List.of())).when(implementationService).findLinkedSoftwarePlatforms(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.SoftwarePlatforms").doesNotExist()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.SoftwarePlatforms").doesNotExist()) ; } @@ -784,11 +794,11 @@ void getSoftwarePlatformsOfImplementation_SingleElement_returnOk() { doReturn(new PageImpl<>(List.of(softwarePlatform))).when(implementationService).findLinkedSoftwarePlatforms(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.softwarePlatforms").isArray()) - .andExpect(jsonPath("$._embedded.softwarePlatforms[0].id").value(softwarePlatform.getId().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.softwarePlatforms").isArray()) + .andExpect(jsonPath("$._embedded.softwarePlatforms[0].id").value(softwarePlatform.getId().toString())) ; } @@ -798,9 +808,9 @@ void getSoftwarePlatformsOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getSoftwarePlatformsOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -814,11 +824,11 @@ void getSoftwarePlatformOfImplementation_returnOk() { doReturn(softwarePlatform).when(softwarePlatformService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getSoftwarePlatformOfImplementation(UUID.randomUUID(), UUID.randomUUID(), softwarePlatform.getId())); + .getSoftwarePlatformOfImplementation(UUID.randomUUID(), UUID.randomUUID(), softwarePlatform.getId())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.name").value(softwarePlatform.getName())) - .andExpect(jsonPath("$.id").value(softwarePlatform.getId().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value(softwarePlatform.getName())) + .andExpect(jsonPath("$.id").value(softwarePlatform.getId().toString())) ; } @@ -828,9 +838,9 @@ void getSoftwarePlatformOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getSoftwarePlatformOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .getSoftwarePlatformOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -843,10 +853,10 @@ void linkImplementationAndSoftwarePlatform_returnNoContent() { softwarePlatformDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNoContent()); } @Test @@ -856,10 +866,10 @@ void linkImplementationAndSoftwarePlatform_returnBadRequest() { softwarePlatformDto.setId(null); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()); + .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()); } @Test @@ -871,10 +881,10 @@ void linkImplementationAndSoftwarePlatform_UnknownAlgorithm_returnNotFound() { softwarePlatformDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test @@ -887,10 +897,10 @@ void linkImplementationAndSoftwarePlatform_UnknownSoftwarePlatform_returnNotFoun softwarePlatformDto.setId(UUID.randomUUID()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); + .linkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform(post(url).accept(APPLICATION_JSON) - .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(mapper.writeValueAsString(softwarePlatformDto)).contentType(APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test @@ -900,9 +910,9 @@ void unlinkImplementationAndSoftwarePlatform_returnNoContent() { doNothing().when(linkingService).unlinkImplementationAndSoftwarePlatform(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .andExpect(status().isNoContent()); } @Test @@ -911,9 +921,9 @@ void unlinkImplementationAndSoftwarePlatform_UnknownAlgorithm_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -923,9 +933,9 @@ void unlinkImplementationAndSoftwarePlatform_UnknownSoftwarePlatform_returnNotFo doThrow(new NoSuchElementException()).when(linkingService).unlinkImplementationAndSoftwarePlatform(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .unlinkImplementationAndSoftwarePlatform(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -933,13 +943,13 @@ void unlinkImplementationAndSoftwarePlatform_UnknownSoftwarePlatform_returnNotFo void getComputeResourcePropertiesOfImplementation_EmptyList_returnOk() { doNothing().when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); doReturn(new PageImpl<>(List.of())).when(computeResourcePropertyService) - .findComputeResourcePropertiesOfImplementation(any(), any()); + .findComputeResourcePropertiesOfImplementation(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$._embedded.computeResourceProperties").doesNotExist()) - .andExpect(status().isOk()); + .andExpect(jsonPath("$._embedded.computeResourceProperties").doesNotExist()) + .andExpect(status().isOk()); } @Test @@ -957,14 +967,14 @@ void getComputeResourcePropertiesOfImplementation_SingleElement_returnOk() { res.setId(UUID.randomUUID()); doReturn(new PageImpl<>(List.of(res))).when(computeResourcePropertyService) - .findComputeResourcePropertiesOfImplementation(any(), any()); + .findComputeResourcePropertiesOfImplementation(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$._embedded.computeResourceProperties[0].id").value(res.getId().toString())) - .andExpect(jsonPath("$._embedded.computeResourceProperties[0].type.id").value(type.getId().toString())) - .andExpect(status().isOk()); + .andExpect(jsonPath("$._embedded.computeResourceProperties[0].id").value(res.getId().toString())) + .andExpect(jsonPath("$._embedded.computeResourceProperties[0].type.id").value(type.getId().toString())) + .andExpect(status().isOk()); } @Test @@ -973,9 +983,9 @@ void getComputeResourcePropertiesOfImplementation_returnNotFound() { doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); + .getComputeResourcePropertiesOfImplementation(UUID.randomUUID(), UUID.randomUUID(), ListParameters.getDefault())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -995,11 +1005,11 @@ void getComputeResourcePropertyOfImplementation_SingleElement_returnOk() { doReturn(res).when(computeResourcePropertyService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), res.getId())); + .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), res.getId())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(res.getId().toString())) - .andExpect(jsonPath("$.type.id").value(type.getId().toString())) - .andExpect(status().isOk()); + .andExpect(jsonPath("$.id").value(res.getId().toString())) + .andExpect(jsonPath("$.type.id").value(type.getId().toString())) + .andExpect(status().isOk()); } @Test @@ -1008,9 +1018,9 @@ void getComputeResourcePropertyOfImplementation_UnknownAlgorithm_returnNotFound( doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -1020,9 +1030,9 @@ void getComputeResourcePropertyOfImplementation_UnknownProperty_returnNotFound() doThrow(new NoSuchElementException()).when(computeResourcePropertyService).findById(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .getComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(get(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -1032,9 +1042,9 @@ void deleteComputeResourcePropertyOfImplementation_returnNoContent() { doNothing().when(computeResourcePropertyService).delete(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNoContent()); + .andExpect(status().isNoContent()); } @Test @@ -1043,9 +1053,9 @@ void deleteComputeResourcePropertyOfImplementation_UnknownAlgorithm_returnNotFou doThrow(new NoSuchElementException()).when(implementationService).checkIfImplementationIsOfAlgorithm(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -1055,9 +1065,9 @@ void deleteComputeResourcePropertyOfImplementation_UnknownProperty_returnNotFoun doThrow(new NoSuchElementException()).when(computeResourcePropertyService).delete(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + .deleteComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); mockMvc.perform(delete(url).accept(APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()); } @Test @@ -1083,15 +1093,15 @@ void createComputeResourcePropertyForImplementation_returnCreated() { doReturn(res).when(computeResourcePropertyService).addComputeResourcePropertyToImplementation(any(), any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - post(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + post(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isCreated()) - .andExpect(jsonPath("$.id").value(res.getId().toString())) - .andExpect(jsonPath("$.type.id").value(type.getId().toString())) + .andExpect(jsonPath("$.id").value(res.getId().toString())) + .andExpect(jsonPath("$.type.id").value(type.getId().toString())) ; } @@ -1101,12 +1111,12 @@ void createComputeResourcePropertyForImplementation_returnBadRequest() { var resDto = new ComputeResourcePropertyDto(); resDto.setValue("test"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - post(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + post(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isBadRequest()) ; } @@ -1123,12 +1133,12 @@ void createComputeResourcePropertyForImplementation_returnNotFound() { resDto.setType(typeDto); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); + .createComputeResourcePropertyForImplementation(UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - post(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + post(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isNotFound()) ; } @@ -1157,15 +1167,15 @@ void updateComputeResourcePropertyOfImplementation_returnOk() { doReturn(res).when(computeResourcePropertyService).update(any()); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), res.getId(), null)); + .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), res.getId(), null)); mockMvc.perform( - put(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + put(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isOk()) - .andExpect(jsonPath("$.id").value(res.getId().toString())) - .andExpect(jsonPath("$.type.id").value(type.getId().toString())) + .andExpect(jsonPath("$.id").value(res.getId().toString())) + .andExpect(jsonPath("$.type.id").value(type.getId().toString())) ; } @@ -1176,12 +1186,12 @@ void updateComputeResourcePropertyOfImplementation_returnBadRequest() { resDto.setValue("123"); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); + .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - put(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + put(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isBadRequest()) ; } @@ -1198,12 +1208,12 @@ void updateComputeResourcePropertyOfImplementation_UnknownAlgorithm_returnNotFou resDto.setType(typeDto); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); + .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - put(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + put(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isNotFound()) ; } @@ -1221,12 +1231,12 @@ void updateComputeResourcePropertyOfImplementation_UnknownProperty_returnNotFoun resDto.setType(typeDto); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); + .updateComputeResourcePropertyOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); mockMvc.perform( - put(url) - .accept(APPLICATION_JSON) - .contentType(APPLICATION_JSON) - .content(mapper.writeValueAsString(resDto)) + put(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(resDto)) ).andExpect(status().isNotFound()) ; } @@ -1242,7 +1252,7 @@ void getDiscussionTopics() { when(discussionTopicService.findByKnowledgeArtifactId(implementation1.getId(), pageable)).thenReturn(discussionTopics); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionTopicsOfImplementation(algorithm1.getId(), implementation1.getId(), new ListParameters(pageable, null))); + .getDiscussionTopicsOfImplementation(algorithm1.getId(), implementation1.getId(), new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(get(path)).andExpect(status().isOk()).andReturn(); @@ -1268,8 +1278,8 @@ void getDiscussionTopic() { when(discussionTopicService.findById(discussionTopic1.getId())).thenReturn(discussionTopic1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - new ListParameters(pageable, null))); + .getDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(get(path)).andExpect(status().isOk()).andReturn(); @@ -1278,8 +1288,8 @@ void getDiscussionTopic() { Mockito.verify(discussionTopicService, times(1)).findById(discussionTopic1.getId()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(response.getContent().getDate(), discussionTopic1.getDate()); assertEquals(response.getContent().getTitle(), discussionTopic1.getTitle()); @@ -1292,11 +1302,11 @@ void getDiscussionTopicAndFail() { initializeDiscussions(); doThrow(new NoSuchElementException()).when(discussionTopicService) - .checkIfDiscussionTopicIsLinkedToKnowledgeArtifact(discussionTopic2.getId(), implementation1.getId()); + .checkIfDiscussionTopicIsLinkedToKnowledgeArtifact(discussionTopic2.getId(), implementation1.getId()); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), - new ListParameters(pageable, null))); + .getDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), + new ListParameters(pageable, null))); // call mockMvc.perform(get(path)).andExpect(status().isNotFound()); @@ -1312,19 +1322,19 @@ void createDiscussionTopic() { discussionTopic2Dto.setId(null); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createDiscussionTopicOfImplementation(algorithm2.getId(), implementation2.getId(), discussionTopic2Dto, - new ListParameters(pageable, null))); + .createDiscussionTopicOfImplementation(algorithm2.getId(), implementation2.getId(), discussionTopic2Dto, + new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(post(path).content(mapper.writeValueAsString(discussionTopic2Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()).andReturn(); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()).andReturn(); // test Mockito.verify(discussionTopicService, times(1)).create(any()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(response.getContent().getDate(), discussionTopic2.getDate()); assertEquals(response.getContent().getTitle(), discussionTopic2.getTitle()); @@ -1338,12 +1348,12 @@ void createDiscussionTopicAndFail() { discussionTopic2Dto.setDate(null); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createDiscussionTopicOfImplementation(algorithm2.getId(), implementation2.getId(), discussionTopic2Dto, - new ListParameters(pageable, null))); + .createDiscussionTopicOfImplementation(algorithm2.getId(), implementation2.getId(), discussionTopic2Dto, + new ListParameters(pageable, null))); // call mockMvc.perform(post(path).content(mapper.writeValueAsString(discussionTopic2Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); } @Test @@ -1355,19 +1365,19 @@ void updateDiscussionTopic() { when(discussionTopicService.update(any())).thenReturn(discussionTopic1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), discussionTopic1Dto, - new ListParameters(pageable, null))); + .updateDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), discussionTopic1Dto, + new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(put(path).content(mapper.writeValueAsString(discussionTopic1Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn(); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn(); // test Mockito.verify(discussionTopicService, times(1)).update(any()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(discussionTopic1Dto.getId(), response.getContent().getId()); assertEquals(discussionTopic1Dto.getTitle(), response.getContent().getTitle()); @@ -1385,13 +1395,13 @@ void updateDiscussionTopicAndFail() { when(discussionTopicService.update(any())).thenReturn(discussionTopic1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), discussionTopic1Dto, - new ListParameters(pageable, null))); + .updateDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), discussionTopic1Dto, + new ListParameters(pageable, null))); // call mockMvc.perform(put(path).content(mapper.writeValueAsString(discussionTopic1Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) - .andExpect(status().isBadRequest()); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) + .andExpect(status().isBadRequest()); } @Test @@ -1400,8 +1410,8 @@ void deleteDiscussionTopic() { initializeDiscussions(); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - new ListParameters(pageable, null))); + .deleteDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(delete(path)).andExpect(status().isOk()).andReturn(); @@ -1413,11 +1423,11 @@ void deleteDiscussionTopicAndFail() { initializeDiscussions(); doThrow(new NoSuchElementException()).when(discussionTopicService) - .checkIfDiscussionTopicIsLinkedToKnowledgeArtifact(discussionTopic2.getId(), implementation1.getId()); + .checkIfDiscussionTopicIsLinkedToKnowledgeArtifact(discussionTopic2.getId(), implementation1.getId()); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), - new ListParameters(pageable, null))); + .deleteDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), + new ListParameters(pageable, null))); // call mockMvc.perform(delete(path)).andExpect(status().isNotFound()); @@ -1435,8 +1445,8 @@ void getDiscussionComments() { when(discussionCommentService.findAllByTopic(discussionTopic1.getId(), pageable)).thenReturn(discussionCommentPage); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionCommentsOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - new ListParameters(pageable, null))); + .getDiscussionCommentsOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(get(path)).andExpect(status().isOk()).andReturn(); @@ -1446,7 +1456,7 @@ void getDiscussionComments() { var resultList = ObjectMapperUtils.mapResponseToList(result.getResponse().getContentAsString(), - "discussionComments", DiscussionCommentDto.class); + "discussionComments", DiscussionCommentDto.class); assertEquals(resultList.size(), 1); assertEquals(resultList.get(0).getText(), discussionComment1Dto.getText()); @@ -1461,8 +1471,8 @@ void getDiscussionComment() { when(discussionCommentService.findById(discussionComment1.getId())).thenReturn(discussionComment1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment1.getId(), new ListParameters(pageable, null))); + .getDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment1.getId(), new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(get(path)).andExpect(status().isOk()).andReturn(); @@ -1471,8 +1481,8 @@ void getDiscussionComment() { Mockito.verify(discussionCommentService, times(1)).findById(discussionComment1.getId()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(response.getContent().getId(), discussionComment1Dto.getId()); assertEquals(response.getContent().getText(), discussionComment1Dto.getText()); @@ -1485,11 +1495,11 @@ void getDiscussionCommentAndFail() { initializeDiscussions(); doThrow(new NoSuchElementException()).when(discussionCommentService) - .checkIfDiscussionCommentIsInDiscussionTopic(discussionComment2.getId(), discussionTopic1.getId()); + .checkIfDiscussionCommentIsInDiscussionTopic(discussionComment2.getId(), discussionTopic1.getId()); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment2.getId(), new ListParameters(pageable, null))); + .getDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment2.getId(), new ListParameters(pageable, null))); // call mockMvc.perform(get(path)).andExpect(status().isNotFound()); @@ -1505,21 +1515,22 @@ void createDiscussionComment() { when(discussionTopicService.findById(discussionTopic1.getId())).thenReturn(discussionTopic1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment2Dto, new ListParameters(pageable, null))); + .createDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment2Dto, new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(post(path).content(mapper.writeValueAsString(discussionComment2Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")).andExpect(status().isCreated()) - .andReturn(); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) + .andExpect(status().isCreated()) + .andReturn(); // test Mockito.verify(discussionCommentService, times(1)).create(any()); Mockito.verify(discussionTopicService, times(1)).findById(discussionTopic1.getId()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(response.getContent().getText(), discussionComment2Dto.getText()); } @@ -1531,12 +1542,12 @@ void createDiscussionCommentAndFail() { discussionComment2Dto.setDate(null); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment2Dto, new ListParameters(pageable, null))); + .createDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment2Dto, new ListParameters(pageable, null))); // call mockMvc.perform(post(path).content(mapper.writeValueAsString(discussionComment2Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); } @Test @@ -1549,20 +1560,20 @@ void updateDiscussionComment() { when(discussionCommentService.findById(discussionComment1.getId())).thenReturn(discussionComment1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment1.getId(), discussionComment1Dto, new ListParameters(pageable, null))); + .updateDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment1.getId(), discussionComment1Dto, new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(put(path).content(mapper.writeValueAsString(discussionComment1Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn(); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn(); // test Mockito.verify(discussionCommentService, times(1)).update(any()); Mockito.verify(discussionCommentService, times(1)).findById(discussionComment1.getId()); EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<>() { - }); + new TypeReference<>() { + }); assertEquals(response.getContent().getText(), discussionComment1Dto.getText()); assertEquals(response.getContent().getId(), discussionComment1Dto.getId()); @@ -1580,13 +1591,13 @@ void updateDiscussionCommentAndFail() { when(discussionCommentService.findById(discussionComment1.getId())).thenReturn(discussionComment1); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .updateDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment1.getId(), discussionComment1Dto, new ListParameters(pageable, null))); + .updateDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment1.getId(), discussionComment1Dto, new ListParameters(pageable, null))); // call mockMvc.perform(put(path).content(mapper.writeValueAsString(discussionComment1Dto)) - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) - .andExpect(status().isBadRequest()); + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) + .andExpect(status().isBadRequest()); } @Test @@ -1595,8 +1606,8 @@ void deleteDiscussionComment() { initializeDiscussions(); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), - discussionComment1.getId(), new ListParameters(pageable, null))); + .deleteDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic1.getId(), + discussionComment1.getId(), new ListParameters(pageable, null))); // call final MvcResult result = mockMvc.perform(delete(path)).andExpect(status().isOk()).andReturn(); @@ -1608,11 +1619,11 @@ void deleteDiscussionCommentAndFail() { initializeDiscussions(); doThrow(new NoSuchElementException()).when(discussionCommentService) - .checkIfDiscussionCommentIsInDiscussionTopic(discussionComment1.getId(), discussionTopic2.getId()); + .checkIfDiscussionCommentIsInDiscussionTopic(discussionComment1.getId(), discussionTopic2.getId()); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), - discussionComment1.getId(), new ListParameters(pageable, null))); + .deleteDiscussionCommentOfDiscussionTopicOfImplementation(algorithm1.getId(), implementation1.getId(), discussionTopic2.getId(), + discussionComment1.getId(), new ListParameters(pageable, null))); // call mockMvc.perform(delete(path)).andExpect(status().isNotFound()); @@ -1620,34 +1631,313 @@ void deleteDiscussionCommentAndFail() { @Test @SneakyThrows - public void testCreateFileForImplementation_returnOk() { + void getImplementationPackages() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + List implementationPackages = new ArrayList<>(); + implementationPackages.add(implementationPackage); + final Page implementationPackages1 = new PageImpl(implementationPackages); + when(implementationPackageService.findImplementationPackagesByImplementationId(impl.getId(), pageable)).thenReturn(implementationPackages1); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .getImplementationPackagesOfImplementation(algo.getId(), impl.getId(), new ListParameters(pageable, null))); + + ResultActions result = mockMvc.perform(get(path).accept(MediaType.APPLICATION_JSON)); + + // Then + result.andExpect(status().isOk()).andReturn(); + + var resultList = ObjectMapperUtils.mapResponseToList(result.andReturn().getResponse().getContentAsString(), + "implementationPackages", ImplementationPackageDto.class); + assertEquals(1, resultList.size()); + + Mockito.verify(implementationPackageService, times(1)) + .findImplementationPackagesByImplementationId(impl.getId(), pageable); + } + + @Test + @SneakyThrows + void getImplementationPackage() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + when(implementationPackageService.findById(implementationPackage.getId())).thenReturn(implementationPackage); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .getImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId())); + + // call + final MvcResult result = mockMvc.perform(get(path)).andExpect(status().isOk()).andReturn(); + + // test + Mockito.verify(implementationPackageService, times(1)).findById(implementationPackage.getId()); + + EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), + new TypeReference<>() { + }); + + assertEquals(response.getContent().getName(), implementationPackage.getName()); + assertEquals(response.getContent().getPackageType(), implementationPackage.getPackageType()); + } + + @Test + @SneakyThrows + void getImplementationPackageAndFail() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + doThrow(new NoSuchElementException()).when(implementationPackageService) + .checkIfImplementationPackageIsLinkedToImplementation(implementationPackage.getId(), impl.getId()); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .getImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId())); + + // call + mockMvc.perform(get(path)).andExpect(status().isNotFound()); + } + + @Test + @SneakyThrows + void createImplementationPackage() { // Given var impl = new Implementation(); impl.setName("implementation for Shor"); impl.setId(UUID.randomUUID()); + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + when(implementationPackageService.create(any(), any())).thenReturn(implementationPackage); + + ImplementationPackageDto implementationPackageDto = new ImplementationPackageDto(); + implementationPackageDto.setId(null); + implementationPackageDto.setPackageType(ImplementationPackageType.FILE); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .createImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackageDto)); + + // call + final MvcResult result = mockMvc.perform(post(path).content(mapper.writeValueAsString(implementationPackageDto)) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()).andReturn(); + + // test + Mockito.verify(implementationPackageService, times(1)).create(any(), any()); + + EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), + new TypeReference<>() { + }); + + assertEquals(response.getContent().getName(), implementationPackage.getName()); + assertEquals(response.getContent().getPackageType(), implementationPackage.getPackageType()); + } + + @Test + @SneakyThrows + void createImplementationPackageAndFail() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + ImplementationPackageDto implementationPackageDto = new ImplementationPackageDto(); + implementationPackageDto.setId(null); + implementationPackageDto.setPackageType(ImplementationPackageType.FILE); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .createImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackageDto)); + + // call + mockMvc.perform(post(path).content(mapper.writeValueAsString(implementationPackageDto)) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); + } + + @Test + @SneakyThrows + void updateImplementationPackage() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + implementationPackage.setDescription("Test123"); + + ImplementationPackageDto implementationPackageDto = ModelMapperUtils.convert(implementationPackage, ImplementationPackageDto.class); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + when(implementationPackageService.update(any())).thenReturn(implementationPackage); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .updateImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId(), implementationPackageDto)); + + // call + final MvcResult result = mockMvc.perform(put(path).content(mapper.writeValueAsString(implementationPackageDto)) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn(); + + // test + Mockito.verify(implementationPackageService, times(1)).update(any()); + + EntityModel response = mapper.readValue(result.getResponse().getContentAsString(), + new TypeReference<>() { + }); + + assertEquals(implementationPackageDto.getId(), response.getContent().getId()); + assertEquals(implementationPackageDto.getPackageType(), response.getContent().getPackageType()); + assertEquals(implementationPackageDto.getDescription(), response.getContent().getDescription()); + } + + @Test + @SneakyThrows + void updateImplementationPackageAndFail() { + var implementationPackageDto = new ImplementationPackageDto(); + implementationPackageDto.setPackageType(ImplementationPackageType.FILE); + + var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .updateImplementationPackageOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), null)); + mockMvc.perform( + put(url) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .content(mapper.writeValueAsString(implementationPackageDto)) + ).andExpect(status().isBadRequest()); + } + + @Test + @SneakyThrows + void deleteImplementationPackage() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + implementationPackage.setDescription("Test123"); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .deleteImplementationPackageOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId())); + + // call + mockMvc.perform(delete(path)).andExpect(status().isNoContent()); + } + + @Test + @SneakyThrows + void deleteImplementationPackageAndFail() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("Test Implementation Package"); + implementationPackage.setPackageType(ImplementationPackageType.FILE); + implementationPackage.setId(UUID.randomUUID()); + implementationPackage.setDescription("Test123"); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + doThrow(new NoSuchElementException()).when(implementationPackageService).checkIfImplementationPackageIsLinkedToImplementation(any(), any()); + + var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .deleteImplementationPackageOfImplementation(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); + mockMvc.perform(delete(url).accept(APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + @SneakyThrows + public void testCreateFileForImplementationPackage_returnOk() { + // Given + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("implementation for Shor"); + implementationPackage.setId(UUID.randomUUID()); + var algo = new Algorithm(); algo.setId(UUID.randomUUID()); byte[] testFile = new byte[20]; final MockMultipartFile file = new MockMultipartFile("file", testFile); - doReturn(new File()).when(implementationService).addFileToImplementation(impl.getId(), file); + doReturn(new File()).when(implementationPackageService).addFileToImplementationPackage(implementationPackage.getId(), file); final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .createFileForImplementation(algo.getId(), impl.getId(), file)); + .createFileForImplementationPackage(algo.getId(), impl.getId(), implementationPackage.getId(), file)); // When ResultActions resultActions = mockMvc.perform(multipart(path).file(file)); // Then resultActions.andExpect(status().isCreated()); - Mockito.verify(implementationService, times(1)).addFileToImplementation(impl.getId(), file); + Mockito.verify(implementationPackageService, times(1)).addFileToImplementationPackage(implementationPackage.getId(), file); } @Test @SneakyThrows - public void testGetAllFilesOfImplementation_response_OK() { + public void testGetFileOfImplementationPackage_response_OK() { // Given + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("implementation for Shor"); + implementationPackage.setId(UUID.randomUUID()); + var impl = new Implementation(); impl.setName("implementation for Shor"); impl.setId(UUID.randomUUID()); @@ -1655,23 +1945,28 @@ public void testGetAllFilesOfImplementation_response_OK() { var algo = new Algorithm(); algo.setId(UUID.randomUUID()); - when(implementationService.findLinkedFiles(impl.getId(), pageable)).thenReturn(Page.empty()); + when(implementationPackageService.findLinkedFile(implementationPackage.getId())).thenReturn(new File()); // When final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getAllFilesOfImplementation(algo.getId(), impl.getId(), new ListParameters(pageable, null))); + .getFileOfImplementationPackage(algo.getId(), impl.getId(), implementationPackage.getId())); ResultActions result = mockMvc.perform(get(path).accept(MediaType.APPLICATION_JSON)); // Then result.andExpect(status().isOk()); - Mockito.verify(implementationService, times(1)).findLinkedFiles(impl.getId(), pageable); + Mockito.verify(implementationPackageService, times(1)).findLinkedFile(implementationPackage.getId()); } @Test @SneakyThrows public void testGetFileOfImplementation_response_OK() { // Given + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("implementation for Shor"); + implementationPackage.setId(UUID.randomUUID()); + + var impl = new Implementation(); impl.setName("implementation for Shor"); impl.setId(UUID.randomUUID()); @@ -1682,12 +1977,14 @@ public void testGetFileOfImplementation_response_OK() { var file = new File(); file.setId(UUID.randomUUID()); file.setMimeType("img/png"); + implementationPackage.setFile(file); - when(fileService.findById(file.getId())).thenReturn(file); + + when(implementationPackageService.findLinkedFile(implementationPackage.getId())).thenReturn(file); // When final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .getFileOfImplementation(algo.getId(), impl.getId(), file.getId())); + .getFileOfImplementationPackage(algo.getId(), impl.getId(), implementationPackage.getId())); ResultActions result = mockMvc.perform(get(path).accept(MediaType.APPLICATION_JSON)); @@ -1695,16 +1992,20 @@ public void testGetFileOfImplementation_response_OK() { result.andExpect(status().isOk()).andReturn(); var resultList = ObjectMapperUtils.mapResponseToList(result.andReturn().getResponse().getContentAsString(), - "file", File.class); + "file", File.class); assertEquals(0, resultList.size()); - Mockito.verify(fileService, times(1)).findById(file.getId()); + Mockito.verify(implementationPackageService, times(1)).findLinkedFile(implementationPackage.getId()); } @Test @SneakyThrows public void testDownloadFileContent_response_OK() { // Given + var implementationPackage = new FileImplementationPackage(); + implementationPackage.setName("implementation for Shor"); + implementationPackage.setId(UUID.randomUUID()); + var impl = new Implementation(); impl.setName("implementation for Shor"); impl.setId(UUID.randomUUID()); @@ -1716,17 +2017,43 @@ public void testDownloadFileContent_response_OK() { file.setId(UUID.randomUUID()); file.setMimeType("img/png"); - when(fileService.findById(file.getId())).thenReturn(file); + when(implementationPackageService.findLinkedFile(implementationPackage.getId())).thenReturn(file); // When final String path = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .downloadFileContent(algo.getId(), impl.getId(), file.getId())); + .downloadFileContent(algo.getId(), impl.getId(), implementationPackage.getId())); ResultActions result = mockMvc.perform(get(path).accept(MediaType.APPLICATION_JSON)); // Then result.andExpect(status().isOk()).andReturn(); - Mockito.verify(fileService, times(1)).findById(file.getId()); + Mockito.verify(implementationPackageService, times(1)).findLinkedFile(implementationPackage.getId()); + } + + @Test + @SneakyThrows + public void testDeleteFile_response_file_not_found() { + var impl = new Implementation(); + impl.setName("implementation for Shor"); + impl.setId(UUID.randomUUID()); + + var algo = new Algorithm(); + algo.setId(UUID.randomUUID()); + + var implementationPackage = new TOSCAImplementationPackage(); + implementationPackage.setId(UUID.randomUUID()); + + var file = new File(); + file.setId(UUID.randomUUID()); + file.setMimeType("img/png"); + + doNothing().when(fileService).delete(file.getId()); + + var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) + .deleteFileOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId())); + mockMvc.perform(delete(url)) + .andExpect(status().isNotFound()).andReturn(); + } @Test @@ -1739,18 +2066,23 @@ public void testDeleteFile_response_no_content() { var algo = new Algorithm(); algo.setId(UUID.randomUUID()); + var implementationPackage = new TOSCAImplementationPackage(); + implementationPackage.setId(UUID.randomUUID()); + var file = new File(); file.setId(UUID.randomUUID()); file.setMimeType("img/png"); doNothing().when(fileService).delete(file.getId()); + when(implementationPackageService.update(any())).thenReturn(implementationPackage); + when(implementationPackageService.findById(any())).thenReturn(implementationPackage); + when(implementationPackageService.findLinkedFile(implementationPackage.getId())).thenReturn(file); var url = linkBuilderService.urlStringTo(methodOn(ImplementationController.class) - .deleteFileOfImplementation(algo.getId(), impl.getId(), file.getId())); + .deleteFileOfImplementation(algo.getId(), impl.getId(), implementationPackage.getId())); mockMvc.perform(delete(url)) - .andExpect(status().isNoContent()).andReturn(); + .andExpect(status().isNoContent()).andReturn(); - Mockito.verify(fileService, times(1)).delete(file.getId()); } }