Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many-To-Many relationship between Implementations and Algorithms #193

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ public class Algorithm extends KnowledgeArtifact {
@NotAudited
private Set<Tag> tags = new HashSet<>();

@OneToMany(mappedBy = "implementedAlgorithm",
fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true)
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "algorithm_implementation",
joinColumns = @JoinColumn(name = "algorithm_id"),
inverseJoinColumns = @JoinColumn(name = "implementation_id"))
@EqualsAndHashCode.Exclude
@ToString.Exclude
@NotAudited
Expand Down Expand Up @@ -297,4 +297,20 @@ public void removeLearningMethod(@NonNull LearningMethod learningMethod) {
learningMethods.remove(learningMethod);
learningMethod.getAlgorithms().remove(this);
}

public void addImplementation(@NonNull Implementation implementation) {
if (implementations.contains(implementation)) {
ValeSayfa marked this conversation as resolved.
Show resolved Hide resolved
return;
}
implementations.add(implementation);
implementation.getImplementedAlgorithms().add(this);
}

public void removeImplementation(@NonNull Implementation implementation) {
if (!implementations.contains(implementation)) {
ValeSayfa marked this conversation as resolved.
Show resolved Hide resolved
return;
}
implementations.remove(implementation);
implementation.getImplementedAlgorithms().remove(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.hibernate.envers.AuditTable;
Expand Down Expand Up @@ -89,10 +88,11 @@ public class Implementation extends KnowledgeArtifact {
@NotAudited
private Set<Publication> publications = new HashSet<>();

@ManyToOne
@ManyToMany(mappedBy = "implementations", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Algorithm implementedAlgorithm;
@NotAudited
private Set<Algorithm> implementedAlgorithms = new HashSet<>();

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "implementation_tag",
Expand Down Expand Up @@ -192,4 +192,20 @@ public void removeImplementationPackage(@NonNull ImplementationPackage implement
this.implementationPackages.remove(implementationPackage);
implementationPackage.setImplementation(null);
}

public void addAlgorithm(@NonNull Algorithm algorithm) {
if (implementedAlgorithms.contains(algorithm)) {
ValeSayfa marked this conversation as resolved.
Show resolved Hide resolved
return;
}
implementedAlgorithms.add(algorithm);
algorithm.getImplementations().add(this);
}

public void removeAlgorithm(@NonNull Algorithm algorithm) {
if (!implementedAlgorithms.contains(algorithm)) {
ValeSayfa marked this conversation as resolved.
Show resolved Hide resolved
return;
}
implementedAlgorithms.remove(algorithm);
algorithm.getImplementations().remove(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
@RepositoryRestResource(exported = false)
public interface ImplementationRepository extends RevisionRepository<Implementation, UUID, Integer>, JpaRepository<Implementation, UUID> {

Page<Implementation> findByImplementedAlgorithmId(UUID implementedAlgorithmId, Pageable pageable);
@Query("SELECT impl " +
"FROM Implementation impl " +
"JOIN impl.implementedAlgorithms alg " +
"WHERE alg.id = :algId")
Page<Implementation> findByImplementedAlgorithmId(@Param("algId") UUID implementedAlgorithmId, Pageable pageable);

@Query("SELECT impl " +
"FROM Implementation impl " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import org.planqk.atlas.core.model.Algorithm;
import org.planqk.atlas.core.model.AlgorithmRelation;
import org.planqk.atlas.core.model.ApplicationArea;
import org.planqk.atlas.core.model.LearningMethod;
import org.planqk.atlas.core.model.ClassicAlgorithm;
import org.planqk.atlas.core.model.LearningMethod;
import org.planqk.atlas.core.model.PatternRelation;
import org.planqk.atlas.core.model.ProblemType;
import org.planqk.atlas.core.model.Publication;
Expand Down Expand Up @@ -184,9 +184,14 @@ private void removeRevisions(@NonNull Algorithm algorithm) {
}

private void removeReferences(@NonNull Algorithm algorithm) {
// delete related implementations
algorithm.getImplementations().forEach(
implementation -> implementationService.delete(implementation.getId()));

// remove links to implementations and remove orphans
CollectionUtils.forEachOnCopy(algorithm.getImplementations(),
implementation -> { implementation.removeAlgorithm(algorithm);
if (implementation.getImplementedAlgorithms().size() == 0) {
implementationService.delete(implementation.getId());
}
});

// delete compute resource property
algorithm.getRequiredComputeResourceProperties().forEach(computeResourcePropertyRepository::delete);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
package org.planqk.atlas.core.services;

import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import org.planqk.atlas.core.model.Algorithm;
import org.planqk.atlas.core.model.ClassicImplementation;
import org.planqk.atlas.core.model.HasId;
import org.planqk.atlas.core.model.Implementation;
import org.planqk.atlas.core.model.Publication;
import org.planqk.atlas.core.model.QuantumImplementation;
Expand Down Expand Up @@ -71,10 +74,8 @@ public class ImplementationServiceImpl implements ImplementationService {
@Transactional
public Implementation create(@NonNull Implementation implementation, @NonNull UUID implementedAlgorithmId) {
final Algorithm implementedAlgorithm = ServiceUtils.findById(implementedAlgorithmId, Algorithm.class, algorithmRepository);
implementation.setImplementedAlgorithm(implementedAlgorithm);
final Implementation savedImplementation = implementationRepository.save(implementation);
implementedAlgorithm.getImplementations().add(savedImplementation);
return savedImplementation;
implementation.addAlgorithm(implementedAlgorithm);
return implementationRepository.save(implementation);
}

@Override
Expand Down Expand Up @@ -166,8 +167,9 @@ private void removeRevisions(@NonNull Implementation implementation) {
}

private void removeReferences(@NonNull Implementation implementation) {
// Remove reference from algorithm
implementation.setImplementedAlgorithm(null);
// Remove references from algorithms
CollectionUtils.forEachOnCopy(implementation.getImplementedAlgorithms(),
algorithm -> algorithm.removeImplementation(implementation));

// Delete compute resource property
implementation.getRequiredComputeResourceProperties().forEach(computeResourcePropertyRepository::delete);
Expand All @@ -183,9 +185,10 @@ private void removeReferences(@NonNull Implementation implementation) {

@Override
public void checkIfImplementationIsOfAlgorithm(@NonNull UUID implementationId, @NonNull UUID algorithmId) {
final Implementation implementation = findById(implementationId);
final Set<UUID> implementedAlgorithmUUIDs = findById(implementationId).getImplementedAlgorithms().stream().map(HasId::getId).collect(
Collectors.toSet());

if (!implementation.getImplementedAlgorithm().getId().equals(algorithmId)) {
if (!implementedAlgorithmUUIDs.contains(algorithmId)) {
throw new NoSuchElementException("Implementation with ID \"" + implementationId
+ "\" of Algorithm with ID \"" + algorithmId + "\" does not exist");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,40 @@
*/
public interface LinkingService {

/**
* Links an existing {@link org.planqk.atlas.core.model.Algorithm} and an existing {@link
* org.planqk.atlas.core.model.Implementation}.
* <p>
* If either the {@link org.planqk.atlas.core.model.Algorithm} or the {@link org.planqk.atlas.core.model.Implementation}
* with given IDs could not be found a {@link java.util.NoSuchElementException} is thrown.
* <p>
* If both entities exist but they are already linked this method will throw an {@link
* org.planqk.atlas.core.exceptions.EntityReferenceConstraintViolationException}.
*
* @param implementationId The ID of the {@link org.planqk.atlas.core.model.Implementation} we want to link
* @param algorithmId The ID of the {@link org.planqk.atlas.core.model.Algorithm} we want to link
*/
@Transactional
void linkImplementationAndAlgorithm(UUID implementationId, UUID algorithmId);

/**
* Unlinks an existing {@link org.planqk.atlas.core.model.Algorithm} and an existing {@link
* org.planqk.atlas.core.model.Implementation}.
* If an {@link org.planqk.atlas.core.model.Implementation} has no reference to an other
* {@link org.planqk.atlas.core.model.Algorithm} after unlinking (orphaned), it will be completely deleted.
* <p>
* If either the {@link org.planqk.atlas.core.model.Algorithm} or the {@link org.planqk.atlas.core.model.Implementation}
* with given IDs could not be found a {@link java.util.NoSuchElementException} is thrown.
* <p>
* If both entities exist but they are already linked this method will throw an {@link
* org.planqk.atlas.core.exceptions.EntityReferenceConstraintViolationException}.
*
* @param implementationId The ID of the {@link org.planqk.atlas.core.model.Implementation} we want to link
* @param algorithmId The ID of the {@link org.planqk.atlas.core.model.Algorithm} we want to link
*/
@Transactional
void unlinkImplementationAndAlgorithm(UUID implementationId, UUID algorithmId);

/**
* Links an existing {@link org.planqk.atlas.core.model.Algorithm} and an existing {@link
* org.planqk.atlas.core.model.Publication}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@ public class LinkingServiceImpl implements LinkingService {

private final LearningMethodService learningMethodService;

@Override
@Transactional
public void linkImplementationAndAlgorithm(UUID implementationId, UUID algorithmId) {
final Algorithm algorithm = algorithmService.findById(algorithmId);
final Implementation implementation = implementationService.findById(implementationId);

if (algorithm.getImplementations().contains(implementation)) {
throw new EntityReferenceConstraintViolationException("Algorithm with ID \"" + algorithmId +
"\" and Implementation with ID \"" + implementationId + "\" are already linked");
}

algorithm.addImplementation(implementation);
}

@Override
@Transactional
public void unlinkImplementationAndAlgorithm(UUID implementationId, UUID algorithmId) {
final Algorithm algorithm = algorithmService.findById(algorithmId);
final Implementation implementation = implementationService.findById(implementationId);

if (!algorithm.getImplementations().contains(implementation)) {
throw new EntityReferenceConstraintViolationException("Algorithm with ID \"" + algorithmId +
"\" and Implementation with ID \"" + implementationId + "\" are not linked");
}

algorithm.removeImplementation(implementation);

if (implementation.getImplementedAlgorithms().size() == 0) {
implementationService.delete(implementationId);
}
}

@Override
@Transactional
public void linkAlgorithmAndPublication(@NonNull UUID algorithmId, @NonNull UUID publicationId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ void deleteAlgorithm_WithLinks() {
// add Implementation
Implementation implementation = new Implementation();
implementation.setName("implementationName");
implementation.setImplementedAlgorithm(algorithm);
implementationService.create(implementation, algorithm.getId());

// add pattern Relation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,6 @@ private QuantumImplementation getCreatedQuantumImplementation(String name) {
QuantumImplementation implementation = new QuantumImplementation();

implementation.setName(name);
implementation.setImplementedAlgorithm(algorithm);

return (QuantumImplementation) implementationService.create(implementation, algorithm.getId());
}
Expand Down
Loading