From bebbd61d7c01e00520dcdc233898819d1ccd7638 Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Tue, 9 Jun 2020 22:00:30 +0200 Subject: [PATCH 01/10] Initial part of design model implementation --- .../com/patternpedia/api/PatternPediaAPI.java | 20 - .../api/config/ResourceServerConfig.java | 4 +- .../api/entities/designmodel/DesignModel.java | 61 +++ .../designmodel/DesignModelDirectedEdge.java | 38 ++ .../DesignModelDirectedEdgeId.java | 20 + .../DesignModelPatternGraphData.java | 23 ++ .../designmodel/DesignModelPatternId.java | 22 ++ .../DesignModelPatternInstance.java | 44 +++ .../DesignModelUndirectedEdge.java | 38 ++ .../DesignModelUndirectedEdgeId.java | 20 + .../DesignModelNotFoundException.java | 21 ++ .../exception/NullDesignModelException.java | 12 + .../DesignModelPatternInstanceRepository.java | 18 + .../repositories/DesignModelRepository.java | 14 + .../controller/DesignModelController.java | 282 ++++++++++++++ .../controller/PatternLanguageController.java | 27 +- .../controller/PatternViewController.java | 27 +- .../RestResponseExceptionHandler.java | 5 +- ...anguageGraphModel.java => GraphModel.java} | 2 +- .../api/rest/model/GraphPatternModel.java | 39 ++ .../api/rest/model/PatternModel.java | 21 +- .../api/service/DesignModelService.java | 53 +++ .../api/service/DesignModelServiceImpl.java | 346 ++++++++++++++++++ src/main/resources/application.properties | 4 +- 24 files changed, 1093 insertions(+), 68 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternGraphData.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdge.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdgeId.java create mode 100644 src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java create mode 100644 src/main/java/com/patternpedia/api/exception/NullDesignModelException.java create mode 100644 src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java create mode 100644 src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java rename src/main/java/com/patternpedia/api/rest/model/{PatternLanguageGraphModel.java => GraphModel.java} (78%) create mode 100644 src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java create mode 100644 src/main/java/com/patternpedia/api/service/DesignModelService.java create mode 100644 src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/PatternPediaAPI.java b/src/main/java/com/patternpedia/api/PatternPediaAPI.java index 3d70d33..62d2017 100644 --- a/src/main/java/com/patternpedia/api/PatternPediaAPI.java +++ b/src/main/java/com/patternpedia/api/PatternPediaAPI.java @@ -1,29 +1,18 @@ package com.patternpedia.api; -import com.patternpedia.api.rest.controller.UserController; -import com.patternpedia.api.service.IssueService; import com.vladmihalcea.hibernate.type.util.Configuration; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.bind.annotation.RestController; @EnableTransactionManagement @Slf4j -@RestController @SpringBootApplication public class PatternPediaAPI implements CommandLineRunner { - @Autowired - private UserController userController; - - @Autowired - private IssueService issueService; - public static void main(String[] args) { System.setProperty(Configuration.PropertyKey.PRINT_BANNER.getKey(), Boolean.FALSE.toString()); SpringApplication.run(PatternPediaAPI.class, args); @@ -31,15 +20,6 @@ public static void main(String[] args) { @Override public void run(String... args) { - log.info("PatternPediaAPI is up"); - // Used this for testing purposes, will be deleted in the final build -// userController.defaultUsers(); -// Issue issue = new Issue(); -// issue.setUri("uri"); -// issue.setName("name"); -// issue.setDescription("description"); -// Issue p = issueService.createIssue(issue); -// log.info(p.toString()); } } diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java index 0e5c515..7a7e0c1 100644 --- a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java +++ b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java @@ -4,8 +4,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -71,4 +69,4 @@ public FilterRegistrationBean customCorsFilter() { bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } -} \ No newline at end of file +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java new file mode 100644 index 0000000..0fa143b --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java @@ -0,0 +1,61 @@ +package com.patternpedia.api.entities.designmodel; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.patternpedia.api.entities.EntityWithURI; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +public class DesignModel extends EntityWithURI { + + private URL logo; + + @JsonIgnore + @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) + private List patterns = new ArrayList<>(); + + @JsonIgnore + @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) + private List directedEdges; + + @JsonIgnore + @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) + private List undirectedEdges; + +// public void removePattern(Pattern pattern) { +// for (Iterator iterator = this.patterns.iterator(); iterator.hasNext(); ) { +// DesignModelPattern designModelPattern = iterator.next(); +// if (designModelPattern.getDesignModel().equals(this) && designModelPattern.getPattern().equals(pattern)) { +// iterator.remove(); +// designModelPattern.getPattern().getDesignModels().remove(designModelPattern); +// designModelPattern.setPattern(null); +// designModelPattern.setDesignModel(null); +// break; +// } +// } +// } +// +// public void removeDirectedEdge(DirectedEdge directedEdge) { +// for (Iterator iterator = this.directedEdges.iterator(); iterator.hasNext(); ) { +// DesignModelDirectedEdge designModelDirectedEdge = iterator.next(); +// if (designModelDirectedEdge.getDesignModel().equals(this) && +// designModelDirectedEdge.getDirectedEdge().equals(directedEdge)) { +// iterator.remove(); +// designModelDirectedEdge.getDirectedEdge().getDesignModels().remove(designModelDirectedEdge); +// designModelDirectedEdge.setDirectedEdge(null); +// designModelDirectedEdge.setDesignModel(null); +// break; +// } +// } +// } +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java new file mode 100644 index 0000000..4153d39 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java @@ -0,0 +1,38 @@ +package com.patternpedia.api.entities.designmodel; + +import com.patternpedia.api.entities.DirectedEdge; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +public class DesignModelDirectedEdge { + + @EmbeddedId + @EqualsAndHashCode.Exclude + private DesignModelDirectedEdgeId id; + + @ManyToOne + @MapsId("designModelId") + @EqualsAndHashCode.Include + private DesignModel designModel; + + @ManyToOne + @MapsId("directedEdgeId") + @EqualsAndHashCode.Include + private DirectedEdge directedEdge; + + public DesignModelDirectedEdge(DesignModel designModel, DirectedEdge directedEdge) { + this.designModel = designModel; + this.directedEdge = directedEdge; + this.id = new DesignModelDirectedEdgeId(designModel.getId(), directedEdge.getId()); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java new file mode 100644 index 0000000..a10eb84 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java @@ -0,0 +1,20 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; +import java.io.Serializable; +import java.util.UUID; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class DesignModelDirectedEdgeId implements Serializable { + protected UUID designModelId; + protected UUID directedEdgeId; +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternGraphData.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternGraphData.java new file mode 100644 index 0000000..52768a0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternGraphData.java @@ -0,0 +1,23 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class DesignModelPatternGraphData { + + private Double x; + private Double y; + private Double vx; + private Double vy; + private String type; + private Integer index; +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java new file mode 100644 index 0000000..575fc23 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java @@ -0,0 +1,22 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; +import java.io.Serializable; +import java.util.UUID; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class DesignModelPatternId implements Serializable { + + protected UUID designModelId; + protected UUID patternId; + protected UUID patternInstanceId; +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java new file mode 100644 index 0000000..30525c0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java @@ -0,0 +1,44 @@ +package com.patternpedia.api.entities.designmodel; + +import com.patternpedia.api.entities.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.hateoas.server.core.Relation; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import java.util.UUID; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +@Relation(value = "pattern", collectionRelation = "patterns") +public class DesignModelPatternInstance { + + @EmbeddedId + @EqualsAndHashCode.Exclude + private DesignModelPatternId id; + + @ManyToOne + @MapsId("designModelId") + @EqualsAndHashCode.Include + private DesignModel designModel; + + @ManyToOne + @MapsId("patternId") + @EqualsAndHashCode.Include + private Pattern pattern; + + private DesignModelPatternGraphData graphData; + + + public DesignModelPatternInstance(DesignModel designModel, Pattern pattern) { + this.designModel = designModel; + this.pattern = pattern; + this.id = new DesignModelPatternId(designModel.getId(), pattern.getId(), UUID.randomUUID()); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdge.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdge.java new file mode 100644 index 0000000..604ca7b --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdge.java @@ -0,0 +1,38 @@ +package com.patternpedia.api.entities.designmodel; + +import com.patternpedia.api.entities.UndirectedEdge; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +public class DesignModelUndirectedEdge { + + @EmbeddedId + @EqualsAndHashCode.Exclude + private DesignModelUndirectedEdgeId id; + + @ManyToOne + @MapsId("designModelId") + @EqualsAndHashCode.Include + private DesignModel designModel; + + @ManyToOne + @MapsId("undirectedEdgeId") + @EqualsAndHashCode.Include + private UndirectedEdge undirectedEdge; + + public DesignModelUndirectedEdge(DesignModel designModel, UndirectedEdge undirectedEdge) { + this.designModel = designModel; + this.undirectedEdge = undirectedEdge; + this.id = new DesignModelUndirectedEdgeId(designModel.getId(), undirectedEdge.getId()); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdgeId.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdgeId.java new file mode 100644 index 0000000..65a5d1e --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelUndirectedEdgeId.java @@ -0,0 +1,20 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; +import java.io.Serializable; +import java.util.UUID; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class DesignModelUndirectedEdgeId implements Serializable { + protected UUID designModelId; + protected UUID undirectedEdgeId; +} diff --git a/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java b/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java new file mode 100644 index 0000000..01be3e8 --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java @@ -0,0 +1,21 @@ +package com.patternpedia.api.exception; + +import com.patternpedia.api.entities.designmodel.DesignModel; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; + +import java.util.UUID; + +public class DesignModelNotFoundException extends ResourceNotFoundException { + + public DesignModelNotFoundException(String message) { + super(message); + } + + public DesignModelNotFoundException(UUID designModelId) { + super(String.format("DesignModel \"%s\" not found!", designModelId)); + } + + public DesignModelNotFoundException(DesignModel designModel) { + super(String.format("PatternView \"%s\" not found!", designModel.getId())); + } +} diff --git a/src/main/java/com/patternpedia/api/exception/NullDesignModelException.java b/src/main/java/com/patternpedia/api/exception/NullDesignModelException.java new file mode 100644 index 0000000..6ece16c --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/NullDesignModelException.java @@ -0,0 +1,12 @@ +package com.patternpedia.api.exception; + +public class NullDesignModelException extends RuntimeException { + + public NullDesignModelException() { + super("DesignModel is null"); + } + + public NullDesignModelException(String message) { + super(message); + } +} diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java new file mode 100644 index 0000000..87a66e2 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java @@ -0,0 +1,18 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.entities.designmodel.DesignModelPatternId; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@RepositoryRestResource(exported = false) +public interface DesignModelPatternInstanceRepository extends JpaRepository { + + Optional> findAllByDesignModelId(UUID patternViewId); + + List findAllByPatternId(UUID patternId); +} diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java new file mode 100644 index 0000000..c0f21bf --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java @@ -0,0 +1,14 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.designmodel.DesignModel; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface DesignModelRepository extends JpaRepository { + + Optional findByUri(String uri); + + boolean existsByUri(String uri); +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java new file mode 100644 index 0000000..43675b6 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java @@ -0,0 +1,282 @@ +package com.patternpedia.api.rest.controller; + +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.patternpedia.api.entities.Pattern; +import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.GraphPatternModel; +import com.patternpedia.api.service.DesignModelService; +import lombok.extern.apachecommons.CommonsLog; +import org.apache.commons.text.CaseUtils; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.Link; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; + + +@RestController +@CommonsLog +@CrossOrigin(allowedHeaders = "*", origins = "*") +@RequestMapping(value = "/designModels", produces = "application/hal+json") +public class DesignModelController { + + private DesignModelService designModelService; + private ObjectCodec objectMapper; + + + public DesignModelController(DesignModelService designModelService, ObjectMapper objectMapper) { + this.designModelService = designModelService; + this.objectMapper = objectMapper; + } + + + private static List getDesignModelCollectionLinks() { + List links = new ArrayList<>(); + + links.add(linkTo(methodOn(DesignModelController.class).getDesignModels()).withSelfRel() + .andAffordance(afford(methodOn(DesignModelController.class).createDesignModel(null)))); + + links.add(linkTo(methodOn(DesignModelController.class).getDesignModel(null)).withRel("designModel")); + + return links; + } + + + private static List getDesignModelLinks(DesignModel designModel) { + List links = new ArrayList<>(); + + links.add( + linkTo(methodOn(DesignModelController.class).getDesignModel(designModel.getId())).withSelfRel() + .andAffordance(afford(methodOn(DesignModelController.class).putDesignModel(designModel.getId(), null))) + .andAffordance(afford(methodOn(DesignModelController.class).deleteDesignModel(designModel.getId()))) + ); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModels()).withRel("designModels")); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModel.getId())).withRel("patterns")); +// links.add(linkTo(methodOn(PatternRelationDescriptorController.class).getDirectedEdgesOfView(patternView.getId())).withRel("directedEdges")); +// links.add(linkTo(methodOn(PatternRelationDescriptorController.class).getUndirectedEdgesOfView(patternView.getId())).withRel("undirectedEdges")); + + return links; + } + + + // TODO currently this is a duplicate from PatternController, may generalize this and move it to a utility class, etc. + List getPatternLinksForDesignModelRoute(Pattern pattern, UUID patternViewId) { + List links = Collections.emptyList(); + +// List links = this.getPatternLinks(pattern); +// +// List outgoingEdges; +// try { +// outgoingEdges = this.patternRelationDescriptorService.findDirectedEdgeBySource(pattern); +// } catch (DirectedEdgeNotFoundException ex) { +// outgoingEdges = Collections.emptyList(); +// } +// if (null != outgoingEdges) { +// for (DirectedEdge directedEdge : outgoingEdges) { +// if (null != directedEdge.getPatternViews()) { +// // edge is part of pattern view, thus we reference the pattern view route +// List newLinks = directedEdge.getPatternViews().stream() +// .filter(patternViewDirectedEdge -> patternViewDirectedEdge.getPatternView().getId().equals(patternViewId)) +// .map(patternViewDirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) +// .getDirectedEdgeOfPatternViewById(patternViewDirectedEdge.getPatternView().getId(), patternViewDirectedEdge.getDirectedEdge().getId())).withRel("outgoingDirectedEdges") +// ).collect(Collectors.toList()); +// links.addAll(newLinks); +// } +// } +// } +// +// List ingoingEdges; +// try { +// ingoingEdges = this.patternRelationDescriptorService.findDirectedEdgeByTarget(pattern); +// } catch (DirectedEdgeNotFoundException ex) { +// ingoingEdges = Collections.emptyList(); +// } +// if (null != ingoingEdges) { +// for (DirectedEdge directedEdge : ingoingEdges) { +// if (null != directedEdge.getPatternViews()) { +// // edge is part of pattern view, thus we reference the pattern view route +// List newLinks = directedEdge.getPatternViews().stream() +// .filter(patternViewDirectedEdge -> patternViewDirectedEdge.getPatternView().getId().equals(patternViewId)) +// .map(patternViewDirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) +// .getDirectedEdgeOfPatternViewById(patternViewDirectedEdge.getPatternView().getId(), patternViewDirectedEdge.getDirectedEdge().getId())).withRel("ingoingDirectedEdges") +// ).collect(Collectors.toList()); +// links.addAll(newLinks); +// } +// } +// } +// +// List undirectedEdges; +// try { +// undirectedEdges = this.patternRelationDescriptorService.findUndirectedEdgeByPattern(pattern); +// } catch (UndirectedEdgeNotFoundException ex) { +// undirectedEdges = Collections.emptyList(); +// } +// if (null != undirectedEdges) { +// for (UndirectedEdge undirectedEdge : undirectedEdges) { +// if (null != undirectedEdge.getPatternViews()) { +// // edge is part of pattern view, thus we reference the pattern view route +// List newLinks = undirectedEdge.getPatternViews().stream() +// .filter(patternViewUndirectedEdge -> patternViewUndirectedEdge.getPatternView().getId().equals(patternViewId)) +// .map(patternViewUndirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) +// .getUndirectedEdgeOfPatternViewById(patternViewUndirectedEdge.getPatternView().getId(), patternViewUndirectedEdge.getUndirectedEdge().getId())).withRel("undirectedEdges") +// ).collect(Collectors.toList()); +// links.addAll(newLinks); +// } +// } +// } +// +// List outgoingFromPatternLanguage; +// try { +// outgoingFromPatternLanguage = this.patternRelationDescriptorService.findDirectedEdgeBySource(pattern); +// } catch (DirectedEdgeNotFoundException ex) { +// outgoingFromPatternLanguage = Collections.emptyList(); +// } +// if (null != outgoingFromPatternLanguage) { +// for (DirectedEdge directedEdge : outgoingFromPatternLanguage) { +// if (null != directedEdge.getPatternLanguage() && directedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { +// // edge is part of pattern language, thus reference the route to edge in pattern language +// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) +// .getDirectedEdgeOfPatternLanguageById(directedEdge.getPatternLanguage().getId(), directedEdge.getId())).withRel("outgoingDirectedEdgesFromPatternLanguage")); +// } +// } +// } +// +// List ingoingFromPatternLanguage; +// try { +// ingoingFromPatternLanguage = this.patternRelationDescriptorService.findDirectedEdgeByTarget(pattern); +// } catch (DirectedEdgeNotFoundException ex) { +// ingoingFromPatternLanguage = Collections.emptyList(); +// } +// if (null != ingoingFromPatternLanguage) { +// for (DirectedEdge directedEdge : ingoingFromPatternLanguage) { +// if (null != directedEdge.getPatternLanguage() && directedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { +// // edge is part of pattern language, thus reference the route to edge in pattern language +// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) +// .getDirectedEdgeOfPatternLanguageById(directedEdge.getPatternLanguage().getId(), directedEdge.getId())).withRel("ingoingDirectedEdgesFromPatternLanguage")); +// } +// } +// } +// +// List undirectedFromPatternLanguage; +// try { +// undirectedFromPatternLanguage = this.patternRelationDescriptorService.findUndirectedEdgeByPattern(pattern); +// } catch (UndirectedEdgeNotFoundException ex) { +// undirectedFromPatternLanguage = Collections.emptyList(); +// } +// if (null != undirectedFromPatternLanguage) { +// for (UndirectedEdge undirectedEdge : undirectedFromPatternLanguage) { +// if (null != undirectedEdge.getPatternLanguage() && undirectedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { +// // edge is part of pattern language, thus reference the route to edge in pattern language +// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) +// .getUndirectedEdgeOfPatternLanguageById(undirectedEdge.getPatternLanguage().getId(), undirectedEdge.getId())).withRel("undirectedEdgesFromPatternLanguage")); +// } +// } +// } + + return links; + } + + + static List getDesignModelPatternInstanceCollectionLinks(UUID designModelId) { + List links = new ArrayList<>(); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).withSelfRel() + .andAffordance(afford(methodOn(DesignModelController.class).addDesignModelPatternInstance(designModelId, null)))); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModel(designModelId)).withRel("designModel")); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).withRel("patterns")); + return links; + } + + + @GetMapping("") + public CollectionModel> getDesignModels() { + + List> patternViews = this.designModelService.getAllDesignModels() + .stream() + .map(patternView -> new EntityModel<>(patternView, + getDesignModelLinks(patternView))) + .collect(Collectors.toList()); + + return new CollectionModel<>(patternViews, getDesignModelCollectionLinks()); + } + + + @PostMapping("") + @CrossOrigin(exposedHeaders = "Location") + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity createDesignModel(@RequestBody DesignModel designModel) { + String nameAsCamelCase = CaseUtils.toCamelCase(designModel.getName(), false); + String uri = String.format("https://patternpedia.org/designModels/%s", nameAsCamelCase); + designModel.setUri(uri); + + DesignModel createdDesignModel = this.designModelService.createDesignModel(designModel); + + return ResponseEntity.created(linkTo(methodOn(DesignModelController.class) + .getDesignModel(createdDesignModel.getId())).toUri()).build(); + } + + + @GetMapping("/{designModelId}") + public EntityModel getDesignModel(@PathVariable UUID designModelId) { + DesignModel patternView = this.designModelService.getDesignModel(designModelId); + + return new EntityModel<>(patternView, getDesignModelLinks(patternView)); + } + + + @PutMapping("/{designModelId}") + public ResponseEntity putDesignModel(@PathVariable UUID designModelId, @RequestBody DesignModel designModel) { +// patternView = this.patternViewService.updateDesignModel(patternView); + + return ResponseEntity.ok(designModel); + } + + + @DeleteMapping("/{designModelId}") + public ResponseEntity deleteDesignModel(@PathVariable UUID designModelId) { +// this.patternViewService.deleteDesignModel(designModelId); + return ResponseEntity.noContent().build(); + } + + + @GetMapping("/{designModelId}/patterns") + CollectionModel> getDesignModelPatternInstances(@PathVariable UUID designModelId) { + List patternInstances = this.designModelService.getDesignModel(designModelId).getPatterns(); + + List> patterns = patternInstances.stream() + .map(GraphPatternModel::from) + .map(patternModel -> new EntityModel<>(patternModel))// TODO, getPatternLinksForDesignModelRoute(patternModel, designModelId))) + .collect(Collectors.toList()); + return new CollectionModel<>(patterns, getDesignModelPatternInstanceCollectionLinks(designModelId)); + } + + + @PostMapping("/{designModelId}/patterns") + @CrossOrigin(exposedHeaders = "Location") + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity addDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { + this.designModelService.addPatternToDesignModel(designModelId, pattern.getId()); + return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller + .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); + } + + + @DeleteMapping("/{designModelId}/patterns") + @CrossOrigin(exposedHeaders = "Location") + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity deleteDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { + this.designModelService.addPatternToDesignModel(designModelId, pattern.getId()); + return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller + .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java index ac6dccf..f41dcfd 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java @@ -1,20 +1,11 @@ package com.patternpedia.api.rest.controller; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - +import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.entities.PatternLanguage; import com.patternpedia.api.entities.PatternSchema; -import com.patternpedia.api.rest.model.PatternLanguageGraphModel; +import com.patternpedia.api.rest.model.GraphModel; import com.patternpedia.api.rest.model.PatternLanguageModel; import com.patternpedia.api.service.PatternLanguageService; - -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.text.CaseUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.CollectionModel; @@ -24,9 +15,15 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.afford; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; @RestController @CrossOrigin(allowedHeaders = "*", origins = "*") @@ -148,7 +145,7 @@ ResponseEntity updatePatternSchema(@PathVariable UUID patternLanguageId, @Req ResponseEntity getPatternLanguageGraph(@PathVariable UUID patternLanguageId) { Object graph = this.patternLanguageService.getGraphOfPatternLanguage(patternLanguageId); - PatternLanguageGraphModel model = new PatternLanguageGraphModel(); + GraphModel model = new GraphModel(); if (null == graph) { model.setGraph(this.objectMapper.createArrayNode()); } else { diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java b/src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java index 601f578..e07cfdf 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java @@ -1,19 +1,10 @@ package com.patternpedia.api.rest.controller; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import com.patternpedia.api.entities.PatternView; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.rest.model.PatternLanguageGraphModel; +import com.patternpedia.api.entities.PatternView; +import com.patternpedia.api.rest.model.GraphModel; import com.patternpedia.api.service.PatternViewService; - import org.apache.commons.text.CaseUtils; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; @@ -22,9 +13,15 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.afford; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; @RestController @CrossOrigin(allowedHeaders = "*", origins = "*") @@ -78,7 +75,7 @@ private static List getPatternViewLinks(PatternView patternView) { ResponseEntity getPatterViewGraph(@PathVariable UUID patternViewId) { Object graph = this.patternViewService.getGraphOfPatternView(patternViewId); - PatternLanguageGraphModel model = new PatternLanguageGraphModel(); + GraphModel model = new GraphModel(); if (null == graph) { model.setGraph(this.objectMapper.createArrayNode()); } else { diff --git a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java index 2f057ab..73a9f50 100644 --- a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java +++ b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java @@ -19,7 +19,8 @@ public class RestResponseExceptionHandler PatternSchemaNotFoundException.class, PatternViewNotFoundException.class, DirectedEdgeNotFoundException.class, - UndirectedEdgeNotFoundException.class + UndirectedEdgeNotFoundException.class, + DesignModelNotFoundException.class }) protected ResponseEntity handleEntityNotFoundExceptions(RuntimeException ex, WebRequest request) { return handleExceptionInternal(ex, ex.getMessage(), new HttpHeaders(), HttpStatus.NOT_FOUND, request); @@ -31,4 +32,4 @@ protected ResponseEntity handleEntityNotFoundExceptions(RuntimeException protected ResponseEntity handleNullPatternSchemaException(RuntimeException ex, WebRequest request) { return handleExceptionInternal(ex, ex.getMessage(), new HttpHeaders(), HttpStatus.BAD_REQUEST, request); } -} \ No newline at end of file +} diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternLanguageGraphModel.java b/src/main/java/com/patternpedia/api/rest/model/GraphModel.java similarity index 78% rename from src/main/java/com/patternpedia/api/rest/model/PatternLanguageGraphModel.java rename to src/main/java/com/patternpedia/api/rest/model/GraphModel.java index 4459c9f..f8d1035 100644 --- a/src/main/java/com/patternpedia/api/rest/model/PatternLanguageGraphModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/GraphModel.java @@ -5,6 +5,6 @@ @NoArgsConstructor @Data -public class PatternLanguageGraphModel { +public class GraphModel { private Object graph; } diff --git a/src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java b/src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java new file mode 100644 index 0000000..de51d12 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java @@ -0,0 +1,39 @@ +package com.patternpedia.api.rest.model; + +import com.patternpedia.api.entities.PatternLanguage; +import com.patternpedia.api.entities.designmodel.DesignModelPatternGraphData; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.hateoas.server.core.Relation; + + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +@Relation(value = "pattern", collectionRelation = "patterns") +public class GraphPatternModel extends PatternModel { + + protected DesignModelPatternGraphData graphData; + + + public static GraphPatternModel from(DesignModelPatternInstance dmpi) { + GraphPatternModel gpm = new GraphPatternModel(); + + + gpm.setName(dmpi.getPattern().getName()); + gpm.setId(dmpi.getId().getPatternInstanceId()); + gpm.setPattern(dmpi.getPattern()); + gpm.setUri(dmpi.getPattern().getUri()); + gpm.setIconUrl(dmpi.getPattern().getIconUrl()); + + PatternLanguage patternLanguage = dmpi.getPattern().getPatternLanguage(); + gpm.setPatternLanguageId(patternLanguage.getId()); + gpm.setPatternLanguageName(patternLanguage.getName()); + + gpm.setGraphData(dmpi.getGraphData()); + + return gpm; + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternModel.java b/src/main/java/com/patternpedia/api/rest/model/PatternModel.java index 6fd0a9f..0a6be1c 100644 --- a/src/main/java/com/patternpedia/api/rest/model/PatternModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/PatternModel.java @@ -1,34 +1,33 @@ package com.patternpedia.api.rest.model; -import java.util.UUID; - -import com.patternpedia.api.entities.Pattern; - import com.fasterxml.jackson.annotation.JsonIgnore; +import com.patternpedia.api.entities.Pattern; import com.patternpedia.api.entities.PatternLanguage; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import java.util.UUID; + @NoArgsConstructor @Data @EqualsAndHashCode(callSuper = false) public class PatternModel { - private UUID id; + protected UUID id; - private String uri; + protected String uri; - private String name; + protected String name; - private String iconUrl; + protected String iconUrl; - private UUID patternLanguageId; + protected UUID patternLanguageId; - private String patternLanguageName; + protected String patternLanguageName; @JsonIgnore - private Pattern pattern; + protected Pattern pattern; private PatternModel(Pattern pattern) { this.pattern = pattern; diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java new file mode 100644 index 0000000..c50032e --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -0,0 +1,53 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.designmodel.DesignModel; + +import java.util.List; +import java.util.UUID; + +public interface DesignModelService { + + DesignModel createDesignModel(DesignModel designModel); + + List getAllDesignModels(); + + DesignModel getDesignModel(UUID designModelId); + +// DesignModel getDesignModelByUri(String uri); +// +// DesignModel updateDesignModel(DesignModel designModel); +// +// void deleteDesignModel(UUID designModelId); + + void addPatternToDesignModel(UUID designModelId, UUID patternId); + +// List getPatternsOfDesignModel(UUID designModelId); +// +// Pattern getPatternOfDesignModelById(UUID designModelId, UUID patternId); +// +// void removePatternFromDesignModel(UUID designModelId, UUID patternId); +// +// void addDirectedEdgeToDesignModel(UUID designModelId, UUID directedEdgeId); +// +// DirectedEdge createDirectedEdgeAndAddToDesignModel(UUID designModelId, AddDirectedEdgeToViewRequest request); +// +// List getDirectedEdgesByDesignModelId(UUID designModelId); +// +// DirectedEdge getDirectedEdgeOfDesignModelById(UUID designModelId, UUID directedEdgeId); +// +// DirectedEdge updateDirectedEdgeOfDesignModel(UUID designModelId, UpdateDirectedEdgeRequest request); +// +// void removeDirectedEdgeFromDesignModel(UUID designModelId, UUID directedEdgeId); +// +// void addUndirectedEdgeToDesignModel(UUID designModelId, UUID undirectedEdgeId); +// +// UndirectedEdge createUndirectedEdgeAndAddToDesignModel(UUID designModelId, AddUndirectedEdgeToViewRequest request); +// +// List getUndirectedEdgesByDesignModelId(UUID designModelId); +// +// UndirectedEdge getUndirectedEdgeOfDesignModelById(UUID designModelId, UUID undirectedEdgeId); +// +// UndirectedEdge updateUndirectedEdgeOfDesignModel(UUID designModelId, UpdateUndirectedEdgeRequest request); +// +// void removeUndirectedEdgeFromDesignModel(UUID designModelId, UUID undirectedEdgeId); +} diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java new file mode 100644 index 0000000..9da6292 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -0,0 +1,346 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.Pattern; +import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.exception.DesignModelNotFoundException; +import com.patternpedia.api.exception.NullDesignModelException; +import com.patternpedia.api.repositories.*; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +@Transactional +public class DesignModelServiceImpl implements DesignModelService { + + private PatternService patternService; + // private PatternRelationDescriptorService patternRelationDescriptorService; + private DesignModelRepository designModelRepository; + private DesignModelPatternInstanceRepository designModelPatternInstanceRepository; +// private PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository; +// private PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository; +// private DirectedEdgeRepository directedEdgeRepository; +// private UndirectedEdgeReository undirectedEdgeReository; + + public DesignModelServiceImpl(PatternService patternService, + PatternRelationDescriptorService patternRelationDescriptorService, + DesignModelRepository designModelRepository, + DesignModelPatternInstanceRepository designModelPatternInstanceRepository, + PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository, + PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository, + DirectedEdgeRepository directedEdgeRepository, + UndirectedEdgeReository undirectedEdgeReository) { + this.patternService = patternService; +// this.patternRelationDescriptorService = patternRelationDescriptorService; + this.designModelRepository = designModelRepository; + this.designModelPatternInstanceRepository = designModelPatternInstanceRepository; +// this.patternViewDirectedEdgeRepository = patternViewDirectedEdgeRepository; +// this.patternViewUndirectedEdgeRepository = patternViewUndirectedEdgeRepository; +// this.directedEdgeRepository = directedEdgeRepository; +// this.undirectedEdgeReository = undirectedEdgeReository; + } + + + @Override + @Transactional + public DesignModel createDesignModel(DesignModel designModel) { + if (null == designModel) { + throw new NullDesignModelException(); + } + + return this.designModelRepository.save(designModel); + } + + + @Override + @Transactional(readOnly = true) + public List getAllDesignModels() { + return this.designModelRepository.findAll(); + } + + + @Override + @Transactional(readOnly = true) + public DesignModel getDesignModel(UUID designModelId) { + DesignModel designModel = this.designModelRepository.findById(designModelId) + .orElseThrow(() -> new DesignModelNotFoundException(designModelId)); + + return designModel; + } + + +// @Override +// @Transactional(readOnly = true) +// public PatternView getPatternViewByUri(String uri) { +// return this.patternViewRepository.findByUri(uri) +// .orElseThrow(() -> new PatternViewNotFoundException(String.format("PatternView with URI \"%s\" not found!", uri))); +// } +// +// @Override +// @Transactional +// public PatternView updatePatternView(PatternView patternView) { +// // We just support updating fields of PatternView but we don't support updates of sub resources such as pattern edges. +// // So we ignore patterns and edges. +// if (null == patternView) { +// throw new NullPatternViewException(); +// } +// +// if (!this.patternViewRepository.existsById(patternView.getId())) { +// throw new PatternViewNotFoundException(patternView); +// } +// +// PatternView oldPatternView = this.getPatternViewById(patternView.getId()); +// +// patternView.setPatterns(oldPatternView.getPatterns()); +// patternView.setDirectedEdges(oldPatternView.getDirectedEdges()); +// patternView.setUndirectedEdges(oldPatternView.getUndirectedEdges()); +// +// return this.patternViewRepository.save(patternView); +// } +// +// @Override +// @Transactional +// public void deletePatternView(UUID patternViewId) { +// PatternView patternView = this.getPatternViewById(patternViewId); +// +// // Remove edges that are just part of pattern view +// if (null != patternView.getDirectedEdges()) { +// patternView.getDirectedEdges().forEach(patternViewDirectedEdge -> { +// if (null == patternViewDirectedEdge.getDirectedEdge().getPatternLanguage()) { +// this.directedEdgeRepository.delete(patternViewDirectedEdge.getDirectedEdge()); +// } +// }); +// } +// +// if (null != patternView.getUndirectedEdges()) { +// patternView.getUndirectedEdges().forEach(patternViewUndirectedEdge -> { +// if (null == patternViewUndirectedEdge.getUndirectedEdge().getPatternLanguage()) { +// this.undirectedEdgeReository.delete(patternViewUndirectedEdge.getUndirectedEdge()); +// } +// }); +// } +// +// this.patternViewRepository.delete(patternView); +// } +// +// // Pattern Handling + + + @Override + @Transactional + public void addPatternToDesignModel(UUID patternViewId, UUID patternId) { + DesignModel designModel = this.getDesignModel(patternViewId); + Pattern pattern = this.patternService.getPatternById(patternId); + + DesignModelPatternInstance designModelPattern = new DesignModelPatternInstance(designModel, pattern); + this.designModelPatternInstanceRepository.save(designModelPattern); + } + + +// @Override +// @Transactional(readOnly = true) +// public List getPatternsOfPatternView(UUID patternViewId) { +// return this.patternViewPatternRepository.findAllByPatternViewId(patternViewId).stream() +// .map(PatternViewPattern::getPattern) +// .collect(Collectors.toList()); +// } +// +// @Override +// @Transactional(readOnly = true) +// public Pattern getPatternOfPatternViewById(UUID patternViewId, UUID patternId) { +// PatternViewPattern patternViewPattern = this.patternViewPatternRepository.findById(new PatternViewPatternId(patternViewId, patternId)) +// .orElseThrow(() -> new PatternNotFoundException(patternViewId, patternId, PatternGraphType.PATTERN_VIEW)); +// +// return patternViewPattern.getPattern(); +// } +// +// @Override +// @Transactional +// public void removePatternFromPatternView(UUID patternViewId, UUID patternId) { +// PatternViewPatternId id = new PatternViewPatternId(patternViewId, patternId); +// if (this.patternViewPatternRepository.existsById(id)) { +// this.patternViewPatternRepository.deleteById(id); +// } else { +// throw new PatternNotFoundException(patternViewId, patternId, PatternGraphType.PATTERN_VIEW); +// } +// } +// +// // DirectedEdge Handling +// +// @Override +// @Transactional +// public void addDirectedEdgeToPatternView(UUID patternViewId, UUID directedEdgeId) { +// PatternView patternView = this.getPatternViewById(patternViewId); +// DirectedEdge directedEdge = this.patternRelationDescriptorService.getDirectedEdgeById(directedEdgeId); +// +// PatternViewDirectedEdge patternViewDirectedEdge = new PatternViewDirectedEdge(patternView, directedEdge); +// this.patternViewDirectedEdgeRepository.save(patternViewDirectedEdge); +// } +// +// @Override +// @Transactional +// public DirectedEdge createDirectedEdgeAndAddToPatternView(UUID patternViewId, AddDirectedEdgeToViewRequest request) { +// PatternView patternView = this.getPatternViewById(patternViewId); +// +// DirectedEdge directedEdge = new DirectedEdge(); +// directedEdge.setSource(this.patternService.getPatternById(request.getSourcePatternId())); +// directedEdge.setTarget(this.patternService.getPatternById(request.getTargetPatternId())); +// directedEdge.setDescription(request.getDescription()); +// directedEdge.setType(request.getType()); +// directedEdge = this.patternRelationDescriptorService.createDirectedEdge(directedEdge); +// +// PatternViewDirectedEdge patternViewDirectedEdge = new PatternViewDirectedEdge(patternView, directedEdge); +// patternViewDirectedEdge = this.patternViewDirectedEdgeRepository.save(patternViewDirectedEdge); +// +// return patternViewDirectedEdge.getDirectedEdge(); +// } +// +// @Override +// @Transactional(readOnly = true) +// public List getDirectedEdgesByPatternViewId(UUID patternViewId) { +// return this.patternViewDirectedEdgeRepository.findByPatternViewId(patternViewId).stream() +// .map(PatternViewDirectedEdge::getDirectedEdge) +// .collect(Collectors.toList()); +// } +// +// @Override +// @Transactional(readOnly = true) +// public DirectedEdge getDirectedEdgeOfPatternViewById(UUID patternViewId, UUID directedEdgeId) { +// return this.patternViewDirectedEdgeRepository.findById(new PatternViewDirectedEdgeId(patternViewId, directedEdgeId)) +// .map(PatternViewDirectedEdge::getDirectedEdge) +// .orElseThrow(() -> new DirectedEdgeNotFoundException(patternViewId, directedEdgeId, PatternGraphType.PATTERN_VIEW)); +// } +// +// @Override +// @Transactional +// public DirectedEdge updateDirectedEdgeOfPatternView(UUID patternViewId, UpdateDirectedEdgeRequest request) { +// +// PatternViewDirectedEdge patternViewDirectedEdge = this.patternViewDirectedEdgeRepository +// .findById(new PatternViewDirectedEdgeId(patternViewId, request.getDirectedEdgeId())) +// .orElseThrow(() -> new DirectedEdgeNotFoundException(patternViewId, request.getDirectedEdgeId(), PatternGraphType.PATTERN_VIEW)); +// +// DirectedEdge directedEdge = patternViewDirectedEdge.getDirectedEdge(); +// directedEdge.setType(request.getType()); +// directedEdge.setDescription(request.getDescription()); +// +// Pattern source = this.patternService.getPatternById(request.getSourcePatternId()); +// directedEdge.setSource(source); +// +// Pattern target = this.patternService.getPatternById(request.getTargetPatternId()); +// directedEdge.setTarget(target); +// +// return this.patternRelationDescriptorService.updateDirectedEdge(directedEdge); +// } +// +// @Override +// @Transactional +// public void removeDirectedEdgeFromPatternView(UUID patternViewId, UUID directedEdgeId) throws DirectedEdgeNotFoundException { +// DirectedEdge directedEdge = this.patternRelationDescriptorService.getDirectedEdgeById(directedEdgeId); +// PatternView patternView = this.getPatternViewById(patternViewId); +// PatternViewDirectedEdge patternViewDirectedEdge = this.patternViewDirectedEdgeRepository.getOne(new PatternViewDirectedEdgeId(patternViewId, directedEdgeId)); +// +// if (null != patternViewDirectedEdge) { +// this.patternViewDirectedEdgeRepository.delete(patternViewDirectedEdge); +// } else { +// throw new DirectedEdgeNotFoundException(patternView, directedEdgeId); +// } +// +// if (null == directedEdge.getPatternLanguage()) { +// // directed edge is not part of pattern language, thus remove it if it is not part of other views +// if (!this.patternViewDirectedEdgeRepository.existsByDirectedEdgeId(directedEdgeId)) { +// this.directedEdgeRepository.delete(directedEdge); +// } +// } +// } +// +// // UndirectedEdge Handling +// +// @Override +// @Transactional +// public void addUndirectedEdgeToPatternView(UUID patternViewId, UUID undirectedEdgeId) { +// PatternView patternView = this.getPatternViewById(patternViewId); +// UndirectedEdge undirectedEdge = this.patternRelationDescriptorService.getUndirectedEdgeById(undirectedEdgeId); +// +// PatternViewUndirectedEdge patternViewUndirectedEdge = new PatternViewUndirectedEdge(patternView, undirectedEdge); +// this.patternViewUndirectedEdgeRepository.save(patternViewUndirectedEdge); +// } +// +// @Override +// @Transactional +// public UndirectedEdge createUndirectedEdgeAndAddToPatternView(UUID patternViewId, AddUndirectedEdgeToViewRequest request) { +// PatternView patternView = this.getPatternViewById(patternViewId); +// +// UndirectedEdge undirectedEdge = new UndirectedEdge(); +// undirectedEdge.setP1(this.patternService.getPatternById(request.getPattern1Id())); +// undirectedEdge.setP2(this.patternService.getPatternById(request.getPattern2Id())); +// undirectedEdge.setDescription(request.getDescription()); +// undirectedEdge.setType(request.getType()); +// undirectedEdge = this.patternRelationDescriptorService.createUndirectedEdge(undirectedEdge); +// +// PatternViewUndirectedEdge patternViewUndirectedEdge = new PatternViewUndirectedEdge(patternView, undirectedEdge); +// patternViewUndirectedEdge = this.patternViewUndirectedEdgeRepository.save(patternViewUndirectedEdge); +// +// return patternViewUndirectedEdge.getUndirectedEdge(); +// } +// +// @Override +// @Transactional(readOnly = true) +// public List getUndirectedEdgesByPatternViewId(UUID patternViewId) { +// return this.patternViewUndirectedEdgeRepository.findByPatternViewId(patternViewId).stream() +// .map(PatternViewUndirectedEdge::getUndirectedEdge) +// .collect(Collectors.toList()); +// } +// +// @Override +// @Transactional(readOnly = true) +// public UndirectedEdge getUndirectedEdgeOfPatternViewById(UUID patternViewId, UUID undirectedEdgeId) { +// return this.patternViewUndirectedEdgeRepository.findById(new PatternViewUndirectedEdgeId(patternViewId, undirectedEdgeId)) +// .map(PatternViewUndirectedEdge::getUndirectedEdge) +// .orElseThrow(() -> new UndirectedEdgeNotFoundException(patternViewId, undirectedEdgeId, PatternGraphType.PATTERN_VIEW)); +// } +// +// @Override +// @Transactional +// public UndirectedEdge updateUndirectedEdgeOfPatternView(UUID patternViewId, UpdateUndirectedEdgeRequest request) { +// PatternViewUndirectedEdge edge = this.patternViewUndirectedEdgeRepository +// .findById(new PatternViewUndirectedEdgeId(patternViewId, request.getUndirectedEdgeId())) +// .orElseThrow(() -> new UndirectedEdgeNotFoundException(patternViewId, request.getUndirectedEdgeId(), PatternGraphType.PATTERN_VIEW)); +// +// UndirectedEdge undirectedEdge = edge.getUndirectedEdge(); +// undirectedEdge.setType(request.getType()); +// undirectedEdge.setDescription(request.getDescription()); +// +// Pattern p1 = this.patternService.getPatternById(request.getPattern1Id()); +// undirectedEdge.setP1(p1); +// +// Pattern p2 = this.patternService.getPatternById(request.getPattern2Id()); +// undirectedEdge.setP2(p2); +// +// return this.patternRelationDescriptorService.updateUndirectedEdge(undirectedEdge); +// } +// +// @Override +// @Transactional +// public void removeUndirectedEdgeFromPatternView(UUID patternViewId, UUID undirectedEdgeId) { +// UndirectedEdge undirectedEdge = this.patternRelationDescriptorService.getUndirectedEdgeById(undirectedEdgeId); +// PatternView patternView = this.getPatternViewById(patternViewId); +// PatternViewUndirectedEdge patternViewUndirectedEdge = this.patternViewUndirectedEdgeRepository +// .getOne(new PatternViewUndirectedEdgeId(patternViewId, undirectedEdgeId)); +// +// if (null != patternViewUndirectedEdge) { +// this.patternViewUndirectedEdgeRepository.delete(patternViewUndirectedEdge); +// } else { +// throw new UndirectedEdgeNotFoundException(patternView, undirectedEdgeId); +// } +// +// if (null == undirectedEdge.getPatternLanguage()) { +// // directed edge is not part of pattern language, thus remove it if it is not part of other views +// if (!this.patternViewUndirectedEdgeRepository.existsByUndirectedEdgeId(undirectedEdgeId)) { +// this.undirectedEdgeReository.delete(undirectedEdge); +// } +// } +// } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2a27bb6..b4dab58 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -12,4 +12,6 @@ spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default -#okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 \ No newline at end of file +#okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 + +springdoc.swagger-ui.path: /swagger-ui.html From 83203a6cce981e089542cb4af4bb6e09bfb9b64b Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:59:19 +0200 Subject: [PATCH 02/10] Basic DM editor implementation --- .../api/entities/designmodel/DesignModel.java | 2 +- .../designmodel/DesignModelDirectedEdge.java | 38 ------ .../designmodel/DesignModelPatternEdge.java | 64 +++++++++++ ...eId.java => DesignModelPatternEdgeId.java} | 8 +- .../designmodel/DesignModelPatternId.java | 22 ---- .../DesignModelPatternInstance.java | 14 +-- .../DesignModelNotFoundException.java | 2 +- ...ModelPatternInstanceNotFoundException.java | 21 ++++ .../DesignModelPatternEdgeRepository.java | 18 +++ .../DesignModelPatternInstanceRepository.java | 5 +- .../repositories/DesignModelRepository.java | 2 + .../controller/DesignModelController.java | 54 +++++++-- .../RestResponseExceptionHandler.java | 26 +++-- .../patternpedia/api/rest/model/EdgeDTO.java | 41 +++++++ .../api/rest/model/ErrorMessageDTO.java | 32 ++++++ ...ternModel.java => PatternInstanceDTO.java} | 16 ++- .../api/rest/model/PositionDTO.java | 16 +++ .../api/service/DesignModelService.java | 18 ++- .../api/service/DesignModelServiceImpl.java | 108 +++++++++++++++--- 19 files changed, 389 insertions(+), 118 deletions(-) delete mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdge.java rename src/main/java/com/patternpedia/api/entities/designmodel/{DesignModelDirectedEdgeId.java => DesignModelPatternEdgeId.java} (71%) delete mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java create mode 100644 src/main/java/com/patternpedia/api/exception/DesignModelPatternInstanceNotFoundException.java create mode 100644 src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/ErrorMessageDTO.java rename src/main/java/com/patternpedia/api/rest/model/{GraphPatternModel.java => PatternInstanceDTO.java} (75%) create mode 100644 src/main/java/com/patternpedia/api/rest/model/PositionDTO.java diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java index 0fa143b..a8e4133 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java @@ -26,7 +26,7 @@ public class DesignModel extends EntityWithURI { @JsonIgnore @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) - private List directedEdges; + private List directedEdges; @JsonIgnore @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java deleted file mode 100644 index 4153d39..0000000 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdge.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.patternpedia.api.entities.designmodel; - -import com.patternpedia.api.entities.DirectedEdge; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; - -@Entity -@Data -@NoArgsConstructor -@EqualsAndHashCode -public class DesignModelDirectedEdge { - - @EmbeddedId - @EqualsAndHashCode.Exclude - private DesignModelDirectedEdgeId id; - - @ManyToOne - @MapsId("designModelId") - @EqualsAndHashCode.Include - private DesignModel designModel; - - @ManyToOne - @MapsId("directedEdgeId") - @EqualsAndHashCode.Include - private DirectedEdge directedEdge; - - public DesignModelDirectedEdge(DesignModel designModel, DirectedEdge directedEdge) { - this.designModel = designModel; - this.directedEdge = directedEdge; - this.id = new DesignModelDirectedEdgeId(designModel.getId(), directedEdge.getId()); - } -} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdge.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdge.java new file mode 100644 index 0000000..707714c --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdge.java @@ -0,0 +1,64 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +import static java.lang.Boolean.TRUE; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +public class DesignModelPatternEdge { + + @EmbeddedId + @EqualsAndHashCode.Exclude + private DesignModelPatternEdgeId edgeId; + + @ManyToOne + @EqualsAndHashCode.Include + private DesignModel designModel; + + @ManyToOne + @MapsId("patternInstanceId1") + @EqualsAndHashCode.Include + private DesignModelPatternInstance patternInstance1; + + @ManyToOne + @MapsId("patternInstanceId2") + @EqualsAndHashCode.Include + private DesignModelPatternInstance patternInstance2; + + private Boolean isDirectedEdge; + + private String type; + + private String description; + + + public boolean isDirectedEdge() { + return TRUE.equals(isDirectedEdge); + } + + public void setPatternInstance1(DesignModelPatternInstance patternInstance) { + if(edgeId == null) { + this.edgeId = new DesignModelPatternEdgeId(); + } + this.edgeId.setPatternInstanceId1(patternInstance.getPatternInstanceId()); + this.patternInstance1 = patternInstance; + } + + public void setPatternInstance2(DesignModelPatternInstance patternInstance) { + if(edgeId == null) { + this.edgeId = new DesignModelPatternEdgeId(); + } + this.edgeId.setPatternInstanceId2(patternInstance.getPatternInstanceId()); + this.patternInstance2 = patternInstance; + } +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdgeId.java similarity index 71% rename from src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java rename to src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdgeId.java index a10eb84..5ffc1b0 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelDirectedEdgeId.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternEdgeId.java @@ -14,7 +14,9 @@ @AllArgsConstructor @Data @EqualsAndHashCode(callSuper = false) -public class DesignModelDirectedEdgeId implements Serializable { - protected UUID designModelId; - protected UUID directedEdgeId; +public class DesignModelPatternEdgeId implements Serializable { + + protected UUID patternInstanceId1; + + protected UUID patternInstanceId2; } diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java deleted file mode 100644 index 575fc23..0000000 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternId.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.patternpedia.api.entities.designmodel; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import javax.persistence.Embeddable; -import java.io.Serializable; -import java.util.UUID; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class DesignModelPatternId implements Serializable { - - protected UUID designModelId; - protected UUID patternId; - protected UUID patternInstanceId; -} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java index 30525c0..1fb1502 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java @@ -6,10 +6,7 @@ import lombok.NoArgsConstructor; import org.springframework.hateoas.server.core.Relation; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; +import javax.persistence.*; import java.util.UUID; @Entity @@ -19,17 +16,15 @@ @Relation(value = "pattern", collectionRelation = "patterns") public class DesignModelPatternInstance { - @EmbeddedId - @EqualsAndHashCode.Exclude - private DesignModelPatternId id; + @Id + @GeneratedValue(generator = "pg-uuid") + protected UUID patternInstanceId; @ManyToOne - @MapsId("designModelId") @EqualsAndHashCode.Include private DesignModel designModel; @ManyToOne - @MapsId("patternId") @EqualsAndHashCode.Include private Pattern pattern; @@ -39,6 +34,5 @@ public class DesignModelPatternInstance { public DesignModelPatternInstance(DesignModel designModel, Pattern pattern) { this.designModel = designModel; this.pattern = pattern; - this.id = new DesignModelPatternId(designModel.getId(), pattern.getId(), UUID.randomUUID()); } } diff --git a/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java b/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java index 01be3e8..4261681 100644 --- a/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java +++ b/src/main/java/com/patternpedia/api/exception/DesignModelNotFoundException.java @@ -16,6 +16,6 @@ public DesignModelNotFoundException(UUID designModelId) { } public DesignModelNotFoundException(DesignModel designModel) { - super(String.format("PatternView \"%s\" not found!", designModel.getId())); + super(String.format("DesignModel \"%s\" not found!", designModel.getId())); } } diff --git a/src/main/java/com/patternpedia/api/exception/DesignModelPatternInstanceNotFoundException.java b/src/main/java/com/patternpedia/api/exception/DesignModelPatternInstanceNotFoundException.java new file mode 100644 index 0000000..ec76f48 --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/DesignModelPatternInstanceNotFoundException.java @@ -0,0 +1,21 @@ +package com.patternpedia.api.exception; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; + +import java.util.UUID; + +public class DesignModelPatternInstanceNotFoundException extends ResourceNotFoundException { + + public DesignModelPatternInstanceNotFoundException(String message) { + super(message); + } + + public DesignModelPatternInstanceNotFoundException(UUID designModelId, UUID patternInstanceId) { + super(String.format("PatternInstance \"%s\" not found in DesignModel \"%s\"!", patternInstanceId, designModelId)); + } + + public DesignModelPatternInstanceNotFoundException(DesignModelPatternInstance patternInstance) { + super(String.format("PatternInstance \"%s\" not found in DesignModel \"%s\"!", patternInstance.getPatternInstanceId(), patternInstance.getDesignModel().getId())); + } +} diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java new file mode 100644 index 0000000..30e96df --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java @@ -0,0 +1,18 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdgeId; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@RepositoryRestResource(exported = false) +public interface DesignModelPatternEdgeRepository extends JpaRepository { + + Optional> findAllByDesignModelId(UUID patternViewId); + + Optional findTopByDesignModelIdAndEdgeId(UUID designModelId, DesignModelPatternEdgeId designModelPatternEdgeId); +} diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java index 87a66e2..4ecdbdb 100644 --- a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java @@ -1,7 +1,6 @@ package com.patternpedia.api.repositories; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; -import com.patternpedia.api.entities.designmodel.DesignModelPatternId; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource; @@ -10,9 +9,9 @@ import java.util.UUID; @RepositoryRestResource(exported = false) -public interface DesignModelPatternInstanceRepository extends JpaRepository { +public interface DesignModelPatternInstanceRepository extends JpaRepository { Optional> findAllByDesignModelId(UUID patternViewId); - List findAllByPatternId(UUID patternId); + Optional findTopByDesignModel_IdAndPatternInstanceId(UUID designModelId, UUID patternInstanceId); } diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java index c0f21bf..8a9cd5c 100644 --- a/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelRepository.java @@ -11,4 +11,6 @@ public interface DesignModelRepository extends JpaRepository Optional findByUri(String uri); boolean existsByUri(String uri); + + boolean existsById(UUID designModelId); } diff --git a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java index 43675b6..012fa18 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java @@ -4,8 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.entities.Pattern; import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; -import com.patternpedia.api.rest.model.GraphPatternModel; +import com.patternpedia.api.rest.model.EdgeDTO; +import com.patternpedia.api.rest.model.PatternInstanceDTO; +import com.patternpedia.api.rest.model.PositionDTO; import com.patternpedia.api.service.DesignModelService; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.text.CaseUtils; @@ -28,7 +31,7 @@ @RestController @CommonsLog @CrossOrigin(allowedHeaders = "*", origins = "*") -@RequestMapping(value = "/designModels", produces = "application/hal+json") +@RequestMapping(value = "/design-models", produces = "application/hal+json") public class DesignModelController { private DesignModelService designModelService; @@ -250,11 +253,11 @@ public ResponseEntity deleteDesignModel(@PathVariable UUID designModelId) { @GetMapping("/{designModelId}/patterns") - CollectionModel> getDesignModelPatternInstances(@PathVariable UUID designModelId) { + CollectionModel> getDesignModelPatternInstances(@PathVariable UUID designModelId) { List patternInstances = this.designModelService.getDesignModel(designModelId).getPatterns(); - List> patterns = patternInstances.stream() - .map(GraphPatternModel::from) + List> patterns = patternInstances.stream() + .map(PatternInstanceDTO::from) .map(patternModel -> new EntityModel<>(patternModel))// TODO, getPatternLinksForDesignModelRoute(patternModel, designModelId))) .collect(Collectors.toList()); return new CollectionModel<>(patterns, getDesignModelPatternInstanceCollectionLinks(designModelId)); @@ -265,18 +268,51 @@ CollectionModel> getDesignModelPatternInstances(@ @CrossOrigin(exposedHeaders = "Location") @ResponseStatus(HttpStatus.CREATED) public ResponseEntity addDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { - this.designModelService.addPatternToDesignModel(designModelId, pattern.getId()); + this.designModelService.addPatternInstance(designModelId, pattern.getId()); return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); } + @PutMapping("/{designModelId}/patterns/{patternInstanceId}/position") + public ResponseEntity putDesignModelPatternInstancePosition(@PathVariable UUID designModelId, @PathVariable UUID patternInstanceId, @RequestBody PositionDTO position) { + this.designModelService.updatePatternInstancePosition(designModelId, patternInstanceId, position.getX(), position.getY()); + return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller + .getPatternOfPatternViewById(designModelId, patternInstanceId)).toUri()).build(); + } + + @DeleteMapping("/{designModelId}/patterns") - @CrossOrigin(exposedHeaders = "Location") - @ResponseStatus(HttpStatus.CREATED) public ResponseEntity deleteDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { - this.designModelService.addPatternToDesignModel(designModelId, pattern.getId()); + this.designModelService.addPatternInstance(designModelId, pattern.getId()); return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); } + + + @PostMapping("/{designModelId}/edges") + @CrossOrigin(exposedHeaders = "Location") + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity addDesignModelEdge(@PathVariable UUID designModelId, @RequestBody EdgeDTO edgeDTO) { + + this.designModelService.addEdge(designModelId, edgeDTO.getFirstPatternId(), edgeDTO.getSecondPatternId(), + edgeDTO.isDirectedEdge(), edgeDTO.getType(), edgeDTO.getDescription()); + + return ResponseEntity.created(linkTo(methodOn(DesignModelController.class) + .addDesignModelEdge(designModelId, null)).toUri()).build(); + } + + + @GetMapping("/{designModelId}/edges") + public ResponseEntity getDesignModelEdge(@PathVariable UUID designModelId) { + + List designModelPatternEdges = this.designModelService.getEdges(designModelId); + + return ResponseEntity.ok(designModelPatternEdges); +// return new CollectionModel( +// designModelPatternEdges, +// (Iterable) ResponseEntity.created(linkTo(methodOn(DesignModelController.class) +// .addDesignModelEdge(designModelId, null)).toUri()).build() +// ); + } } diff --git a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java index 73a9f50..aa86467 100644 --- a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java +++ b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java @@ -1,6 +1,9 @@ package com.patternpedia.api.rest.exception; import com.patternpedia.api.exception.*; +import com.patternpedia.api.rest.model.ErrorMessageDTO; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -9,27 +12,32 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + @ControllerAdvice public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(value = { - PatternLanguageNotFoundException.class, - PatternNotFoundException.class, - PatternSchemaNotFoundException.class, - PatternViewNotFoundException.class, - DirectedEdgeNotFoundException.class, - UndirectedEdgeNotFoundException.class, - DesignModelNotFoundException.class + ResourceNotFoundException.class }) protected ResponseEntity handleEntityNotFoundExceptions(RuntimeException ex, WebRequest request) { - return handleExceptionInternal(ex, ex.getMessage(), new HttpHeaders(), HttpStatus.NOT_FOUND, request); + ErrorMessageDTO errorMessage = new ErrorMessageDTO(ex.getMessage(), HttpStatus.NOT_FOUND); + return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.NOT_FOUND, request); } @ExceptionHandler(value = { NullPatternSchemaException.class }) protected ResponseEntity handleNullPatternSchemaException(RuntimeException ex, WebRequest request) { - return handleExceptionInternal(ex, ex.getMessage(), new HttpHeaders(), HttpStatus.BAD_REQUEST, request); + ErrorMessageDTO errorMessage = new ErrorMessageDTO(ex.getMessage(), HttpStatus.BAD_REQUEST); + return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.BAD_REQUEST, request); + } + + @ExceptionHandler({ + InvalidDataAccessResourceUsageException.class + }) + protected ResponseEntity handleStorageExceptions(RuntimeException ex, WebRequest request) { + ErrorMessageDTO errorMessage = new ErrorMessageDTO(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request); } } diff --git a/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java b/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java new file mode 100644 index 0000000..6b8e1af --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java @@ -0,0 +1,41 @@ +package com.patternpedia.api.rest.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.hateoas.server.core.Relation; + +import java.util.UUID; + + +@NoArgsConstructor +@Data +@EqualsAndHashCode +@Relation(value = "edge", collectionRelation = "edges") +public class EdgeDTO { + + private UUID sourcePatternId; + + private UUID targetPatternId; + + private UUID pattern1Id; + + private UUID pattern2Id; + + private String type; + + private String description; + + + public boolean isDirectedEdge() { + return sourcePatternId != null && targetPatternId != null; + } + + public UUID getFirstPatternId() { + return isDirectedEdge() ? sourcePatternId : pattern1Id; + } + + public UUID getSecondPatternId() { + return isDirectedEdge() ? targetPatternId : pattern2Id; + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/ErrorMessageDTO.java b/src/main/java/com/patternpedia/api/rest/model/ErrorMessageDTO.java new file mode 100644 index 0000000..3d01518 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/ErrorMessageDTO.java @@ -0,0 +1,32 @@ +package com.patternpedia.api.rest.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import org.springframework.http.HttpStatus; + +import java.time.ZonedDateTime; + + +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ErrorMessageDTO { + + protected Integer status; + protected String message; + protected ZonedDateTime time; + + public ErrorMessageDTO(String message) { + this.message = message; + this.time = ZonedDateTime.now(); + } + + public ErrorMessageDTO(String message, int status) { + this(message); + this.status = status; + } + + public ErrorMessageDTO(String message, HttpStatus status) { + this(message); + this.status = status.value(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java b/src/main/java/com/patternpedia/api/rest/model/PatternInstanceDTO.java similarity index 75% rename from src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java rename to src/main/java/com/patternpedia/api/rest/model/PatternInstanceDTO.java index de51d12..91a9a66 100644 --- a/src/main/java/com/patternpedia/api/rest/model/GraphPatternModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/PatternInstanceDTO.java @@ -8,22 +8,30 @@ import lombok.NoArgsConstructor; import org.springframework.hateoas.server.core.Relation; +import java.util.UUID; + @NoArgsConstructor @Data @EqualsAndHashCode(callSuper = false) @Relation(value = "pattern", collectionRelation = "patterns") -public class GraphPatternModel extends PatternModel { +public class PatternInstanceDTO extends PatternModel { protected DesignModelPatternGraphData graphData; + protected UUID patternLanguageId; + + protected double x; + + protected double y; + - public static GraphPatternModel from(DesignModelPatternInstance dmpi) { - GraphPatternModel gpm = new GraphPatternModel(); + public static PatternInstanceDTO from(DesignModelPatternInstance dmpi) { + PatternInstanceDTO gpm = new PatternInstanceDTO(); gpm.setName(dmpi.getPattern().getName()); - gpm.setId(dmpi.getId().getPatternInstanceId()); + gpm.setId(dmpi.getPatternInstanceId()); gpm.setPattern(dmpi.getPattern()); gpm.setUri(dmpi.getPattern().getUri()); gpm.setIconUrl(dmpi.getPattern().getIconUrl()); diff --git a/src/main/java/com/patternpedia/api/rest/model/PositionDTO.java b/src/main/java/com/patternpedia/api/rest/model/PositionDTO.java new file mode 100644 index 0000000..6659607 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/PositionDTO.java @@ -0,0 +1,16 @@ +package com.patternpedia.api.rest.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class PositionDTO { + + protected double x; + + protected double y; +} diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java index c50032e..f1b95c9 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelService.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -1,6 +1,9 @@ package com.patternpedia.api.service; +import com.patternpedia.api.entities.Pattern; import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import java.util.List; import java.util.UUID; @@ -19,7 +22,20 @@ public interface DesignModelService { // // void deleteDesignModel(UUID designModelId); - void addPatternToDesignModel(UUID designModelId, UUID patternId); + void addPatternInstance(UUID designModelId, UUID patternId); + + DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID patternInstanceId); + + void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern); + + void updatePatternInstancePosition(UUID designModelId, UUID patternInstanceId, Double x, Double y); + +// void addEdge(UUID designModelId, DesignModelEdge edge); + + List getEdges(UUID designModelId); + + void addEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2, Boolean directed, String type, String description); + // List getPatternsOfDesignModel(UUID designModelId); // diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java index 9da6292..a178fab 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -1,14 +1,16 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.Pattern; -import com.patternpedia.api.entities.designmodel.DesignModel; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.entities.designmodel.*; import com.patternpedia.api.exception.DesignModelNotFoundException; +import com.patternpedia.api.exception.DesignModelPatternInstanceNotFoundException; import com.patternpedia.api.exception.NullDesignModelException; import com.patternpedia.api.repositories.*; +import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -20,6 +22,7 @@ public class DesignModelServiceImpl implements DesignModelService { // private PatternRelationDescriptorService patternRelationDescriptorService; private DesignModelRepository designModelRepository; private DesignModelPatternInstanceRepository designModelPatternInstanceRepository; + private DesignModelPatternEdgeRepository designModelPatternEdgeRepository; // private PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository; // private PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository; // private DirectedEdgeRepository directedEdgeRepository; @@ -29,6 +32,7 @@ public DesignModelServiceImpl(PatternService patternService, PatternRelationDescriptorService patternRelationDescriptorService, DesignModelRepository designModelRepository, DesignModelPatternInstanceRepository designModelPatternInstanceRepository, + DesignModelPatternEdgeRepository designModelPatternEdgeRepository, PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository, PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository, DirectedEdgeRepository directedEdgeRepository, @@ -37,6 +41,7 @@ public DesignModelServiceImpl(PatternService patternService, // this.patternRelationDescriptorService = patternRelationDescriptorService; this.designModelRepository = designModelRepository; this.designModelPatternInstanceRepository = designModelPatternInstanceRepository; + this.designModelPatternEdgeRepository = designModelPatternEdgeRepository; // this.patternViewDirectedEdgeRepository = patternViewDirectedEdgeRepository; // this.patternViewUndirectedEdgeRepository = patternViewUndirectedEdgeRepository; // this.directedEdgeRepository = directedEdgeRepository; @@ -58,7 +63,11 @@ public DesignModel createDesignModel(DesignModel designModel) { @Override @Transactional(readOnly = true) public List getAllDesignModels() { - return this.designModelRepository.findAll(); + try { + return this.designModelRepository.findAll(); + } catch (InvalidDataAccessResourceUsageException e) { + return Collections.emptyList(); + } } @@ -68,7 +77,18 @@ public DesignModel getDesignModel(UUID designModelId) { DesignModel designModel = this.designModelRepository.findById(designModelId) .orElseThrow(() -> new DesignModelNotFoundException(designModelId)); - return designModel; + return designModel; + } + + + @Override + @Transactional(readOnly = true) + public DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID patternInstanceId) { + DesignModelPatternInstance patternInstance = this.designModelPatternInstanceRepository + .findTopByDesignModel_IdAndPatternInstanceId(designModelId, patternInstanceId) + .orElseThrow(() -> new DesignModelPatternInstanceNotFoundException(designModelId, patternInstanceId)); + + return patternInstance; } @@ -131,7 +151,7 @@ public DesignModel getDesignModel(UUID designModelId) { @Override @Transactional - public void addPatternToDesignModel(UUID patternViewId, UUID patternId) { + public void addPatternInstance(UUID patternViewId, UUID patternId) { DesignModel designModel = this.getDesignModel(patternViewId); Pattern pattern = this.patternService.getPatternById(patternId); @@ -140,6 +160,30 @@ public void addPatternToDesignModel(UUID patternViewId, UUID patternId) { } + @Override + @Transactional + public void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern) { +// List patternList = this.designModelPatternInstanceRepository.findTopByDesignModel_IdAndPatternInstanceId(patternInstanceId); + } + + + @Override + @Transactional + public void updatePatternInstancePosition(UUID designModelId, UUID patternInstanceId, Double x, Double y) { + DesignModelPatternInstance patternInstance = this.designModelPatternInstanceRepository + .findTopByDesignModel_IdAndPatternInstanceId(designModelId, patternInstanceId) + .orElseThrow(() -> new DesignModelPatternInstanceNotFoundException(designModelId, patternInstanceId)); + + DesignModelPatternGraphData graphData = new DesignModelPatternGraphData(); + graphData.setX(x); + graphData.setY(y); + + patternInstance.setGraphData(graphData); + + this.designModelPatternInstanceRepository.save(patternInstance); + } + + // @Override // @Transactional(readOnly = true) // public List getPatternsOfPatternView(UUID patternViewId) { @@ -168,18 +212,48 @@ public void addPatternToDesignModel(UUID patternViewId, UUID patternId) { // } // } // -// // DirectedEdge Handling -// -// @Override -// @Transactional -// public void addDirectedEdgeToPatternView(UUID patternViewId, UUID directedEdgeId) { -// PatternView patternView = this.getPatternViewById(patternViewId); -// DirectedEdge directedEdge = this.patternRelationDescriptorService.getDirectedEdgeById(directedEdgeId); -// -// PatternViewDirectedEdge patternViewDirectedEdge = new PatternViewDirectedEdge(patternView, directedEdge); -// this.patternViewDirectedEdgeRepository.save(patternViewDirectedEdge); -// } -// + + + // DirectedEdge Handling + @Override + @Transactional(readOnly = true) + public List getEdges(UUID designModelId) { + List edgeList = this.designModelPatternEdgeRepository.findAllByDesignModelId(designModelId).orElse(Collections.emptyList()); + + if (edgeList.isEmpty() && !this.designModelRepository.existsById(designModelId)) { + throw new DesignModelNotFoundException(designModelId); + } + + return edgeList; + } + + + @Override + @Transactional + public void addEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2, Boolean directed, String type, String description) { + DesignModel designModel = this.designModelRepository.findById(designModelId) + .orElseThrow(() -> new DesignModelNotFoundException(designModelId)); + + DesignModelPatternInstance patternInstance1 = this.designModelPatternInstanceRepository + .findTopByDesignModel_IdAndPatternInstanceId(designModelId, patternInstanceId1) + .orElseThrow(() -> new DesignModelPatternInstanceNotFoundException(designModelId, patternInstanceId1)); + + DesignModelPatternInstance patternInstance2 = this.designModelPatternInstanceRepository + .findTopByDesignModel_IdAndPatternInstanceId(designModelId, patternInstanceId2) + .orElseThrow(() -> new DesignModelPatternInstanceNotFoundException(designModelId, patternInstanceId2)); + + DesignModelPatternEdge designModelEdge = new DesignModelPatternEdge(); + designModelEdge.setDesignModel(designModel); + designModelEdge.setPatternInstance1(patternInstance1); + designModelEdge.setPatternInstance2(patternInstance2); + designModelEdge.setIsDirectedEdge(directed); + designModelEdge.setType(type); + designModelEdge.setDescription(description); + + this.designModelPatternEdgeRepository.save(designModelEdge); + } + + // @Override // @Transactional // public DirectedEdge createDirectedEdgeAndAddToPatternView(UUID patternViewId, AddDirectedEdgeToViewRequest request) { From 38629d21bef95f57ba1179a679ba4fefac8b0271 Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Wed, 24 Jun 2020 23:28:34 +0200 Subject: [PATCH 03/10] Design model editor implementation --- .../designmodel/ConcreteSolution.java | 41 +++++++++++++++ .../designmodel/ConcreteSolutionOption.java | 30 +++++++++++ .../ConcreteSolutionNotFoundException.java | 21 ++++++++ .../ConcreteSolutionRepository.java | 21 ++++++++ .../DesignModelPatternEdgeRepository.java | 2 + .../DesignModelPatternInstanceRepository.java | 2 + .../ConcreteSolutionController.java | 52 +++++++++++++++++++ .../controller/DesignModelController.java | 21 ++++---- .../patternpedia/api/rest/model/EdgeDTO.java | 27 ++++++++++ .../api/service/ConcreteSolutionService.java | 17 ++++++ .../service/ConcreteSolutionServiceImpl.java | 38 ++++++++++++++ .../api/service/DesignModelService.java | 2 + .../api/service/DesignModelServiceImpl.java | 10 ++++ 13 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java create mode 100644 src/main/java/com/patternpedia/api/exception/ConcreteSolutionNotFoundException.java create mode 100644 src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java create mode 100644 src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java create mode 100644 src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java create mode 100644 src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java new file mode 100644 index 0000000..5cb5b73 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java @@ -0,0 +1,41 @@ +package com.patternpedia.api.entities.designmodel; + +import com.patternpedia.api.entities.EntityWithURI; +import com.patternpedia.api.entities.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.NaturalId; +import org.springframework.hateoas.server.core.Relation; + +import javax.persistence.*; +import java.io.Serializable; +import java.net.URI; +import java.util.List; +import java.util.UUID; + + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +@Relation(value = "concreteSolution", collectionRelation = "concreteSolutions") +public class ConcreteSolution { + + @Id + @GeneratedValue(generator = "pg-uuid") + protected UUID id; + + @NaturalId(mutable = true) + @Column(nullable = false) + private String patternUri; + +// @OneToMany +// private List options; + + private Boolean isTemplate; + + private String template; + + private String reference; +} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java new file mode 100644 index 0000000..70eddf4 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java @@ -0,0 +1,30 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.hateoas.server.core.Relation; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MapsId; +import java.net.URI; +import java.util.List; +import java.util.UUID; + + +//@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode +public class ConcreteSolutionOption { + + @Id + private UUID concreteSolutionId; + + @Id + private String key; + + private String value; +} diff --git a/src/main/java/com/patternpedia/api/exception/ConcreteSolutionNotFoundException.java b/src/main/java/com/patternpedia/api/exception/ConcreteSolutionNotFoundException.java new file mode 100644 index 0000000..bdf80d9 --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/ConcreteSolutionNotFoundException.java @@ -0,0 +1,21 @@ +package com.patternpedia.api.exception; + +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; + +import java.util.UUID; + +public class ConcreteSolutionNotFoundException extends ResourceNotFoundException { + + public ConcreteSolutionNotFoundException(String message) { + super(message); + } + + public ConcreteSolutionNotFoundException(UUID concreteSolutionId) { + super(String.format("ConcreteSolution \"%s\" not found!", concreteSolutionId)); + } + + public ConcreteSolutionNotFoundException(ConcreteSolution concreteSolution) { + super(String.format("ConcreteSolution \"%s\" not found!", concreteSolution.getId())); + } +} diff --git a/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java b/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java new file mode 100644 index 0000000..bde1715 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java @@ -0,0 +1,21 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModel; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.net.URI; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + + +public interface ConcreteSolutionRepository extends JpaRepository { + + List findAllByPatternUri(String uri); + + Optional findTopById(UUID uuid); + + boolean existsByPatternUri(URI uri); +} + diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java index 30e96df..c408d2c 100644 --- a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java @@ -15,4 +15,6 @@ public interface DesignModelPatternEdgeRepository extends JpaRepository> findAllByDesignModelId(UUID patternViewId); Optional findTopByDesignModelIdAndEdgeId(UUID designModelId, DesignModelPatternEdgeId designModelPatternEdgeId); + + void deleteAllByDesignModel_IdAndPatternInstance1_PatternInstanceIdOrPatternInstance2_PatternInstanceId(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2); } diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java index 4ecdbdb..da261d6 100644 --- a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternInstanceRepository.java @@ -14,4 +14,6 @@ public interface DesignModelPatternInstanceRepository extends JpaRepository> findAllByDesignModelId(UUID patternViewId); Optional findTopByDesignModel_IdAndPatternInstanceId(UUID designModelId, UUID patternInstanceId); + + void deleteAllByDesignModel_IdAndPatternInstanceId(UUID designModelId, UUID patternInstanceId); } diff --git a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java new file mode 100644 index 0000000..e821f0d --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java @@ -0,0 +1,52 @@ +package com.patternpedia.api.rest.controller; + +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.service.ConcreteSolutionService; +import lombok.extern.apachecommons.CommonsLog; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.web.bind.annotation.*; + +import javax.websocket.server.PathParam; +import java.net.URI; +import java.util.List; +import java.util.UUID; + + +@RestController +@CommonsLog +@CrossOrigin(allowedHeaders = "*", origins = "*") +@RequestMapping(value = "/concrete-solutions", produces = "application/hal+json") +public class ConcreteSolutionController { + + private ConcreteSolutionService concreteSolutionService; + private ObjectCodec objectMapper; + + + public ConcreteSolutionController(ConcreteSolutionService concreteSolutionService, ObjectMapper objectMapper) { + this.concreteSolutionService = concreteSolutionService; + this.objectMapper = objectMapper; + } + + + @GetMapping("") + public CollectionModel> getConcreteSolutions(@RequestParam(value = "pattern-uri", required = false) URI patternUri) { + List concreteSolutions; + + if (patternUri != null) { + concreteSolutions = this.concreteSolutionService.getConcreteSolutions(patternUri); + } else { + concreteSolutions = this.concreteSolutionService.getConcreteSolutions(); + } + + return CollectionModel.wrap(concreteSolutions); + } + + + @PostMapping("/aggregate/{designModelId}") + public String aggregateConcreteSolutions(@PathVariable UUID designModelId) { + return designModelId.toString(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java index 012fa18..d91e997 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java @@ -66,8 +66,7 @@ private static List getDesignModelLinks(DesignModel designModel) { ); links.add(linkTo(methodOn(DesignModelController.class).getDesignModels()).withRel("designModels")); links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModel.getId())).withRel("patterns")); -// links.add(linkTo(methodOn(PatternRelationDescriptorController.class).getDirectedEdgesOfView(patternView.getId())).withRel("directedEdges")); -// links.add(linkTo(methodOn(PatternRelationDescriptorController.class).getUndirectedEdgesOfView(patternView.getId())).withRel("undirectedEdges")); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternEdges(designModel.getId())).withRel("edges")); return links; } @@ -197,6 +196,7 @@ static List getDesignModelPatternInstanceCollectionLinks(UUID designModelI .andAffordance(afford(methodOn(DesignModelController.class).addDesignModelPatternInstance(designModelId, null)))); links.add(linkTo(methodOn(DesignModelController.class).getDesignModel(designModelId)).withRel("designModel")); links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).withRel("patterns")); + links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternEdges(designModelId)).withRel("edges")); return links; } @@ -282,11 +282,10 @@ public ResponseEntity putDesignModelPatternInstancePosition(@PathVariable UUI } - @DeleteMapping("/{designModelId}/patterns") - public ResponseEntity deleteDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { - this.designModelService.addPatternInstance(designModelId, pattern.getId()); - return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller - .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); + @DeleteMapping("/{designModelId}/patterns/{patternInstanceId}") + public ResponseEntity deleteDesignModelPatternInstance(@PathVariable UUID designModelId, @PathVariable UUID patternInstanceId) { + this.designModelService.deletePatternInstance(designModelId, patternInstanceId); + return ResponseEntity.ok().build(); } @@ -304,11 +303,15 @@ public ResponseEntity addDesignModelEdge(@PathVariable UUID designModelId, @R @GetMapping("/{designModelId}/edges") - public ResponseEntity getDesignModelEdge(@PathVariable UUID designModelId) { + public ResponseEntity getDesignModelPatternEdges(@PathVariable UUID designModelId) { List designModelPatternEdges = this.designModelService.getEdges(designModelId); - return ResponseEntity.ok(designModelPatternEdges); + List edgeDTOs = designModelPatternEdges.parallelStream() + .map(EdgeDTO::from) + .collect(Collectors.toList()); + + return ResponseEntity.ok(edgeDTOs); // return new CollectionModel( // designModelPatternEdges, // (Iterable) ResponseEntity.created(linkTo(methodOn(DesignModelController.class) diff --git a/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java b/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java index 6b8e1af..cc39b89 100644 --- a/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java +++ b/src/main/java/com/patternpedia/api/rest/model/EdgeDTO.java @@ -1,5 +1,8 @@ package com.patternpedia.api.rest.model; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -12,6 +15,7 @@ @Data @EqualsAndHashCode @Relation(value = "edge", collectionRelation = "edges") +@JsonInclude(JsonInclude.Include.NON_NULL) public class EdgeDTO { private UUID sourcePatternId; @@ -31,11 +35,34 @@ public boolean isDirectedEdge() { return sourcePatternId != null && targetPatternId != null; } + @JsonIgnore public UUID getFirstPatternId() { return isDirectedEdge() ? sourcePatternId : pattern1Id; } + @JsonIgnore public UUID getSecondPatternId() { return isDirectedEdge() ? targetPatternId : pattern2Id; } + + + public static EdgeDTO from(DesignModelPatternEdge designModelPatternEdge) { + EdgeDTO edgeDTO = new EdgeDTO(); + + UUID pattern1 = designModelPatternEdge.getPatternInstance1().getPatternInstanceId(); + UUID pattern2 = designModelPatternEdge.getPatternInstance2().getPatternInstanceId(); + + if (designModelPatternEdge.isDirectedEdge()) { + edgeDTO.setSourcePatternId(pattern1); + edgeDTO.setTargetPatternId(pattern2); + } else { + edgeDTO.setPattern1Id(pattern1); + edgeDTO.setPattern2Id(pattern2); + } + + edgeDTO.setType(designModelPatternEdge.getType()); + edgeDTO.setDescription(designModelPatternEdge.getDescription()); + + return edgeDTO; + } } diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java new file mode 100644 index 0000000..676d088 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java @@ -0,0 +1,17 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.designmodel.ConcreteSolution; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + + +public interface ConcreteSolutionService { + + List getConcreteSolutions(); + + List getConcreteSolutions(URI patternUri); + + ConcreteSolution getConcreteSolution(UUID uuid); +} diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java new file mode 100644 index 0000000..7aa0e59 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java @@ -0,0 +1,38 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.exception.ConcreteSolutionNotFoundException; +import com.patternpedia.api.repositories.ConcreteSolutionRepository; +import org.springframework.stereotype.Service; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + + +@Service +public class ConcreteSolutionServiceImpl implements ConcreteSolutionService { + + private final ConcreteSolutionRepository concreteSolutionRepository; + + + public ConcreteSolutionServiceImpl(ConcreteSolutionRepository concreteSolutionRepository) { + this.concreteSolutionRepository = concreteSolutionRepository; + } + + + public List getConcreteSolutions() { + return this.concreteSolutionRepository.findAll(); + } + + + public List getConcreteSolutions(URI patternUri) { + return this.concreteSolutionRepository.findAllByPatternUri(patternUri.toString()); + } + + + public ConcreteSolution getConcreteSolution(UUID uuid) { + return this.concreteSolutionRepository.findTopById(uuid) + .orElseThrow(() -> new ConcreteSolutionNotFoundException(uuid)); + } +} diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java index f1b95c9..1ebfb5e 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelService.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -24,6 +24,8 @@ public interface DesignModelService { void addPatternInstance(UUID designModelId, UUID patternId); + void deletePatternInstance(UUID designModelId, UUID patternInstanceId); + DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID patternInstanceId); void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern); diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java index a178fab..f152a1d 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -160,6 +160,16 @@ public void addPatternInstance(UUID patternViewId, UUID patternId) { } + @Override + @Transactional + public void deletePatternInstance(UUID designModelId, UUID patternInstanceId) { + this.designModelPatternEdgeRepository.deleteAllByDesignModel_IdAndPatternInstance1_PatternInstanceIdOrPatternInstance2_PatternInstanceId( + designModelId, patternInstanceId, patternInstanceId + ); + this.designModelPatternInstanceRepository.deleteAllByDesignModel_IdAndPatternInstanceId(designModelId, patternInstanceId); + } + + @Override @Transactional public void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern) { From c39f1728b0f403a809fdb653e1fbeb4f0e89607f Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Thu, 9 Jul 2020 11:21:28 +0200 Subject: [PATCH 04/10] Implement basic aggregation --- pom.xml | 7 ++ .../designmodel/ConcreteSolution.java | 16 ++- .../ConcreteSolutionRepository.java | 4 +- .../ConcreteSolutionController.java | 36 +++++- .../patternpedia/api/rest/model/FileDTO.java | 22 ++++ .../api/service/ConcreteSolutionService.java | 7 ++ .../service/ConcreteSolutionServiceImpl.java | 109 +++++++++++++++++- 7 files changed, 184 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/rest/model/FileDTO.java diff --git a/pom.xml b/pom.xml index b111102..938def6 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,13 @@ 1.8 + + org.antlr + ST4 + 4.3 + compile + + diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java index 5cb5b73..7a7a7a0 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java @@ -1,16 +1,11 @@ package com.patternpedia.api.entities.designmodel; -import com.patternpedia.api.entities.EntityWithURI; -import com.patternpedia.api.entities.Pattern; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import org.hibernate.annotations.NaturalId; import org.springframework.hateoas.server.core.Relation; import javax.persistence.*; -import java.io.Serializable; -import java.net.URI; import java.util.List; import java.util.UUID; @@ -26,16 +21,19 @@ public class ConcreteSolution { @GeneratedValue(generator = "pg-uuid") protected UUID id; - @NaturalId(mutable = true) @Column(nullable = false) private String patternUri; // @OneToMany // private List options; - private Boolean isTemplate; + @ElementCollection + private List requirements; - private String template; + @ElementCollection + private List capabilities; - private String reference; + private String templateRef; + + private String aggregatorType; } diff --git a/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java b/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java index bde1715..9fd3076 100644 --- a/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/ConcreteSolutionRepository.java @@ -1,7 +1,6 @@ package com.patternpedia.api.repositories; import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModel; import org.springframework.data.jpa.repository.JpaRepository; import java.net.URI; @@ -14,8 +13,9 @@ public interface ConcreteSolutionRepository extends JpaRepository findAllByPatternUri(String uri); + Optional findTopByPatternUriAndAggregatorType(String uri, String technology); + Optional findTopById(UUID uuid); boolean existsByPatternUri(URI uri); } - diff --git a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java index e821f0d..eefd085 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java @@ -3,16 +3,23 @@ import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; import com.patternpedia.api.service.ConcreteSolutionService; +import com.patternpedia.api.service.DesignModelService; import lombok.extern.apachecommons.CommonsLog; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.web.bind.annotation.*; -import javax.websocket.server.PathParam; import java.net.URI; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; @RestController @@ -22,11 +29,13 @@ public class ConcreteSolutionController { private ConcreteSolutionService concreteSolutionService; + private DesignModelService designModelService; private ObjectCodec objectMapper; - public ConcreteSolutionController(ConcreteSolutionService concreteSolutionService, ObjectMapper objectMapper) { + public ConcreteSolutionController(ConcreteSolutionService concreteSolutionService, DesignModelService designModelService, ObjectMapper objectMapper) { this.concreteSolutionService = concreteSolutionService; + this.designModelService = designModelService; this.objectMapper = objectMapper; } @@ -45,8 +54,27 @@ public CollectionModel> getConcreteSolutions(@Requ } + @GetMapping("/technologies/{designModelId}") + public Set checkConcreteSolutions(@PathVariable UUID designModelId) { + List patternInstanceList = this.designModelService.getDesignModel(designModelId).getPatterns(); + Set patternUris = patternInstanceList.stream().map(patternInstance -> patternInstance.getPattern().getUri()).collect(Collectors.toSet()); + Set technologies = new HashSet<>(); + + for (String uri : patternUris) { + this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> technologies.add(concreteSolution.getAggregatorType())); + } + + return technologies; + } + + @PostMapping("/aggregate/{designModelId}") - public String aggregateConcreteSolutions(@PathVariable UUID designModelId) { - return designModelId.toString(); + public FileDTO aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestParam(defaultValue = "") String technology) { + + DesignModel designModel = this.designModelService.getDesignModel(designModelId); + List patternInstanceList = designModel.getPatterns(); + List directedEdgeList = designModel.getDirectedEdges(); + + return this.concreteSolutionService.aggregate(patternInstanceList, directedEdgeList, technology); } } diff --git a/src/main/java/com/patternpedia/api/rest/model/FileDTO.java b/src/main/java/com/patternpedia/api/rest/model/FileDTO.java new file mode 100644 index 0000000..20c3512 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/FileDTO.java @@ -0,0 +1,22 @@ +package com.patternpedia.api.rest.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +@NoArgsConstructor +@AllArgsConstructor +@Data +@EqualsAndHashCode +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileDTO { + + private String name; + + private String mime; + + private String file; +} diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java index 676d088..28f0c7c 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java @@ -1,6 +1,9 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; import java.net.URI; import java.util.List; @@ -14,4 +17,8 @@ public interface ConcreteSolutionService { List getConcreteSolutions(URI patternUri); ConcreteSolution getConcreteSolution(UUID uuid); + +// ConcreteSolution getConcreteSolution(URI patternUri, String technology); + + FileDTO aggregate(List patternInstances, List edges, String technology); } diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java index 7aa0e59..41215b0 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java @@ -1,20 +1,32 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdgeId; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.exception.ConcreteSolutionNotFoundException; import com.patternpedia.api.repositories.ConcreteSolutionRepository; +import com.patternpedia.api.rest.model.FileDTO; +import lombok.extern.apachecommons.CommonsLog; import org.springframework.stereotype.Service; +import org.stringtemplate.v4.ST; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.net.URI; -import java.util.List; -import java.util.UUID; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; @Service +@CommonsLog public class ConcreteSolutionServiceImpl implements ConcreteSolutionService { private final ConcreteSolutionRepository concreteSolutionRepository; + private static final Random RANDOM = new Random(); + public ConcreteSolutionServiceImpl(ConcreteSolutionRepository concreteSolutionRepository) { this.concreteSolutionRepository = concreteSolutionRepository; @@ -35,4 +47,97 @@ public ConcreteSolution getConcreteSolution(UUID uuid) { return this.concreteSolutionRepository.findTopById(uuid) .orElseThrow(() -> new ConcreteSolutionNotFoundException(uuid)); } + + + public FileDTO aggregate(List patternInstances, List edges, String technology) { + Set patternUriSet = patternInstances.stream().map(i -> i.getPattern().getUri()).collect(Collectors.toSet()); + Map patternToConcreteSolutionMapping = new HashMap<>(); + patternUriSet.forEach(uri -> patternToConcreteSolutionMapping.put( + uri, this.concreteSolutionRepository.findTopByPatternUriAndAggregatorType(uri, technology).get() + )); + + Map patternInstanceImplementations = new HashMap<>(); + patternInstances.forEach(instance -> { + ConcreteSolution concreteSolution = patternToConcreteSolutionMapping.get(instance.getPattern().getUri()); + + patternInstanceImplementations.put(instance.getPatternInstanceId(), readFile(concreteSolution.getTemplateRef())); + }); + + StringBuilder camelContext = new StringBuilder(); + + patternInstanceImplementations.keySet().forEach(uuid -> { + List incomingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId2())).collect(Collectors.toList()); + List outgoingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId1())).collect(Collectors.toList()); + + Map dataContainer = new HashMap<>(); + dataContainer.put("input", getQueueList(incomingEdges)); + dataContainer.put("output", getQueueList(outgoingEdges)); + + camelContext.append(renderTemplate(patternInstanceImplementations.get(uuid), dataContainer)); + camelContext.append("\n"); + }); + + Map technologyWrapper = new HashMap<>(); + technologyWrapper.put("ActiveMQ-XML", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"); + technologyWrapper.put("ActiveMQ-Java", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"); + + String mainTemplate = readFile(technologyWrapper.get(technology)); + String camelXML = renderTemplate(mainTemplate, Collections.singletonMap("camelContext", camelContext.toString())); + + String name = ""; + String mime = ""; + switch (technology) { + case "ActiveMQ-XML": + name = "camel.xml"; + mime = "text/xml"; + break; + case "ActiveMQ-Java": + name = "PatternAtlasRouteBuilder.java"; + mime = "text/x-java"; + break; + } + + return new FileDTO(name, mime, camelXML); + } + + + private static String readFile(String url) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { + return reader.lines().collect(Collectors.joining("\n")); + + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + + private static Object getQueueList(Collection edges) { + if (edges.size() == 1) { + DesignModelPatternEdgeId edgeId = edges.iterator().next().getEdgeId(); + return "queue" + edgeId.getPatternInstanceId1().toString() + edgeId.getPatternInstanceId2().toString(); + } + if (edges.size() >= 2) { + List queueNames = new ArrayList<>(); + for (DesignModelPatternEdge edge : edges) { + DesignModelPatternEdgeId edgeId = edge.getEdgeId(); + queueNames.add("queue" + edgeId.getPatternInstanceId1().toString() + edgeId.getPatternInstanceId2().toString()); + } + return queueNames; + } + return null; + } + + + private static String renderTemplate(String concreteSolutionTemplate, Map dataContainer) { + ST template = new ST(concreteSolutionTemplate, '$', '$'); + + template.add("random", RANDOM.nextInt(Integer.MAX_VALUE)); + + for (String key : dataContainer.keySet()) { + template.add(key, dataContainer.get(key)); + } + + return template.render(); + } } From b54425ad28bb10ab37619b54768fd2168de5babf Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Mon, 17 Aug 2020 12:15:31 +0200 Subject: [PATCH 05/10] Add intermediate changes --- .../designmodel/ConcreteSolution.java | 10 +- .../DesignModelPatternInstance.java | 3 + .../DesignModelPatternEdgeRepository.java | 2 + .../ConcreteSolutionController.java | 45 +++--- .../controller/DesignModelController.java | 49 +++++- .../api/service/ConcreteSolutionService.java | 3 +- .../service/ConcreteSolutionServiceImpl.java | 143 ++++++------------ .../api/service/DesignModelService.java | 2 + .../api/service/DesignModelServiceImpl.java | 9 ++ .../AWSCloudFormationJsonAggregator.java | 15 ++ .../util/aggregator/ActiveMQAggregator.java | 33 ++++ .../aggregator/ActiveMQJavaAggregator.java | 16 ++ .../aggregator/ActiveMQXMLAggregator.java | 65 ++++++++ .../api/util/aggregator/Aggregator.java | 48 ++++++ 14 files changed, 313 insertions(+), 130 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java index 7a7a7a0..9b0c169 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java @@ -24,16 +24,14 @@ public class ConcreteSolution { @Column(nullable = false) private String patternUri; -// @OneToMany -// private List options; + private String name; @ElementCollection - private List requirements; - - @ElementCollection - private List capabilities; + private List properties; private String templateRef; private String aggregatorType; + + private Integer priority; } diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java index 1fb1502..97ed806 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelPatternInstance.java @@ -30,6 +30,9 @@ public class DesignModelPatternInstance { private DesignModelPatternGraphData graphData; + @Transient + private ConcreteSolution concreteSolution; + public DesignModelPatternInstance(DesignModel designModel, Pattern pattern) { this.designModel = designModel; diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java index c408d2c..74780ad 100644 --- a/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelPatternEdgeRepository.java @@ -17,4 +17,6 @@ public interface DesignModelPatternEdgeRepository extends JpaRepository findTopByDesignModelIdAndEdgeId(UUID designModelId, DesignModelPatternEdgeId designModelPatternEdgeId); void deleteAllByDesignModel_IdAndPatternInstance1_PatternInstanceIdOrPatternInstance2_PatternInstanceId(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2); + + void deleteAllByDesignModel_IdAndPatternInstance1_PatternInstanceIdAndPatternInstance2_PatternInstanceId(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2); } diff --git a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java index eefd085..bcdb810 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java @@ -10,15 +10,10 @@ import com.patternpedia.api.service.ConcreteSolutionService; import com.patternpedia.api.service.DesignModelService; import lombok.extern.apachecommons.CommonsLog; -import org.springframework.hateoas.CollectionModel; -import org.springframework.hateoas.EntityModel; import org.springframework.web.bind.annotation.*; import java.net.URI; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; @@ -40,41 +35,41 @@ public ConcreteSolutionController(ConcreteSolutionService concreteSolutionServic } - @GetMapping("") - public CollectionModel> getConcreteSolutions(@RequestParam(value = "pattern-uri", required = false) URI patternUri) { - List concreteSolutions; - - if (patternUri != null) { - concreteSolutions = this.concreteSolutionService.getConcreteSolutions(patternUri); - } else { - concreteSolutions = this.concreteSolutionService.getConcreteSolutions(); - } - - return CollectionModel.wrap(concreteSolutions); - } +// @GetMapping("") +// public CollectionModel> getConcreteSolutions(@RequestParam(value = "pattern-uri", required = false) URI patternUri) { +// List concreteSolutions; +// +// if (patternUri != null) { +// concreteSolutions = this.concreteSolutionService.getConcreteSolutions(patternUri); +// } else { +// concreteSolutions = this.concreteSolutionService.getConcreteSolutions(); +// } +// +// return CollectionModel.wrap(concreteSolutions); +// } - @GetMapping("/technologies/{designModelId}") - public Set checkConcreteSolutions(@PathVariable UUID designModelId) { + @GetMapping("/{designModelId}/concrete-solutions") + public Set checkConcreteSolutions(@PathVariable UUID designModelId) { List patternInstanceList = this.designModelService.getDesignModel(designModelId).getPatterns(); Set patternUris = patternInstanceList.stream().map(patternInstance -> patternInstance.getPattern().getUri()).collect(Collectors.toSet()); - Set technologies = new HashSet<>(); + Set concreteSolutionSet = new HashSet<>(); for (String uri : patternUris) { - this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> technologies.add(concreteSolution.getAggregatorType())); + this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> concreteSolutionSet.add(concreteSolution)); } - return technologies; + return concreteSolutionSet; } @PostMapping("/aggregate/{designModelId}") - public FileDTO aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestParam(defaultValue = "") String technology) { + public List aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestBody Map query) { DesignModel designModel = this.designModelService.getDesignModel(designModelId); List patternInstanceList = designModel.getPatterns(); List directedEdgeList = designModel.getDirectedEdges(); - return this.concreteSolutionService.aggregate(patternInstanceList, directedEdgeList, technology); + return this.concreteSolutionService.aggregate(patternInstanceList, directedEdgeList, query); } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java index d91e997..2ec3a22 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java @@ -3,12 +3,15 @@ import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.entities.Pattern; +import com.patternpedia.api.entities.designmodel.ConcreteSolution; import com.patternpedia.api.entities.designmodel.DesignModel; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.rest.model.EdgeDTO; +import com.patternpedia.api.rest.model.FileDTO; import com.patternpedia.api.rest.model.PatternInstanceDTO; import com.patternpedia.api.rest.model.PositionDTO; +import com.patternpedia.api.service.ConcreteSolutionService; import com.patternpedia.api.service.DesignModelService; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.text.CaseUtils; @@ -19,10 +22,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; +import java.net.URI; +import java.util.*; import java.util.stream.Collectors; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; @@ -35,11 +36,13 @@ public class DesignModelController { private DesignModelService designModelService; + private ConcreteSolutionService concreteSolutionService; private ObjectCodec objectMapper; - public DesignModelController(DesignModelService designModelService, ObjectMapper objectMapper) { + public DesignModelController(DesignModelService designModelService, ConcreteSolutionService concreteSolutionService, ObjectMapper objectMapper) { this.designModelService = designModelService; + this.concreteSolutionService = concreteSolutionService; this.objectMapper = objectMapper; } @@ -318,4 +321,40 @@ public ResponseEntity getDesignModelPatternEdges(@PathVariable UUID designMod // .addDesignModelEdge(designModelId, null)).toUri()).build() // ); } + + + @DeleteMapping("/{designModelId}/edges/{sourceId}/{targetId}") + public ResponseEntity getDesignModelPatternEdges(@PathVariable UUID designModelId, @PathVariable UUID sourceId, @PathVariable UUID targetId) { + + this.designModelService.deleteEdge(designModelId, sourceId, targetId); + + return ResponseEntity.ok().build(); + } + + + @GetMapping("/{designModelId}/concrete-solutions") + public Set checkConcreteSolutions(@PathVariable UUID designModelId) { + List patternInstanceList = this.designModelService.getDesignModel(designModelId).getPatterns(); + Set patternUris = patternInstanceList.stream().map(patternInstance -> patternInstance.getPattern().getUri()).collect(Collectors.toSet()); + Set concreteSolutionSet = new HashSet<>(); + + for (String uri : patternUris) { + this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> concreteSolutionSet.add(concreteSolution)); + } + + return concreteSolutionSet; + } + + + @PostMapping("/{designModelId}/aggregate") + public List aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestBody Map patternConcreteSolutionMap) { + + log.info(patternConcreteSolutionMap.toString()); + + DesignModel designModel = this.designModelService.getDesignModel(designModelId); + List patternInstanceList = designModel.getPatterns(); + List directedEdgeList = designModel.getDirectedEdges(); + + return this.concreteSolutionService.aggregate(patternInstanceList, directedEdgeList, patternConcreteSolutionMap); + } } diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java index 28f0c7c..d68bd9e 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java @@ -7,6 +7,7 @@ import java.net.URI; import java.util.List; +import java.util.Map; import java.util.UUID; @@ -20,5 +21,5 @@ public interface ConcreteSolutionService { // ConcreteSolution getConcreteSolution(URI patternUri, String technology); - FileDTO aggregate(List patternInstances, List edges, String technology); + List aggregate(List patternInstances, List edges, Map concreteSolutionMapping); } diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java index 41215b0..e9045cc 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java @@ -2,21 +2,18 @@ import com.patternpedia.api.entities.designmodel.ConcreteSolution; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdgeId; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.exception.ConcreteSolutionNotFoundException; import com.patternpedia.api.repositories.ConcreteSolutionRepository; import com.patternpedia.api.rest.model.FileDTO; import lombok.extern.apachecommons.CommonsLog; import org.springframework.stereotype.Service; -import org.stringtemplate.v4.ST; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.net.URI; -import java.net.URL; -import java.util.*; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; @Service @@ -25,8 +22,6 @@ public class ConcreteSolutionServiceImpl implements ConcreteSolutionService { private final ConcreteSolutionRepository concreteSolutionRepository; - private static final Random RANDOM = new Random(); - public ConcreteSolutionServiceImpl(ConcreteSolutionRepository concreteSolutionRepository) { this.concreteSolutionRepository = concreteSolutionRepository; @@ -49,95 +44,57 @@ public ConcreteSolution getConcreteSolution(UUID uuid) { } - public FileDTO aggregate(List patternInstances, List edges, String technology) { - Set patternUriSet = patternInstances.stream().map(i -> i.getPattern().getUri()).collect(Collectors.toSet()); - Map patternToConcreteSolutionMapping = new HashMap<>(); - patternUriSet.forEach(uri -> patternToConcreteSolutionMapping.put( - uri, this.concreteSolutionRepository.findTopByPatternUriAndAggregatorType(uri, technology).get() - )); - - Map patternInstanceImplementations = new HashMap<>(); - patternInstances.forEach(instance -> { - ConcreteSolution concreteSolution = patternToConcreteSolutionMapping.get(instance.getPattern().getUri()); - - patternInstanceImplementations.put(instance.getPatternInstanceId(), readFile(concreteSolution.getTemplateRef())); - }); - - StringBuilder camelContext = new StringBuilder(); - - patternInstanceImplementations.keySet().forEach(uuid -> { - List incomingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId2())).collect(Collectors.toList()); - List outgoingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId1())).collect(Collectors.toList()); - - Map dataContainer = new HashMap<>(); - dataContainer.put("input", getQueueList(incomingEdges)); - dataContainer.put("output", getQueueList(outgoingEdges)); - - camelContext.append(renderTemplate(patternInstanceImplementations.get(uuid), dataContainer)); - camelContext.append("\n"); - }); - - Map technologyWrapper = new HashMap<>(); - technologyWrapper.put("ActiveMQ-XML", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"); - technologyWrapper.put("ActiveMQ-Java", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"); - - String mainTemplate = readFile(technologyWrapper.get(technology)); - String camelXML = renderTemplate(mainTemplate, Collections.singletonMap("camelContext", camelContext.toString())); - - String name = ""; - String mime = ""; - switch (technology) { - case "ActiveMQ-XML": - name = "camel.xml"; - mime = "text/xml"; - break; - case "ActiveMQ-Java": - name = "PatternAtlasRouteBuilder.java"; - mime = "text/x-java"; - break; - } - - return new FileDTO(name, mime, camelXML); - } - - - private static String readFile(String url) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { - return reader.lines().collect(Collectors.joining("\n")); + public List aggregate(List patternInstances, List edges, Map concreteSolutionMapping) { - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return null; - } + DesignModelPatternInstance patternWithHighestCSPrio = null; + for (DesignModelPatternInstance patternInstance : patternInstances) { + UUID piId = patternInstance.getPatternInstanceId(); + UUID csId = concreteSolutionMapping.get(piId); + ConcreteSolution cs = this.concreteSolutionRepository.findTopById(csId) + .orElseThrow(() -> new ConcreteSolutionNotFoundException(csId)); + patternInstance.setConcreteSolution(cs); - private static Object getQueueList(Collection edges) { - if (edges.size() == 1) { - DesignModelPatternEdgeId edgeId = edges.iterator().next().getEdgeId(); - return "queue" + edgeId.getPatternInstanceId1().toString() + edgeId.getPatternInstanceId2().toString(); - } - if (edges.size() >= 2) { - List queueNames = new ArrayList<>(); - for (DesignModelPatternEdge edge : edges) { - DesignModelPatternEdgeId edgeId = edge.getEdgeId(); - queueNames.add("queue" + edgeId.getPatternInstanceId1().toString() + edgeId.getPatternInstanceId2().toString()); + if (patternInstance.getConcreteSolution().getPriority() != null) { + if (patternWithHighestCSPrio == null || patternInstance.getConcreteSolution().getPriority() > patternWithHighestCSPrio.getConcreteSolution().getPriority()) { + patternWithHighestCSPrio = patternInstance; + } } - return queueNames; - } - return null; - } - - - private static String renderTemplate(String concreteSolutionTemplate, Map dataContainer) { - ST template = new ST(concreteSolutionTemplate, '$', '$'); - - template.add("random", RANDOM.nextInt(Integer.MAX_VALUE)); - - for (String key : dataContainer.keySet()) { - template.add(key, dataContainer.get(key)); } - return template.render(); + List aggregatedFiles = new ArrayList<>(); + +// for (String technology : ((List) concreteSolutionMapping.getOrDefault("technology", Collections.EMPTY_LIST))) { +// Aggregator aggregator; +// String name; +// String mime; +// +// switch (technology) { +// case "ActiveMQ-XML": +// aggregator = new ActiveMQXMLAggregator(); +// name = "camel.xml"; +// mime = "text/xml"; +// break; +// case "ActiveMQ-Java": +// aggregator = new ActiveMQJavaAggregator(); +// name = "PatternAtlasRouteBuilder.java"; +// mime = "text/x-java"; +// break; +// case "AWS-CloudFormation-Json": +// aggregator = new AWSCloudFormationJsonAggregator(); +// name = "CloudFormation-Template.json"; +// mime = "application/json"; +// break; +// default: +// log.error("No aggregator for " + technology); +// continue; +// } +// +// +// String aggregation = aggregator.aggregate(patternInstances, edges, query); +// aggregatedFiles.add(new FileDTO(name, mime, aggregation)); +// } + + return aggregatedFiles; } } diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java index 1ebfb5e..1b0bf5c 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelService.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -38,6 +38,8 @@ public interface DesignModelService { void addEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2, Boolean directed, String type, String description); + void deleteEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2); + // List getPatternsOfDesignModel(UUID designModelId); // diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java index f152a1d..2bb1b7e 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -264,6 +264,15 @@ public void addEdge(UUID designModelId, UUID patternInstanceId1, UUID patternIns } + @Override + @Transactional + public void deleteEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2) { + this.designModelPatternEdgeRepository.deleteAllByDesignModel_IdAndPatternInstance1_PatternInstanceIdAndPatternInstance2_PatternInstanceId( + designModelId, patternInstanceId1, patternInstanceId2 + ); + } + + // @Override // @Transactional // public DirectedEdge createDirectedEdgeAndAddToPatternView(UUID patternViewId, AddDirectedEdgeToViewRequest request) { diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java new file mode 100644 index 0000000..2297c53 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java @@ -0,0 +1,15 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; + +import java.util.List; +import java.util.Map; + +public class AWSCloudFormationJsonAggregator extends ActiveMQAggregator { + + @Override + public String aggregate(List patternInstances, List edges, Map query) { + return null; + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java new file mode 100644 index 0000000..e70456c --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java @@ -0,0 +1,33 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdgeId; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import lombok.extern.apachecommons.CommonsLog; + +import java.util.*; + + +@CommonsLog +public abstract class ActiveMQAggregator extends Aggregator { + + + @Override + public abstract String aggregate(List patternInstances, List edges, Map query); + + + public static Object getQueueList(Collection edges) { + if (edges.size() == 1) { + DesignModelPatternEdgeId edgeId = edges.iterator().next().getEdgeId(); + return "queue" + edgeId.getPatternInstanceId2().toString(); + } + if (edges.size() >= 2) { + Set queueNames = new HashSet<>(); + for (DesignModelPatternEdge edge : edges) { + queueNames.add("queue" + edge.getEdgeId().getPatternInstanceId2().toString()); + } + return queueNames; + } + return null; + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java new file mode 100644 index 0000000..cebefad --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java @@ -0,0 +1,16 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; + +import java.util.List; +import java.util.Map; + +public class ActiveMQJavaAggregator extends ActiveMQAggregator { + + + @Override + public String aggregate(List patternInstances, List edges, Map query) { + return null; + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java new file mode 100644 index 0000000..d277c63 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java @@ -0,0 +1,65 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import lombok.extern.apachecommons.CommonsLog; + +import java.util.*; +import java.util.stream.Collectors; + + +@CommonsLog +public class ActiveMQXMLAggregator extends ActiveMQAggregator { + + private static final String TECHNOLOGY = "ActiveMQ-XML"; + + + @Override + public String aggregate(List patternInstances, List edges, Map query) { + + Set patternUriSet = patternInstances.stream().map(i -> i.getPattern().getUri()).collect(Collectors.toSet()); + Map patternToConcreteSolutionMapping = new HashMap<>(); + patternUriSet.forEach(uri -> { + try { +// patternToConcreteSolutionMapping.put( +// uri, this.concreteSolutionRepository.findTopByPatternUriAndAggregatorType(uri, TECHNOLOGY).get() +// ); + } catch (NoSuchElementException e) { + log.info("No concrete solution found for " + uri); + } + }); + + Map patternInstanceImplementations = new HashMap<>(); + patternInstances.forEach(instance -> { + ConcreteSolution concreteSolution = patternToConcreteSolutionMapping.get(instance.getPattern().getUri()); + + if (concreteSolution != null) { + patternInstanceImplementations.put(instance.getPatternInstanceId(), readFile(concreteSolution.getTemplateRef())); + } + }); + + StringBuilder camelContext = new StringBuilder(); + + patternInstanceImplementations.keySet().forEach(uuid -> { + List incomingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId2())).collect(Collectors.toList()); + List outgoingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId1())).collect(Collectors.toList()); + + Map dataContainer = new HashMap<>(); + dataContainer.put("input", getQueueList(incomingEdges)); + dataContainer.put("output", getQueueList(outgoingEdges)); + + camelContext.append(renderTemplate(patternInstanceImplementations.get(uuid), dataContainer)); + camelContext.append("\n"); + }); + + Map technologyWrapper = new HashMap<>(); + technologyWrapper.put("ActiveMQ-XML", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"); + technologyWrapper.put("ActiveMQ-Java", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"); + + String mainTemplate = readFile(technologyWrapper.get(TECHNOLOGY)); + String camelXML = renderTemplate(mainTemplate, Collections.singletonMap("camelContext", camelContext.toString())); + + return camelXML; + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java new file mode 100644 index 0000000..0d5ede5 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java @@ -0,0 +1,48 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import lombok.extern.apachecommons.CommonsLog; +import org.stringtemplate.v4.ST; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + + +@CommonsLog +public abstract class Aggregator { + + protected static final Random RANDOM = new Random(); + + + public abstract String aggregate(List patternInstances, List edges, Map query); + + + protected static String readFile(String url) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { + return reader.lines().collect(Collectors.joining("\n")); + + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + + protected static String renderTemplate(String concreteSolutionTemplate, Map dataContainer) { + ST template = new ST(concreteSolutionTemplate, '$', '$'); + + template.add("random", RANDOM.nextInt(Integer.MAX_VALUE)); + + for (Map.Entry entry : dataContainer.entrySet()) { + template.add(entry.getKey(), entry.getValue()); + } + + return template.render(); + } +} From 512a37bd56fb802224928f0ab973ad5b988eb284 Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Wed, 2 Sep 2020 22:44:23 +0200 Subject: [PATCH 06/10] Improve aggregator implementations --- .../entities/designmodel/AggregationData.java | 32 ++++ .../service/ConcreteSolutionServiceImpl.java | 173 +++++++++++++----- .../AWSCloudFormationJsonAggregator.java | 60 +++++- .../util/aggregator/ActiveMQAggregator.java | 33 +++- .../aggregator/ActiveMQJavaAggregator.java | 55 +++++- .../aggregator/ActiveMQXMLAggregator.java | 82 +++++---- .../api/util/aggregator/Aggregator.java | 45 +---- .../api/util/aggregator/AggregatorImpl.java | 59 ++++++ .../util/aggregator/AggregatorMetadata.java | 13 ++ .../util/aggregator/AggregatorScanner.java | 74 ++++++++ .../aggregator/MessageEndpointAggregator.java | 43 +++++ 11 files changed, 535 insertions(+), 134 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/AggregationData.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/AggregatorMetadata.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/AggregatorScanner.java create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/AggregationData.java b/src/main/java/com/patternpedia/api/entities/designmodel/AggregationData.java new file mode 100644 index 0000000..3daa1e9 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/AggregationData.java @@ -0,0 +1,32 @@ +package com.patternpedia.api.entities.designmodel; + +import com.patternpedia.api.rest.model.FileDTO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + + +@Data +public class AggregationData { + + private DesignModelPatternInstance source; + + private DesignModelPatternInstance target; + + private DesignModelPatternEdge edge; + + private Map templateContext = new HashMap<>(); + + private FileDTO result; + + + public AggregationData(DesignModelPatternInstance source, DesignModelPatternInstance target, DesignModelPatternEdge edge) { + this.source = source; + this.target = target; + this.edge = edge; + } +} diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java index e9045cc..fe1bbd8 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java @@ -1,19 +1,21 @@ package com.patternpedia.api.service; +import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.ConcreteSolution; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.exception.ConcreteSolutionNotFoundException; import com.patternpedia.api.repositories.ConcreteSolutionRepository; import com.patternpedia.api.rest.model.FileDTO; +import com.patternpedia.api.util.aggregator.Aggregator; +import com.patternpedia.api.util.aggregator.AggregatorScanner; import lombok.extern.apachecommons.CommonsLog; import org.springframework.stereotype.Service; import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Service @@ -44,56 +46,143 @@ public ConcreteSolution getConcreteSolution(UUID uuid) { } - public List aggregate(List patternInstances, List edges, Map concreteSolutionMapping) { - - DesignModelPatternInstance patternWithHighestCSPrio = null; - + private void linkConcreteSolutionsToPatternInstances(List patternInstances, Map concreteSolutionMapping) { for (DesignModelPatternInstance patternInstance : patternInstances) { UUID piId = patternInstance.getPatternInstanceId(); UUID csId = concreteSolutionMapping.get(piId); ConcreteSolution cs = this.concreteSolutionRepository.findTopById(csId) .orElseThrow(() -> new ConcreteSolutionNotFoundException(csId)); patternInstance.setConcreteSolution(cs); + } + } - if (patternInstance.getConcreteSolution().getPriority() != null) { - if (patternWithHighestCSPrio == null || patternInstance.getConcreteSolution().getPriority() > patternWithHighestCSPrio.getConcreteSolution().getPriority()) { - patternWithHighestCSPrio = patternInstance; - } + + private void swapEdgeDirections(List edges) { + Set edgeTypesToSwapDirections = Stream.of("produce", "publish").collect(Collectors.toSet()); + + for (DesignModelPatternEdge edge : edges) { + if (edge.isDirectedEdge() && edgeTypesToSwapDirections.contains(edge.getType())) { + DesignModelPatternInstance source = edge.getPatternInstance1(); + edge.setPatternInstance1(edge.getPatternInstance2()); + edge.setPatternInstance2(source); } } + } + + + private Set findRootNodes(List patternInstances, List edges) { + Set rootNodes = new HashSet<>(); + + for (DesignModelPatternInstance patternInstance : patternInstances) { + rootNodes.add(patternInstance.getPatternInstanceId()); + } + + for (DesignModelPatternEdge edge : edges) { + rootNodes.remove(edge.getPatternInstance1().getPatternInstanceId()); + } + + log.info("Root nodes: " + rootNodes.toString()); + return rootNodes; + } + + + private Set findLeafNodes(List patternInstances, List edges) { + Set leafNodes = new HashSet<>(); + + for (DesignModelPatternInstance patternInstance : patternInstances) { + leafNodes.add(patternInstance.getPatternInstanceId()); + } + + for (DesignModelPatternEdge edge : edges) { + leafNodes.remove(edge.getPatternInstance2().getPatternInstanceId()); + } + + log.info("Leaf nodes: " + leafNodes.toString()); + return leafNodes; + } + + + private UUID lastLeafUUID = null; + + private AggregationData getLeafAndPredecessor(List patternInstances, List edges) { + Set leafNodes = findLeafNodes(patternInstances, edges); + + if (leafNodes.isEmpty()) { + throw new RuntimeException("No leaf node found"); + } + + final UUID leafNodeUUID = leafNodes.contains(lastLeafUUID) ? lastLeafUUID : leafNodes.iterator().next(); + lastLeafUUID = leafNodeUUID; + + DesignModelPatternInstance leafPatternInstance = patternInstances.stream().filter(designModelPatternInstance -> leafNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())).findAny().get(); + + if (patternInstances.size() == 1) { + return new AggregationData(leafPatternInstance, null, null); + } + + DesignModelPatternEdge edge = edges.stream().filter(designModelPatternEdge -> leafNodeUUID.equals(designModelPatternEdge.getPatternInstance1().getPatternInstanceId())).findAny().orElse(null); + + DesignModelPatternInstance predecessorPatternInstance = null; + + if (edge != null) { + UUID predecessorNodeUUID = edge.getPatternInstance2().getPatternInstanceId(); + + predecessorPatternInstance = patternInstances.stream().filter(designModelPatternInstance -> predecessorNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())).findAny().get(); + + log.info("Found leaf [" + leafNodeUUID.toString() + "] and predecessor [" + predecessorNodeUUID.toString() + "]: " + leafPatternInstance.getPattern().getName() + " ---" + edge.getType() + "--> " + predecessorPatternInstance.getPattern().getName()); + } + + return new AggregationData(leafPatternInstance, predecessorPatternInstance, edge); + } + + + private void aggregate(AggregationData aggregationData) { + + String sourceAggregationType = aggregationData.getSource().getConcreteSolution().getAggregatorType(); + String targetAggregationType = null; + try { + targetAggregationType = aggregationData.getTarget().getConcreteSolution().getAggregatorType(); + } catch (NullPointerException e) { + } + + Aggregator aggregator = AggregatorScanner.findMatchingAggregatorImpl(sourceAggregationType, targetAggregationType); + + if (aggregator == null) { + throw new RuntimeException("Aggregation type combination is not yet supported: [" + sourceAggregationType + "] --> [" + targetAggregationType + "]"); + } + aggregator.aggregate(aggregationData); + } + + + public List aggregate(List patternInstances, List edges, Map concreteSolutionMapping) { + + linkConcreteSolutionsToPatternInstances(patternInstances, concreteSolutionMapping); + + swapEdgeDirections(edges); + + Map templateContext = new HashMap<>(); List aggregatedFiles = new ArrayList<>(); -// for (String technology : ((List) concreteSolutionMapping.getOrDefault("technology", Collections.EMPTY_LIST))) { -// Aggregator aggregator; -// String name; -// String mime; -// -// switch (technology) { -// case "ActiveMQ-XML": -// aggregator = new ActiveMQXMLAggregator(); -// name = "camel.xml"; -// mime = "text/xml"; -// break; -// case "ActiveMQ-Java": -// aggregator = new ActiveMQJavaAggregator(); -// name = "PatternAtlasRouteBuilder.java"; -// mime = "text/x-java"; -// break; -// case "AWS-CloudFormation-Json": -// aggregator = new AWSCloudFormationJsonAggregator(); -// name = "CloudFormation-Template.json"; -// mime = "application/json"; -// break; -// default: -// log.error("No aggregator for " + technology); -// continue; -// } -// -// -// String aggregation = aggregator.aggregate(patternInstances, edges, query); -// aggregatedFiles.add(new FileDTO(name, mime, aggregation)); -// } + while (!patternInstances.isEmpty()) { + AggregationData aggregationData = getLeafAndPredecessor(patternInstances, edges); + + aggregationData.setTemplateContext(templateContext); + + aggregate(aggregationData); + + templateContext = aggregationData.getTemplateContext(); + + if (aggregationData.getResult() != null) { + aggregatedFiles.add(aggregationData.getResult()); + } + + edges.remove(aggregationData.getEdge()); + if (!edges.stream().filter(edge -> aggregationData.getSource().getPatternInstanceId().equals(edge.getPatternInstance1().getPatternInstanceId())).findAny().isPresent()) { + patternInstances.remove(aggregationData.getSource()); + } + } + return aggregatedFiles; } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java index 2297c53..c422e79 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java @@ -1,15 +1,67 @@ package com.patternpedia.api.util.aggregator; +import com.patternpedia.api.entities.designmodel.AggregationData; +import com.patternpedia.api.entities.designmodel.ConcreteSolution; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; -import java.util.List; -import java.util.Map; +import java.util.*; + +@AggregatorMetadata(sourceTypes = {"AWS-CloudFormation-JSON"}, targetTypes = {"AWS-CloudFormation-JSON"}) public class AWSCloudFormationJsonAggregator extends ActiveMQAggregator { + private static final String FILENAME = "CloudFormation-Template.json"; + private static final String MIME_TYPE = "application/json"; + private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/aws-cloudformation-json/cloudformation.st"; + + @Override - public String aggregate(List patternInstances, List edges, Map query) { - return null; + public void aggregate(AggregationData aggregationData) { + + + DesignModelPatternInstance sourcePattern = aggregationData.getSource(); + ConcreteSolution concreteSolution = sourcePattern.getConcreteSolution(); + String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); + Map templateContext = aggregationData.getTemplateContext(); + + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + + String cloudFormationTemplate = extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"; + + // Make possible Camel XML JSON string compatible + if (templateContext.containsKey(patternInstanceId + "-configuration")) { + templateContext.compute( + patternInstanceId + "-configuration", + (String key, Object value) -> ((String) value).replaceAll("[\r\n\t ]+", " ").replaceAll("\"", "\\\\\"") + ); + } + + if (aggregationData.getEdge() != null) { + addInputOutputChannelContext(aggregationData); + } + + // Render template and wrap into camel context + String renderedCloudFormationTemplate = renderTemplate(cloudFormationTemplate, templateContext); + + templateContext.compute("resources", (String key, Object value) -> { + List resources = new ArrayList<>(); + if (value != null) { + resources.addAll((Collection) value); + } + resources.add(renderedCloudFormationTemplate); + return resources; + }); + + if (aggregationData.getTarget() != null && "AWS-CloudFormation-JSON".equals(aggregationData.getTarget().getConcreteSolution().getAggregatorType())) { + return; + } + + String wrapperTemplate = readFile(WRAPPER_TEMPLATE); + String completeTemplate = renderTemplate(wrapperTemplate, templateContext); + + FileDTO aggregationResult = new FileDTO(FILENAME, MIME_TYPE, completeTemplate); + aggregationData.setResult(aggregationResult); } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java index e70456c..f4e72ae 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java @@ -1,19 +1,20 @@ package com.patternpedia.api.util.aggregator; +import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdgeId; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import lombok.extern.apachecommons.CommonsLog; import java.util.*; +import java.util.function.BiFunction; @CommonsLog -public abstract class ActiveMQAggregator extends Aggregator { +public abstract class ActiveMQAggregator extends AggregatorImpl { @Override - public abstract String aggregate(List patternInstances, List edges, Map query); + public abstract void aggregate(AggregationData aggregationData); public static Object getQueueList(Collection edges) { @@ -30,4 +31,30 @@ public static Object getQueueList(Collection edges) { } return null; } + + + protected static void addInputOutputChannelContext(AggregationData aggregationData) { + + final String channelName = getIdentifier(aggregationData.getSource()); + + BiFunction computeMapEntries = (Object key, Object value) -> { + String newValue = channelName; + + if (value == null || value.equals(newValue)) { + return newValue; + } else if (value instanceof Collection) { + List values = new ArrayList((Collection) value); + values.add(newValue); + return values; + } else { + return Arrays.asList(value, newValue); + } + }; + + Map context = aggregationData.getTemplateContext(); + context.compute(aggregationData.getSource().getPatternInstanceId() + "-input", computeMapEntries); + if (aggregationData.getTarget() != null) { + context.compute(aggregationData.getTarget().getPatternInstanceId().toString() + "-output", computeMapEntries); + } + } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java index cebefad..6174f0f 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java @@ -1,16 +1,63 @@ package com.patternpedia.api.util.aggregator; +import com.patternpedia.api.entities.designmodel.AggregationData; +import com.patternpedia.api.entities.designmodel.ConcreteSolution; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.function.BiFunction; + +@AggregatorMetadata(sourceTypes = {"ActiveMQ-Java"}, targetTypes = {"ActiveMQ-Java", "ActiveMQ-XML"}) public class ActiveMQJavaAggregator extends ActiveMQAggregator { + private static final String FILENAME = "PatternAtlasRouteBuilder.java"; + private static final String MIME_TYPE = "text/x-java"; + private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"; + @Override - public String aggregate(List patternInstances, List edges, Map query) { - return null; + public void aggregate(AggregationData aggregationData) { + + StringBuilder camelContext = new StringBuilder(); + + DesignModelPatternInstance sourcePattern = aggregationData.getSource(); + ConcreteSolution concreteSolution = sourcePattern.getConcreteSolution(); + String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); + String targetInstanceId = aggregationData.getTarget().getPatternInstanceId().toString(); + + camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + "-template", "")); + + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + + String idComment = "/* " + getIdentifier(aggregationData.getSource()) + " */"; + if (!camelContext.toString().contains(idComment)) { + camelContext.insert(0, "\n" + idComment + extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"); + } + + aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + + if (aggregationData.getEdge() != null) { + + addInputOutputChannelContext(aggregationData); + + if ("ActiveMQ-Java".equals(aggregationData.getTarget().getConcreteSolution().getAggregatorType())) { + return; + } + } + + + // Render template and wrap into camel context + String renderedCamelContext = renderTemplate(camelContext.toString(), aggregationData.getTemplateContext()); + + String wrapperTemplate = readFile(WRAPPER_TEMPLATE); + String camelConfig = renderTemplate(wrapperTemplate, Collections.singletonMap("camelContext", renderedCamelContext)); + + aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + + FileDTO aggregationResult = new FileDTO(FILENAME, MIME_TYPE, camelConfig); + aggregationData.setResult(aggregationResult); } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java index d277c63..6ac878f 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java @@ -1,65 +1,69 @@ package com.patternpedia.api.util.aggregator; +import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; import lombok.extern.apachecommons.CommonsLog; import java.util.*; -import java.util.stream.Collectors; +import java.util.function.BiFunction; @CommonsLog +@AggregatorMetadata(sourceTypes = {"ActiveMQ-XML"}, targetTypes = {"ActiveMQ-XML", "ActiveMQ-Java", "AWS-CloudFormation-JSON", "MessageEndpoint"}) public class ActiveMQXMLAggregator extends ActiveMQAggregator { - private static final String TECHNOLOGY = "ActiveMQ-XML"; + private static final String FILENAME = "camel.xml"; + private static final String MIME_TYPE = "text/xml"; + private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"; @Override - public String aggregate(List patternInstances, List edges, Map query) { - - Set patternUriSet = patternInstances.stream().map(i -> i.getPattern().getUri()).collect(Collectors.toSet()); - Map patternToConcreteSolutionMapping = new HashMap<>(); - patternUriSet.forEach(uri -> { - try { -// patternToConcreteSolutionMapping.put( -// uri, this.concreteSolutionRepository.findTopByPatternUriAndAggregatorType(uri, TECHNOLOGY).get() -// ); - } catch (NoSuchElementException e) { - log.info("No concrete solution found for " + uri); - } - }); + public void aggregate(AggregationData aggregationData) { - Map patternInstanceImplementations = new HashMap<>(); - patternInstances.forEach(instance -> { - ConcreteSolution concreteSolution = patternToConcreteSolutionMapping.get(instance.getPattern().getUri()); + StringBuilder camelContext = new StringBuilder(); - if (concreteSolution != null) { - patternInstanceImplementations.put(instance.getPatternInstanceId(), readFile(concreteSolution.getTemplateRef())); - } - }); + DesignModelPatternInstance sourcePattern = aggregationData.getSource(); + ConcreteSolution concreteSolution = sourcePattern.getConcreteSolution(); + String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); + String targetInstanceId = aggregationData.getTarget().getPatternInstanceId().toString(); - StringBuilder camelContext = new StringBuilder(); + camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + "-template", "")); + + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + + String idComment = ""; + if (!camelContext.toString().contains(idComment)) { + camelContext.insert(0, idComment + "\n" + extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"); + } + + aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + + if (aggregationData.getEdge() != null) { + addInputOutputChannelContext(aggregationData); + + if ("ActiveMQ-XML".equals(aggregationData.getTarget().getConcreteSolution().getAggregatorType())) { + return; + } + } - patternInstanceImplementations.keySet().forEach(uuid -> { - List incomingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId2())).collect(Collectors.toList()); - List outgoingEdges = edges.stream().filter(edge -> uuid.equals(edge.getEdgeId().getPatternInstanceId1())).collect(Collectors.toList()); - Map dataContainer = new HashMap<>(); - dataContainer.put("input", getQueueList(incomingEdges)); - dataContainer.put("output", getQueueList(outgoingEdges)); + // Render template and wrap into camel context + String renderedCamelContext = renderTemplate(camelContext.toString(), aggregationData.getTemplateContext()); - camelContext.append(renderTemplate(patternInstanceImplementations.get(uuid), dataContainer)); - camelContext.append("\n"); - }); + if (aggregationData.getTarget() != null && "AWS-CloudFormation-JSON".equals(aggregationData.getTarget().getConcreteSolution().getAggregatorType())) { + String id = aggregationData.getTarget().getPatternInstanceId().toString(); + aggregationData.getTemplateContext().put(id + "-configuration", renderedCamelContext); + return; + } - Map technologyWrapper = new HashMap<>(); - technologyWrapper.put("ActiveMQ-XML", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"); - technologyWrapper.put("ActiveMQ-Java", "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"); + String wrapperTemplate = readFile(WRAPPER_TEMPLATE); + String camelConfig = renderTemplate(wrapperTemplate, Collections.singletonMap("camelContext", renderedCamelContext)); - String mainTemplate = readFile(technologyWrapper.get(TECHNOLOGY)); - String camelXML = renderTemplate(mainTemplate, Collections.singletonMap("camelContext", camelContext.toString())); + aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelConfig); - return camelXML; + FileDTO aggregationResult = new FileDTO(FILENAME, MIME_TYPE, camelConfig); + aggregationData.setResult(aggregationResult); } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java index 0d5ede5..f557bb8 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/Aggregator.java @@ -1,48 +1,9 @@ package com.patternpedia.api.util.aggregator; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; -import lombok.extern.apachecommons.CommonsLog; -import org.stringtemplate.v4.ST; +import com.patternpedia.api.entities.designmodel.AggregationData; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.stream.Collectors; +public interface Aggregator { -@CommonsLog -public abstract class Aggregator { - - protected static final Random RANDOM = new Random(); - - - public abstract String aggregate(List patternInstances, List edges, Map query); - - - protected static String readFile(String url) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { - return reader.lines().collect(Collectors.joining("\n")); - - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return null; - } - - - protected static String renderTemplate(String concreteSolutionTemplate, Map dataContainer) { - ST template = new ST(concreteSolutionTemplate, '$', '$'); - - template.add("random", RANDOM.nextInt(Integer.MAX_VALUE)); - - for (Map.Entry entry : dataContainer.entrySet()) { - template.add(entry.getKey(), entry.getValue()); - } - - return template.render(); - } + void aggregate(AggregationData aggregationData); } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java new file mode 100644 index 0000000..d353e53 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java @@ -0,0 +1,59 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.AggregationData; +import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import lombok.extern.apachecommons.CommonsLog; +import org.stringtemplate.v4.ST; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + + +@CommonsLog +public abstract class AggregatorImpl implements Aggregator { + + protected static final Random RANDOM = new Random(); + + + public abstract void aggregate(AggregationData aggregationData); + + + protected static String readFile(String url) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { + return reader.lines().collect(Collectors.joining("\n")); + + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + + protected static String renderTemplate(String concreteSolutionTemplate, Map dataContainer) { + ST template = new ST(concreteSolutionTemplate, '$', '$'); + + template.add("random", RANDOM.nextInt(Integer.MAX_VALUE)); + + for (Map.Entry entry : dataContainer.entrySet()) { + template.add(entry.getKey(), entry.getValue()); + } + + return template.render(); + } + + + protected static String extendVariables(String template, String id) { + return template.replaceAll("\\$(.*?)(input|output|configuration)(.*?)\\$", "\\$$1" + id + "-$2$3\\$"); + } + + + protected static String getIdentifier(DesignModelPatternInstance patternInstance) { + return patternInstance.getPattern().getName().replaceAll(" ", "-").toLowerCase() + "-" + patternInstance.getPatternInstanceId().toString(); + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorMetadata.java b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorMetadata.java new file mode 100644 index 0000000..57a9913 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorMetadata.java @@ -0,0 +1,13 @@ +package com.patternpedia.api.util.aggregator; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + + +@Retention(RetentionPolicy.RUNTIME) +public @interface AggregatorMetadata { + + String[] sourceTypes(); + + String[] targetTypes(); +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorScanner.java b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorScanner.java new file mode 100644 index 0000000..333d60d --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorScanner.java @@ -0,0 +1,74 @@ +package com.patternpedia.api.util.aggregator; + +import lombok.extern.apachecommons.CommonsLog; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; +import org.springframework.util.SystemPropertyUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +@CommonsLog +public class AggregatorScanner { + + public static Aggregator findMatchingAggregatorImpl(String sourceType, String targetType) { + try { + List classList = findAggregatorImplementations(AggregatorScanner.class.getPackage().getName()); + for (Class implCandidate : classList) { + AggregatorMetadata annotation = (AggregatorMetadata) implCandidate.getAnnotation(AggregatorMetadata.class); + List sourceTypes = Arrays.asList(annotation.sourceTypes()); + List targetTypes = Arrays.asList(annotation.targetTypes()); + + if (sourceTypes.contains(sourceType) && (targetType == null || targetTypes.contains(targetType))) { + return (Aggregator) implCandidate.newInstance(); + } + } + + } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { + log.error(e.getMessage(), e); + } + return null; + } + + private static List findAggregatorImplementations(String basePackage) throws IOException, ClassNotFoundException { + ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); + + List candidates = new ArrayList(); + String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + resolveBasePackage(basePackage) + "/" + "**/*.class"; + Resource[] resources = resourcePatternResolver.getResources(packageSearchPath); + for (Resource resource : resources) { + if (resource.isReadable()) { + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource); + if (isCandidate(metadataReader)) { + candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName())); + } + } + } + return candidates; + } + + private static String resolveBasePackage(String basePackage) { + return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)); + } + + private static boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException { + try { + Class c = Class.forName(metadataReader.getClassMetadata().getClassName()); + if (c.getAnnotation(AggregatorMetadata.class) != null) { + return true; + } + } catch (Throwable e) { + } + return false; + } +} diff --git a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java new file mode 100644 index 0000000..c2df430 --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java @@ -0,0 +1,43 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.AggregationData; +import com.patternpedia.api.entities.designmodel.ConcreteSolution; +import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.rest.model.FileDTO; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +@AggregatorMetadata(sourceTypes = {"MessageEndpoint"}, targetTypes = {"ActiveMQ-XML", "ActiveMQ-Java"}) +public class MessageEndpointAggregator extends ActiveMQAggregator { + + private static final String MIME_TYPE = "text/x-java"; + + + @Override + public void aggregate(AggregationData aggregationData) { + + DesignModelPatternInstance sourcePattern = aggregationData.getSource(); + ConcreteSolution concreteSolution = sourcePattern.getConcreteSolution(); + String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); + Map templateContext = aggregationData.getTemplateContext(); + + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + concreteSolutionTemplate = extendVariables(concreteSolutionTemplate, patternInstanceId); + + boolean isProducer = aggregationData.getTarget() == null; + + String filename = isProducer ? "QueueProducer.java" : "QueueConsumer.java"; + templateContext.put("producer", isProducer); + + addInputOutputChannelContext(aggregationData); + + String renderedTemplate = renderTemplate(concreteSolutionTemplate, templateContext); + + FileDTO aggregationResult = new FileDTO(filename, MIME_TYPE, renderedTemplate); + aggregationData.setResult(aggregationResult); + } +} From b80d0f72111d1b95025ed08e2ee27392d210d371 Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Sun, 20 Sep 2020 15:24:13 +0200 Subject: [PATCH 07/10] Add another aggregator impl and fix some aggregation bugs --- .../AWSCloudFormationJsonAggregator.java | 26 +++++++++++-------- .../aggregator/ActiveMQJavaAggregator.java | 6 ++--- .../aggregator/ActiveMQXMLAggregator.java | 5 ++-- .../api/util/aggregator/AggregatorImpl.java | 4 +-- .../util/aggregator/AggregatorScanner.java | 6 ++++- .../aggregator/MessageEndpointAggregator.java | 5 +--- .../MessageEndpointOnAWSAggregator.java | 22 ++++++++++++++++ 7 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointOnAWSAggregator.java diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java index c422e79..f80a947 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java @@ -2,14 +2,16 @@ import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.rest.model.FileDTO; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; -@AggregatorMetadata(sourceTypes = {"AWS-CloudFormation-JSON"}, targetTypes = {"AWS-CloudFormation-JSON"}) +@AggregatorMetadata(sourceTypes = {"AWS-CloudFormation-JSON"}, targetTypes = {"", "AWS-CloudFormation-JSON"}) public class AWSCloudFormationJsonAggregator extends ActiveMQAggregator { private static final String FILENAME = "CloudFormation-Template.json"; @@ -45,14 +47,16 @@ public void aggregate(AggregationData aggregationData) { // Render template and wrap into camel context String renderedCloudFormationTemplate = renderTemplate(cloudFormationTemplate, templateContext); - templateContext.compute("resources", (String key, Object value) -> { - List resources = new ArrayList<>(); - if (value != null) { - resources.addAll((Collection) value); - } - resources.add(renderedCloudFormationTemplate); - return resources; - }); + if (renderedCloudFormationTemplate != null && !renderedCloudFormationTemplate.trim().isEmpty()) { + templateContext.compute("resources", (String key, Object value) -> { + List resources = new ArrayList<>(); + if (value != null) { + resources.addAll((Collection) value); + } + resources.add(renderedCloudFormationTemplate); + return resources; + }); + } if (aggregationData.getTarget() != null && "AWS-CloudFormation-JSON".equals(aggregationData.getTarget().getConcreteSolution().getAggregatorType())) { return; diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java index 6174f0f..4d63a10 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java @@ -2,15 +2,13 @@ import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.rest.model.FileDTO; -import java.util.*; -import java.util.function.BiFunction; +import java.util.Collections; -@AggregatorMetadata(sourceTypes = {"ActiveMQ-Java"}, targetTypes = {"ActiveMQ-Java", "ActiveMQ-XML"}) +@AggregatorMetadata(sourceTypes = {"ActiveMQ-Java"}, targetTypes = {"", "ActiveMQ-Java", "ActiveMQ-XML"}) public class ActiveMQJavaAggregator extends ActiveMQAggregator { private static final String FILENAME = "PatternAtlasRouteBuilder.java"; diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java index 6ac878f..c7588e7 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java @@ -6,12 +6,11 @@ import com.patternpedia.api.rest.model.FileDTO; import lombok.extern.apachecommons.CommonsLog; -import java.util.*; -import java.util.function.BiFunction; +import java.util.Collections; @CommonsLog -@AggregatorMetadata(sourceTypes = {"ActiveMQ-XML"}, targetTypes = {"ActiveMQ-XML", "ActiveMQ-Java", "AWS-CloudFormation-JSON", "MessageEndpoint"}) +@AggregatorMetadata(sourceTypes = {"ActiveMQ-XML"}, targetTypes = {"", "ActiveMQ-XML", "ActiveMQ-Java", "AWS-CloudFormation-JSON", "MessageEndpoint"}) public class ActiveMQXMLAggregator extends ActiveMQAggregator { private static final String FILENAME = "camel.xml"; diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java index d353e53..20ab493 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java @@ -1,7 +1,6 @@ package com.patternpedia.api.util.aggregator; import com.patternpedia.api.entities.designmodel.AggregationData; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import lombok.extern.apachecommons.CommonsLog; import org.stringtemplate.v4.ST; @@ -9,7 +8,6 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.stream.Collectors; @@ -49,7 +47,7 @@ protected static String renderTemplate(String concreteSolutionTemplate, Map classList = findAggregatorImplementations(AggregatorScanner.class.getPackage().getName()); for (Class implCandidate : classList) { AggregatorMetadata annotation = (AggregatorMetadata) implCandidate.getAnnotation(AggregatorMetadata.class); List sourceTypes = Arrays.asList(annotation.sourceTypes()); List targetTypes = Arrays.asList(annotation.targetTypes()); - if (sourceTypes.contains(sourceType) && (targetType == null || targetTypes.contains(targetType))) { + if (sourceTypes.contains(sourceType) && targetTypes.contains(targetType)) { return (Aggregator) implCandidate.newInstance(); } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java index c2df430..c2ec4ec 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java @@ -5,13 +5,10 @@ import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; import com.patternpedia.api.rest.model.FileDTO; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Map; -@AggregatorMetadata(sourceTypes = {"MessageEndpoint"}, targetTypes = {"ActiveMQ-XML", "ActiveMQ-Java"}) +@AggregatorMetadata(sourceTypes = {"MessageEndpoint"}, targetTypes = {"", "ActiveMQ-XML", "ActiveMQ-Java"}) public class MessageEndpointAggregator extends ActiveMQAggregator { private static final String MIME_TYPE = "text/x-java"; diff --git a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointOnAWSAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointOnAWSAggregator.java new file mode 100644 index 0000000..13bc9aa --- /dev/null +++ b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointOnAWSAggregator.java @@ -0,0 +1,22 @@ +package com.patternpedia.api.util.aggregator; + +import com.patternpedia.api.entities.designmodel.AggregationData; +import com.patternpedia.api.rest.model.FileDTO; + + +@AggregatorMetadata(sourceTypes = {"MessageEndpoint"}, targetTypes = {"AWS-CloudFormation-JSON"}) +public class MessageEndpointOnAWSAggregator extends ActiveMQAggregator { + + @Override + public void aggregate(AggregationData aggregationData) { + + final String[] instructions = { + "Please perform the following steps for running your Messaging Endpoint on AWS:", + "1. upload your artefact on Amazon S3", + "2. replace the S3Bucket and S3Key values in the Cloud Formation template" + }; + + FileDTO aggregationResult = new FileDTO("Instructions for Message Endpoint deployment on AWS.txt", "plain/text", String.join("\n", instructions)); + aggregationData.setResult(aggregationResult); + } +} From b47ea503a08f086436ad6056d4f932f3ebb0e00b Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Sun, 4 Oct 2020 19:59:24 +0200 Subject: [PATCH 08/10] Fix bug if Java DSL and XML config are aggregated within the same model --- .../api/util/aggregator/ActiveMQJavaAggregator.java | 7 ++++--- .../api/util/aggregator/ActiveMQXMLAggregator.java | 13 +++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java index 4d63a10..766eeea 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java @@ -14,6 +14,7 @@ public class ActiveMQJavaAggregator extends ActiveMQAggregator { private static final String FILENAME = "PatternAtlasRouteBuilder.java"; private static final String MIME_TYPE = "text/x-java"; private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"; + private static final String TEMPLATE_KEY = "-template-jdsl"; @Override @@ -26,7 +27,7 @@ public void aggregate(AggregationData aggregationData) { String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); String targetInstanceId = aggregationData.getTarget().getPatternInstanceId().toString(); - camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + "-template", "")); + camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + TEMPLATE_KEY, "")); String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); @@ -35,7 +36,7 @@ public void aggregate(AggregationData aggregationData) { camelContext.insert(0, "\n" + idComment + extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"); } - aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + aggregationData.getTemplateContext().put(targetInstanceId + TEMPLATE_KEY, camelContext.toString()); if (aggregationData.getEdge() != null) { @@ -53,7 +54,7 @@ public void aggregate(AggregationData aggregationData) { String wrapperTemplate = readFile(WRAPPER_TEMPLATE); String camelConfig = renderTemplate(wrapperTemplate, Collections.singletonMap("camelContext", renderedCamelContext)); - aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + aggregationData.getTemplateContext().put(targetInstanceId + TEMPLATE_KEY, camelContext.toString()); FileDTO aggregationResult = new FileDTO(FILENAME, MIME_TYPE, camelConfig); aggregationData.setResult(aggregationResult); diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java index c7588e7..1667a06 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java @@ -16,6 +16,7 @@ public class ActiveMQXMLAggregator extends ActiveMQAggregator { private static final String FILENAME = "camel.xml"; private static final String MIME_TYPE = "text/xml"; private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"; + private static final String TEMPLATE_KEY = "-template"; @Override @@ -26,9 +27,9 @@ public void aggregate(AggregationData aggregationData) { DesignModelPatternInstance sourcePattern = aggregationData.getSource(); ConcreteSolution concreteSolution = sourcePattern.getConcreteSolution(); String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); - String targetInstanceId = aggregationData.getTarget().getPatternInstanceId().toString(); + String targetInstanceId = aggregationData.getTarget() == null ? null : aggregationData.getTarget().getPatternInstanceId().toString(); - camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + "-template", "")); + camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + TEMPLATE_KEY, "")); String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); @@ -37,7 +38,9 @@ public void aggregate(AggregationData aggregationData) { camelContext.insert(0, idComment + "\n" + extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"); } - aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelContext.toString()); + if (targetInstanceId != null) { + aggregationData.getTemplateContext().put(targetInstanceId + TEMPLATE_KEY, camelContext.toString()); + } if (aggregationData.getEdge() != null) { addInputOutputChannelContext(aggregationData); @@ -60,7 +63,9 @@ public void aggregate(AggregationData aggregationData) { String wrapperTemplate = readFile(WRAPPER_TEMPLATE); String camelConfig = renderTemplate(wrapperTemplate, Collections.singletonMap("camelContext", renderedCamelContext)); - aggregationData.getTemplateContext().put(targetInstanceId + "-template", camelConfig); + if (targetInstanceId != null) { + aggregationData.getTemplateContext().put(targetInstanceId + TEMPLATE_KEY, camelConfig); + } FileDTO aggregationResult = new FileDTO(FILENAME, MIME_TYPE, camelConfig); aggregationData.setResult(aggregationResult); From 6ea627c09156af842f6115fb51b675d171186acf Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Sun, 1 Nov 2020 02:56:33 +0100 Subject: [PATCH 09/10] Code cleanup and REST improvements --- .../api/config/ResourceServerConfig.java | 2 + .../designmodel/ConcreteSolution.java | 4 +- .../designmodel/ConcreteSolutionOption.java | 30 -- .../api/entities/designmodel/DesignModel.java | 27 -- .../designmodel/DesignModelEdgeType.java | 16 + .../api/exception/AggregationException.java | 8 + .../DesignModelEdgeTypeRepository.java | 11 + .../ConcreteSolutionController.java | 75 ----- .../controller/DesignModelController.java | 264 +++++------------ .../RestResponseExceptionHandler.java | 7 +- .../api/service/ConcreteSolutionService.java | 2 - .../service/ConcreteSolutionServiceImpl.java | 41 ++- .../api/service/DesignModelService.java | 40 +-- .../api/service/DesignModelServiceImpl.java | 273 +----------------- .../AWSCloudFormationJsonAggregator.java | 4 +- .../util/aggregator/ActiveMQAggregator.java | 1 - .../aggregator/ActiveMQJavaAggregator.java | 4 +- .../aggregator/ActiveMQXMLAggregator.java | 4 +- .../api/util/aggregator/AggregatorImpl.java | 18 +- .../aggregator/MessageEndpointAggregator.java | 2 +- 20 files changed, 161 insertions(+), 672 deletions(-) delete mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java create mode 100644 src/main/java/com/patternpedia/api/entities/designmodel/DesignModelEdgeType.java create mode 100644 src/main/java/com/patternpedia/api/exception/AggregationException.java create mode 100644 src/main/java/com/patternpedia/api/repositories/DesignModelEdgeTypeRepository.java delete mode 100644 src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java index ce6db77..1e8d45f 100644 --- a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java +++ b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java @@ -4,6 +4,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java index 9b0c169..1c0deec 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolution.java @@ -29,9 +29,7 @@ public class ConcreteSolution { @ElementCollection private List properties; - private String templateRef; + private String templateUri; private String aggregatorType; - - private Integer priority; } diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java b/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java deleted file mode 100644 index 70eddf4..0000000 --- a/src/main/java/com/patternpedia/api/entities/designmodel/ConcreteSolutionOption.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.patternpedia.api.entities.designmodel; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import org.springframework.hateoas.server.core.Relation; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.MapsId; -import java.net.URI; -import java.util.List; -import java.util.UUID; - - -//@Entity -@Data -@NoArgsConstructor -@EqualsAndHashCode -public class ConcreteSolutionOption { - - @Id - private UUID concreteSolutionId; - - @Id - private String key; - - private String value; -} diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java index a8e4133..bf68cd5 100644 --- a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModel.java @@ -31,31 +31,4 @@ public class DesignModel extends EntityWithURI { @JsonIgnore @OneToMany(mappedBy = "designModel", cascade = CascadeType.ALL, orphanRemoval = true) private List undirectedEdges; - -// public void removePattern(Pattern pattern) { -// for (Iterator iterator = this.patterns.iterator(); iterator.hasNext(); ) { -// DesignModelPattern designModelPattern = iterator.next(); -// if (designModelPattern.getDesignModel().equals(this) && designModelPattern.getPattern().equals(pattern)) { -// iterator.remove(); -// designModelPattern.getPattern().getDesignModels().remove(designModelPattern); -// designModelPattern.setPattern(null); -// designModelPattern.setDesignModel(null); -// break; -// } -// } -// } -// -// public void removeDirectedEdge(DirectedEdge directedEdge) { -// for (Iterator iterator = this.directedEdges.iterator(); iterator.hasNext(); ) { -// DesignModelDirectedEdge designModelDirectedEdge = iterator.next(); -// if (designModelDirectedEdge.getDesignModel().equals(this) && -// designModelDirectedEdge.getDirectedEdge().equals(directedEdge)) { -// iterator.remove(); -// designModelDirectedEdge.getDirectedEdge().getDesignModels().remove(designModelDirectedEdge); -// designModelDirectedEdge.setDirectedEdge(null); -// designModelDirectedEdge.setDesignModel(null); -// break; -// } -// } -// } } diff --git a/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelEdgeType.java b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelEdgeType.java new file mode 100644 index 0000000..47aac0c --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/designmodel/DesignModelEdgeType.java @@ -0,0 +1,16 @@ +package com.patternpedia.api.entities.designmodel; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +@Data +public class DesignModelEdgeType { + + @Id + private String name; + + private Boolean swap; +} diff --git a/src/main/java/com/patternpedia/api/exception/AggregationException.java b/src/main/java/com/patternpedia/api/exception/AggregationException.java new file mode 100644 index 0000000..3d076ed --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/AggregationException.java @@ -0,0 +1,8 @@ +package com.patternpedia.api.exception; + +public class AggregationException extends RuntimeException { + + public AggregationException(String message) { + super(message); + } +} diff --git a/src/main/java/com/patternpedia/api/repositories/DesignModelEdgeTypeRepository.java b/src/main/java/com/patternpedia/api/repositories/DesignModelEdgeTypeRepository.java new file mode 100644 index 0000000..53bbcfd --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/DesignModelEdgeTypeRepository.java @@ -0,0 +1,11 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.designmodel.DesignModelEdgeType; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface DesignModelEdgeTypeRepository extends JpaRepository { + + Optional findTopByName(String name); +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java b/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java deleted file mode 100644 index bcdb810..0000000 --- a/src/main/java/com/patternpedia/api/rest/controller/ConcreteSolutionController.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.patternpedia.api.rest.controller; - -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModel; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; -import com.patternpedia.api.rest.model.FileDTO; -import com.patternpedia.api.service.ConcreteSolutionService; -import com.patternpedia.api.service.DesignModelService; -import lombok.extern.apachecommons.CommonsLog; -import org.springframework.web.bind.annotation.*; - -import java.net.URI; -import java.util.*; -import java.util.stream.Collectors; - - -@RestController -@CommonsLog -@CrossOrigin(allowedHeaders = "*", origins = "*") -@RequestMapping(value = "/concrete-solutions", produces = "application/hal+json") -public class ConcreteSolutionController { - - private ConcreteSolutionService concreteSolutionService; - private DesignModelService designModelService; - private ObjectCodec objectMapper; - - - public ConcreteSolutionController(ConcreteSolutionService concreteSolutionService, DesignModelService designModelService, ObjectMapper objectMapper) { - this.concreteSolutionService = concreteSolutionService; - this.designModelService = designModelService; - this.objectMapper = objectMapper; - } - - -// @GetMapping("") -// public CollectionModel> getConcreteSolutions(@RequestParam(value = "pattern-uri", required = false) URI patternUri) { -// List concreteSolutions; -// -// if (patternUri != null) { -// concreteSolutions = this.concreteSolutionService.getConcreteSolutions(patternUri); -// } else { -// concreteSolutions = this.concreteSolutionService.getConcreteSolutions(); -// } -// -// return CollectionModel.wrap(concreteSolutions); -// } - - - @GetMapping("/{designModelId}/concrete-solutions") - public Set checkConcreteSolutions(@PathVariable UUID designModelId) { - List patternInstanceList = this.designModelService.getDesignModel(designModelId).getPatterns(); - Set patternUris = patternInstanceList.stream().map(patternInstance -> patternInstance.getPattern().getUri()).collect(Collectors.toSet()); - Set concreteSolutionSet = new HashSet<>(); - - for (String uri : patternUris) { - this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> concreteSolutionSet.add(concreteSolution)); - } - - return concreteSolutionSet; - } - - - @PostMapping("/aggregate/{designModelId}") - public List aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestBody Map query) { - - DesignModel designModel = this.designModelService.getDesignModel(designModelId); - List patternInstanceList = designModel.getPatterns(); - List directedEdgeList = designModel.getDirectedEdges(); - - return this.concreteSolutionService.aggregate(patternInstanceList, directedEdgeList, query); - } -} diff --git a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java index 2ec3a22..2c8b432 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/DesignModelController.java @@ -1,12 +1,7 @@ package com.patternpedia.api.rest.controller; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.entities.Pattern; -import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModel; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.entities.designmodel.*; import com.patternpedia.api.rest.model.EdgeDTO; import com.patternpedia.api.rest.model.FileDTO; import com.patternpedia.api.rest.model.PatternInstanceDTO; @@ -26,6 +21,7 @@ import java.util.*; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; @@ -37,183 +33,58 @@ public class DesignModelController { private DesignModelService designModelService; private ConcreteSolutionService concreteSolutionService; - private ObjectCodec objectMapper; - public DesignModelController(DesignModelService designModelService, ConcreteSolutionService concreteSolutionService, ObjectMapper objectMapper) { + public DesignModelController(DesignModelService designModelService, ConcreteSolutionService concreteSolutionService) { this.designModelService = designModelService; this.concreteSolutionService = concreteSolutionService; - this.objectMapper = objectMapper; } private static List getDesignModelCollectionLinks() { - List links = new ArrayList<>(); - - links.add(linkTo(methodOn(DesignModelController.class).getDesignModels()).withSelfRel() - .andAffordance(afford(methodOn(DesignModelController.class).createDesignModel(null)))); - - links.add(linkTo(methodOn(DesignModelController.class).getDesignModel(null)).withRel("designModel")); - - return links; - } - - - private static List getDesignModelLinks(DesignModel designModel) { - List links = new ArrayList<>(); - - links.add( - linkTo(methodOn(DesignModelController.class).getDesignModel(designModel.getId())).withSelfRel() - .andAffordance(afford(methodOn(DesignModelController.class).putDesignModel(designModel.getId(), null))) - .andAffordance(afford(methodOn(DesignModelController.class).deleteDesignModel(designModel.getId()))) + return Arrays.asList( + linkTo(methodOn(DesignModelController.class).getDesignModels()).withSelfRel() + .andAffordance(afford(methodOn(DesignModelController.class).createDesignModel(null))), + linkTo(methodOn(DesignModelController.class).getDesignModel(null)).withRel("designModel"), + linkTo(methodOn(DesignModelController.class).getDesignModelPatternEdgeTypes()).withRel("edgeTypes") ); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModels()).withRel("designModels")); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModel.getId())).withRel("patterns")); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternEdges(designModel.getId())).withRel("edges")); - - return links; } - // TODO currently this is a duplicate from PatternController, may generalize this and move it to a utility class, etc. - List getPatternLinksForDesignModelRoute(Pattern pattern, UUID patternViewId) { - List links = Collections.emptyList(); - -// List links = this.getPatternLinks(pattern); -// -// List outgoingEdges; -// try { -// outgoingEdges = this.patternRelationDescriptorService.findDirectedEdgeBySource(pattern); -// } catch (DirectedEdgeNotFoundException ex) { -// outgoingEdges = Collections.emptyList(); -// } -// if (null != outgoingEdges) { -// for (DirectedEdge directedEdge : outgoingEdges) { -// if (null != directedEdge.getPatternViews()) { -// // edge is part of pattern view, thus we reference the pattern view route -// List newLinks = directedEdge.getPatternViews().stream() -// .filter(patternViewDirectedEdge -> patternViewDirectedEdge.getPatternView().getId().equals(patternViewId)) -// .map(patternViewDirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) -// .getDirectedEdgeOfPatternViewById(patternViewDirectedEdge.getPatternView().getId(), patternViewDirectedEdge.getDirectedEdge().getId())).withRel("outgoingDirectedEdges") -// ).collect(Collectors.toList()); -// links.addAll(newLinks); -// } -// } -// } -// -// List ingoingEdges; -// try { -// ingoingEdges = this.patternRelationDescriptorService.findDirectedEdgeByTarget(pattern); -// } catch (DirectedEdgeNotFoundException ex) { -// ingoingEdges = Collections.emptyList(); -// } -// if (null != ingoingEdges) { -// for (DirectedEdge directedEdge : ingoingEdges) { -// if (null != directedEdge.getPatternViews()) { -// // edge is part of pattern view, thus we reference the pattern view route -// List newLinks = directedEdge.getPatternViews().stream() -// .filter(patternViewDirectedEdge -> patternViewDirectedEdge.getPatternView().getId().equals(patternViewId)) -// .map(patternViewDirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) -// .getDirectedEdgeOfPatternViewById(patternViewDirectedEdge.getPatternView().getId(), patternViewDirectedEdge.getDirectedEdge().getId())).withRel("ingoingDirectedEdges") -// ).collect(Collectors.toList()); -// links.addAll(newLinks); -// } -// } -// } -// -// List undirectedEdges; -// try { -// undirectedEdges = this.patternRelationDescriptorService.findUndirectedEdgeByPattern(pattern); -// } catch (UndirectedEdgeNotFoundException ex) { -// undirectedEdges = Collections.emptyList(); -// } -// if (null != undirectedEdges) { -// for (UndirectedEdge undirectedEdge : undirectedEdges) { -// if (null != undirectedEdge.getPatternViews()) { -// // edge is part of pattern view, thus we reference the pattern view route -// List newLinks = undirectedEdge.getPatternViews().stream() -// .filter(patternViewUndirectedEdge -> patternViewUndirectedEdge.getPatternView().getId().equals(patternViewId)) -// .map(patternViewUndirectedEdge -> linkTo(methodOn(PatternRelationDescriptorController.class) -// .getUndirectedEdgeOfPatternViewById(patternViewUndirectedEdge.getPatternView().getId(), patternViewUndirectedEdge.getUndirectedEdge().getId())).withRel("undirectedEdges") -// ).collect(Collectors.toList()); -// links.addAll(newLinks); -// } -// } -// } -// -// List outgoingFromPatternLanguage; -// try { -// outgoingFromPatternLanguage = this.patternRelationDescriptorService.findDirectedEdgeBySource(pattern); -// } catch (DirectedEdgeNotFoundException ex) { -// outgoingFromPatternLanguage = Collections.emptyList(); -// } -// if (null != outgoingFromPatternLanguage) { -// for (DirectedEdge directedEdge : outgoingFromPatternLanguage) { -// if (null != directedEdge.getPatternLanguage() && directedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { -// // edge is part of pattern language, thus reference the route to edge in pattern language -// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) -// .getDirectedEdgeOfPatternLanguageById(directedEdge.getPatternLanguage().getId(), directedEdge.getId())).withRel("outgoingDirectedEdgesFromPatternLanguage")); -// } -// } -// } -// -// List ingoingFromPatternLanguage; -// try { -// ingoingFromPatternLanguage = this.patternRelationDescriptorService.findDirectedEdgeByTarget(pattern); -// } catch (DirectedEdgeNotFoundException ex) { -// ingoingFromPatternLanguage = Collections.emptyList(); -// } -// if (null != ingoingFromPatternLanguage) { -// for (DirectedEdge directedEdge : ingoingFromPatternLanguage) { -// if (null != directedEdge.getPatternLanguage() && directedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { -// // edge is part of pattern language, thus reference the route to edge in pattern language -// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) -// .getDirectedEdgeOfPatternLanguageById(directedEdge.getPatternLanguage().getId(), directedEdge.getId())).withRel("ingoingDirectedEdgesFromPatternLanguage")); -// } -// } -// } -// -// List undirectedFromPatternLanguage; -// try { -// undirectedFromPatternLanguage = this.patternRelationDescriptorService.findUndirectedEdgeByPattern(pattern); -// } catch (UndirectedEdgeNotFoundException ex) { -// undirectedFromPatternLanguage = Collections.emptyList(); -// } -// if (null != undirectedFromPatternLanguage) { -// for (UndirectedEdge undirectedEdge : undirectedFromPatternLanguage) { -// if (null != undirectedEdge.getPatternLanguage() && undirectedEdge.getPatternLanguage().getId().equals(pattern.getPatternLanguage().getId())) { -// // edge is part of pattern language, thus reference the route to edge in pattern language -// links.add(linkTo(methodOn(PatternRelationDescriptorController.class) -// .getUndirectedEdgeOfPatternLanguageById(undirectedEdge.getPatternLanguage().getId(), undirectedEdge.getId())).withRel("undirectedEdgesFromPatternLanguage")); -// } -// } -// } - - return links; - } + private static List getDesignModelLinks(UUID designModelId, String selfRel) { + Map linkMap = new HashMap<>(); + + linkMap.put("designModels", methodOn(DesignModelController.class).getDesignModels()); + linkMap.put("designModel", methodOn(DesignModelController.class).getDesignModel(designModelId)); + linkMap.put("patterns", methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)); + linkMap.put("edges", methodOn(DesignModelController.class).getDesignModelPatternEdges(designModelId)); + linkMap.put("edgeTypes", methodOn(DesignModelController.class).getDesignModelPatternEdgeTypes()); + linkMap.put("concreteSolutions", methodOn(DesignModelController.class).checkConcreteSolutions(designModelId)); + linkMap.put("aggregate", methodOn(DesignModelController.class).aggregateConcreteSolutions(designModelId, null)); + List linkList = new ArrayList<>(); + if (linkMap.containsKey(selfRel)) { + linkList.add(linkTo(linkMap.get(selfRel)).withSelfRel()); + } else { + log.error("_self link for " + selfRel + " not found in linkMap"); + } + for (Map.Entry linkPair : linkMap.entrySet()) { + linkList.add(linkTo(linkPair.getValue()).withRel(linkPair.getKey())); + } - static List getDesignModelPatternInstanceCollectionLinks(UUID designModelId) { - List links = new ArrayList<>(); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).withSelfRel() - .andAffordance(afford(methodOn(DesignModelController.class).addDesignModelPatternInstance(designModelId, null)))); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModel(designModelId)).withRel("designModel")); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).withRel("patterns")); - links.add(linkTo(methodOn(DesignModelController.class).getDesignModelPatternEdges(designModelId)).withRel("edges")); - return links; + return linkList; } @GetMapping("") public CollectionModel> getDesignModels() { - List> patternViews = this.designModelService.getAllDesignModels() + List> designModels = this.designModelService.getAllDesignModels() .stream() - .map(patternView -> new EntityModel<>(patternView, - getDesignModelLinks(patternView))) - .collect(Collectors.toList()); + .map(designModel -> new EntityModel<>(designModel, getDesignModelLinks(designModel.getId(), "designModel"))) + .collect(toList()); - return new CollectionModel<>(patternViews, getDesignModelCollectionLinks()); + return new CollectionModel<>(designModels, getDesignModelCollectionLinks()); } @@ -232,38 +103,35 @@ public ResponseEntity createDesignModel(@RequestBody DesignModel designModel) } - @GetMapping("/{designModelId}") - public EntityModel getDesignModel(@PathVariable UUID designModelId) { - DesignModel patternView = this.designModelService.getDesignModel(designModelId); - - return new EntityModel<>(patternView, getDesignModelLinks(patternView)); - } - + @GetMapping("/edge-types") + public EntityModel>> getDesignModelPatternEdgeTypes() { - @PutMapping("/{designModelId}") - public ResponseEntity putDesignModel(@PathVariable UUID designModelId, @RequestBody DesignModel designModel) { -// patternView = this.patternViewService.updateDesignModel(patternView); + List edgeTypes = this.designModelService.getDesignModelEdgeTypes().stream() + .map(DesignModelEdgeType::getName) + .collect(toList()); - return ResponseEntity.ok(designModel); + return new EntityModel<>(Collections.singletonMap("edgeTypes", edgeTypes), getDesignModelLinks(null, "edgeTypes")); } - @DeleteMapping("/{designModelId}") - public ResponseEntity deleteDesignModel(@PathVariable UUID designModelId) { -// this.patternViewService.deleteDesignModel(designModelId); - return ResponseEntity.noContent().build(); + @GetMapping("/{designModelId}") + public EntityModel getDesignModel(@PathVariable UUID designModelId) { + DesignModel designModel = this.designModelService.getDesignModel(designModelId); + + return new EntityModel<>(designModel, getDesignModelLinks(designModel.getId(), "designModel")); } @GetMapping("/{designModelId}/patterns") - CollectionModel> getDesignModelPatternInstances(@PathVariable UUID designModelId) { + public CollectionModel> getDesignModelPatternInstances(@PathVariable UUID designModelId) { List patternInstances = this.designModelService.getDesignModel(designModelId).getPatterns(); List> patterns = patternInstances.stream() .map(PatternInstanceDTO::from) - .map(patternModel -> new EntityModel<>(patternModel))// TODO, getPatternLinksForDesignModelRoute(patternModel, designModelId))) - .collect(Collectors.toList()); - return new CollectionModel<>(patterns, getDesignModelPatternInstanceCollectionLinks(designModelId)); + .map(patternModel -> new EntityModel<>(patternModel)) + .collect(toList()); + + return new CollectionModel<>(patterns, getDesignModelLinks(designModelId, "patterns")); } @@ -271,23 +139,27 @@ CollectionModel> getDesignModelPatternInstances( @CrossOrigin(exposedHeaders = "Location") @ResponseStatus(HttpStatus.CREATED) public ResponseEntity addDesignModelPatternInstance(@PathVariable UUID designModelId, @RequestBody Pattern pattern) { + this.designModelService.addPatternInstance(designModelId, pattern.getId()); - return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller - .getPatternOfPatternViewById(designModelId, pattern.getId())).toUri()).build(); + + return ResponseEntity.created(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).toUri()).build(); } @PutMapping("/{designModelId}/patterns/{patternInstanceId}/position") public ResponseEntity putDesignModelPatternInstancePosition(@PathVariable UUID designModelId, @PathVariable UUID patternInstanceId, @RequestBody PositionDTO position) { + this.designModelService.updatePatternInstancePosition(designModelId, patternInstanceId, position.getX(), position.getY()); - return ResponseEntity.created(linkTo(methodOn(PatternController.class) // TODO fix controller - .getPatternOfPatternViewById(designModelId, patternInstanceId)).toUri()).build(); + + return ResponseEntity.created(linkTo(methodOn(DesignModelController.class).getDesignModelPatternInstances(designModelId)).toUri()).build(); } @DeleteMapping("/{designModelId}/patterns/{patternInstanceId}") public ResponseEntity deleteDesignModelPatternInstance(@PathVariable UUID designModelId, @PathVariable UUID patternInstanceId) { + this.designModelService.deletePatternInstance(designModelId, patternInstanceId); + return ResponseEntity.ok().build(); } @@ -301,25 +173,21 @@ public ResponseEntity addDesignModelEdge(@PathVariable UUID designModelId, @R edgeDTO.isDirectedEdge(), edgeDTO.getType(), edgeDTO.getDescription()); return ResponseEntity.created(linkTo(methodOn(DesignModelController.class) - .addDesignModelEdge(designModelId, null)).toUri()).build(); + .getDesignModelPatternEdges(designModelId)).toUri()).build(); } @GetMapping("/{designModelId}/edges") - public ResponseEntity getDesignModelPatternEdges(@PathVariable UUID designModelId) { + public CollectionModel> getDesignModelPatternEdges(@PathVariable UUID designModelId) { List designModelPatternEdges = this.designModelService.getEdges(designModelId); - List edgeDTOs = designModelPatternEdges.parallelStream() + List> edges = designModelPatternEdges.parallelStream() .map(EdgeDTO::from) - .collect(Collectors.toList()); - - return ResponseEntity.ok(edgeDTOs); -// return new CollectionModel( -// designModelPatternEdges, -// (Iterable) ResponseEntity.created(linkTo(methodOn(DesignModelController.class) -// .addDesignModelEdge(designModelId, null)).toUri()).build() -// ); + .map(edgeDTO -> new EntityModel<>(edgeDTO)) + .collect(toList()); + + return new CollectionModel<>(edges, getDesignModelLinks(designModelId, "edges")); } @@ -333,7 +201,7 @@ public ResponseEntity getDesignModelPatternEdges(@PathVariable UUID designMod @GetMapping("/{designModelId}/concrete-solutions") - public Set checkConcreteSolutions(@PathVariable UUID designModelId) { + public CollectionModel checkConcreteSolutions(@PathVariable UUID designModelId) { List patternInstanceList = this.designModelService.getDesignModel(designModelId).getPatterns(); Set patternUris = patternInstanceList.stream().map(patternInstance -> patternInstance.getPattern().getUri()).collect(Collectors.toSet()); Set concreteSolutionSet = new HashSet<>(); @@ -342,15 +210,13 @@ public Set checkConcreteSolutions(@PathVariable UUID designMod this.concreteSolutionService.getConcreteSolutions(URI.create(uri)).forEach(concreteSolution -> concreteSolutionSet.add(concreteSolution)); } - return concreteSolutionSet; + return new CollectionModel<>(concreteSolutionSet, getDesignModelLinks(designModelId, "concreteSolutions")); } @PostMapping("/{designModelId}/aggregate") public List aggregateConcreteSolutions(@PathVariable UUID designModelId, @RequestBody Map patternConcreteSolutionMap) { - log.info(patternConcreteSolutionMap.toString()); - DesignModel designModel = this.designModelService.getDesignModel(designModelId); List patternInstanceList = designModel.getPatterns(); List directedEdgeList = designModel.getDirectedEdges(); diff --git a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java index aa86467..59b3a90 100644 --- a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java +++ b/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java @@ -1,8 +1,7 @@ package com.patternpedia.api.rest.exception; -import com.patternpedia.api.exception.*; +import com.patternpedia.api.exception.NullPatternSchemaException; import com.patternpedia.api.rest.model.ErrorMessageDTO; -import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -33,8 +32,8 @@ protected ResponseEntity handleNullPatternSchemaException(RuntimeExcepti return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.BAD_REQUEST, request); } - @ExceptionHandler({ - InvalidDataAccessResourceUsageException.class + @ExceptionHandler(value = { + Exception.class }) protected ResponseEntity handleStorageExceptions(RuntimeException ex, WebRequest request) { ErrorMessageDTO errorMessage = new ErrorMessageDTO(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java index d68bd9e..929a8a3 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionService.java @@ -19,7 +19,5 @@ public interface ConcreteSolutionService { ConcreteSolution getConcreteSolution(UUID uuid); -// ConcreteSolution getConcreteSolution(URI patternUri, String technology); - List aggregate(List patternInstances, List edges, Map concreteSolutionMapping); } diff --git a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java index fe1bbd8..30da930 100644 --- a/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/ConcreteSolutionServiceImpl.java @@ -1,11 +1,10 @@ package com.patternpedia.api.service; -import com.patternpedia.api.entities.designmodel.AggregationData; -import com.patternpedia.api.entities.designmodel.ConcreteSolution; -import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; -import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.entities.designmodel.*; +import com.patternpedia.api.exception.AggregationException; import com.patternpedia.api.exception.ConcreteSolutionNotFoundException; import com.patternpedia.api.repositories.ConcreteSolutionRepository; +import com.patternpedia.api.repositories.DesignModelEdgeTypeRepository; import com.patternpedia.api.rest.model.FileDTO; import com.patternpedia.api.util.aggregator.Aggregator; import com.patternpedia.api.util.aggregator.AggregatorScanner; @@ -15,7 +14,6 @@ import java.net.URI; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Service @@ -23,10 +21,13 @@ public class ConcreteSolutionServiceImpl implements ConcreteSolutionService { private final ConcreteSolutionRepository concreteSolutionRepository; + private final DesignModelEdgeTypeRepository designModelEdgeTypeRepository; - public ConcreteSolutionServiceImpl(ConcreteSolutionRepository concreteSolutionRepository) { + public ConcreteSolutionServiceImpl(ConcreteSolutionRepository concreteSolutionRepository, + DesignModelEdgeTypeRepository designModelEdgeTypeRepository) { this.concreteSolutionRepository = concreteSolutionRepository; + this.designModelEdgeTypeRepository = designModelEdgeTypeRepository; } @@ -58,7 +59,10 @@ private void linkConcreteSolutionsToPatternInstances(List edges) { - Set edgeTypesToSwapDirections = Stream.of("produce", "publish").collect(Collectors.toSet()); + Set edgeTypesToSwapDirections = this.designModelEdgeTypeRepository.findAll().stream() + .filter(DesignModelEdgeType::getSwap) + .map(DesignModelEdgeType::getName) + .collect(Collectors.toSet()); for (DesignModelPatternEdge edge : edges) { if (edge.isDirectedEdge() && edgeTypesToSwapDirections.contains(edge.getType())) { @@ -97,7 +101,6 @@ private Set findLeafNodes(List patternInstance leafNodes.remove(edge.getPatternInstance2().getPatternInstanceId()); } - log.info("Leaf nodes: " + leafNodes.toString()); return leafNodes; } @@ -114,7 +117,9 @@ private AggregationData getLeafAndPredecessor(List p final UUID leafNodeUUID = leafNodes.contains(lastLeafUUID) ? lastLeafUUID : leafNodes.iterator().next(); lastLeafUUID = leafNodeUUID; - DesignModelPatternInstance leafPatternInstance = patternInstances.stream().filter(designModelPatternInstance -> leafNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())).findAny().get(); + DesignModelPatternInstance leafPatternInstance = patternInstances.stream() + .filter(designModelPatternInstance -> leafNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())) + .findAny().orElse(null); if (patternInstances.size() == 1) { return new AggregationData(leafPatternInstance, null, null); @@ -127,9 +132,11 @@ private AggregationData getLeafAndPredecessor(List p if (edge != null) { UUID predecessorNodeUUID = edge.getPatternInstance2().getPatternInstanceId(); - predecessorPatternInstance = patternInstances.stream().filter(designModelPatternInstance -> predecessorNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())).findAny().get(); + predecessorPatternInstance = patternInstances.stream() + .filter(designModelPatternInstance -> predecessorNodeUUID.equals(designModelPatternInstance.getPatternInstanceId())) + .findAny().orElse(null); - log.info("Found leaf [" + leafNodeUUID.toString() + "] and predecessor [" + predecessorNodeUUID.toString() + "]: " + leafPatternInstance.getPattern().getName() + " ---" + edge.getType() + "--> " + predecessorPatternInstance.getPattern().getName()); + log.info("Found leaf [" + leafNodeUUID.toString() + "] and predecessor [" + predecessorNodeUUID.toString() + "]: " + leafPatternInstance.getPattern().getName() + " ---" + edge.getType() + "--- " + predecessorPatternInstance.getPattern().getName()); } return new AggregationData(leafPatternInstance, predecessorPatternInstance, edge); @@ -142,16 +149,20 @@ private void aggregate(AggregationData aggregationData) { String targetAggregationType = null; try { targetAggregationType = aggregationData.getTarget().getConcreteSolution().getAggregatorType(); - } catch (NullPointerException e) { + } catch (NullPointerException ignored) { } Aggregator aggregator = AggregatorScanner.findMatchingAggregatorImpl(sourceAggregationType, targetAggregationType); if (aggregator == null) { - throw new RuntimeException("Aggregation type combination is not yet supported: [" + sourceAggregationType + "] --> [" + targetAggregationType + "]"); + throw new AggregationException("Aggregation type combination is not yet supported: [" + sourceAggregationType + "] --> [" + targetAggregationType + "]"); } - aggregator.aggregate(aggregationData); + try { + aggregator.aggregate(aggregationData); + } catch (AggregationException e) { + throw new AggregationException("Failed to aggregate concrete solutions"); + } } @@ -178,7 +189,7 @@ public List aggregate(List patternInstances } edges.remove(aggregationData.getEdge()); - if (!edges.stream().filter(edge -> aggregationData.getSource().getPatternInstanceId().equals(edge.getPatternInstance1().getPatternInstanceId())).findAny().isPresent()) { + if (!edges.stream().anyMatch(edge -> aggregationData.getSource().getPatternInstanceId().equals(edge.getPatternInstance1().getPatternInstanceId()))) { patternInstances.remove(aggregationData.getSource()); } } diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java index 1b0bf5c..3d9d12b 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelService.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -2,6 +2,7 @@ import com.patternpedia.api.entities.Pattern; import com.patternpedia.api.entities.designmodel.DesignModel; +import com.patternpedia.api.entities.designmodel.DesignModelEdgeType; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; @@ -16,11 +17,7 @@ public interface DesignModelService { DesignModel getDesignModel(UUID designModelId); -// DesignModel getDesignModelByUri(String uri); -// -// DesignModel updateDesignModel(DesignModel designModel); -// -// void deleteDesignModel(UUID designModelId); + List getDesignModelEdgeTypes(); void addPatternInstance(UUID designModelId, UUID patternId); @@ -32,42 +29,9 @@ public interface DesignModelService { void updatePatternInstancePosition(UUID designModelId, UUID patternInstanceId, Double x, Double y); -// void addEdge(UUID designModelId, DesignModelEdge edge); - List getEdges(UUID designModelId); void addEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2, Boolean directed, String type, String description); void deleteEdge(UUID designModelId, UUID patternInstanceId1, UUID patternInstanceId2); - - -// List getPatternsOfDesignModel(UUID designModelId); -// -// Pattern getPatternOfDesignModelById(UUID designModelId, UUID patternId); -// -// void removePatternFromDesignModel(UUID designModelId, UUID patternId); -// -// void addDirectedEdgeToDesignModel(UUID designModelId, UUID directedEdgeId); -// -// DirectedEdge createDirectedEdgeAndAddToDesignModel(UUID designModelId, AddDirectedEdgeToViewRequest request); -// -// List getDirectedEdgesByDesignModelId(UUID designModelId); -// -// DirectedEdge getDirectedEdgeOfDesignModelById(UUID designModelId, UUID directedEdgeId); -// -// DirectedEdge updateDirectedEdgeOfDesignModel(UUID designModelId, UpdateDirectedEdgeRequest request); -// -// void removeDirectedEdgeFromDesignModel(UUID designModelId, UUID directedEdgeId); -// -// void addUndirectedEdgeToDesignModel(UUID designModelId, UUID undirectedEdgeId); -// -// UndirectedEdge createUndirectedEdgeAndAddToDesignModel(UUID designModelId, AddUndirectedEdgeToViewRequest request); -// -// List getUndirectedEdgesByDesignModelId(UUID designModelId); -// -// UndirectedEdge getUndirectedEdgeOfDesignModelById(UUID designModelId, UUID undirectedEdgeId); -// -// UndirectedEdge updateUndirectedEdgeOfDesignModel(UUID designModelId, UpdateUndirectedEdgeRequest request); -// -// void removeUndirectedEdgeFromDesignModel(UUID designModelId, UUID undirectedEdgeId); } diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java index 2bb1b7e..9b2df74 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -19,14 +19,11 @@ public class DesignModelServiceImpl implements DesignModelService { private PatternService patternService; - // private PatternRelationDescriptorService patternRelationDescriptorService; private DesignModelRepository designModelRepository; private DesignModelPatternInstanceRepository designModelPatternInstanceRepository; private DesignModelPatternEdgeRepository designModelPatternEdgeRepository; -// private PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository; -// private PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository; -// private DirectedEdgeRepository directedEdgeRepository; -// private UndirectedEdgeReository undirectedEdgeReository; + private DesignModelEdgeTypeRepository designModelEdgeTypeRepository; + public DesignModelServiceImpl(PatternService patternService, PatternRelationDescriptorService patternRelationDescriptorService, @@ -36,16 +33,13 @@ public DesignModelServiceImpl(PatternService patternService, PatternViewDirectedEdgeRepository patternViewDirectedEdgeRepository, PatternViewUndirectedEdgeRepository patternViewUndirectedEdgeRepository, DirectedEdgeRepository directedEdgeRepository, - UndirectedEdgeReository undirectedEdgeReository) { + UndirectedEdgeReository undirectedEdgeReository, + DesignModelEdgeTypeRepository designModelEdgeTypeRepository) { this.patternService = patternService; -// this.patternRelationDescriptorService = patternRelationDescriptorService; this.designModelRepository = designModelRepository; this.designModelPatternInstanceRepository = designModelPatternInstanceRepository; this.designModelPatternEdgeRepository = designModelPatternEdgeRepository; -// this.patternViewDirectedEdgeRepository = patternViewDirectedEdgeRepository; -// this.patternViewUndirectedEdgeRepository = patternViewUndirectedEdgeRepository; -// this.directedEdgeRepository = directedEdgeRepository; -// this.undirectedEdgeReository = undirectedEdgeReository; + this.designModelEdgeTypeRepository = designModelEdgeTypeRepository; } @@ -81,6 +75,11 @@ public DesignModel getDesignModel(UUID designModelId) { } + public List getDesignModelEdgeTypes() { + return this.designModelEdgeTypeRepository.findAll(); + } + + @Override @Transactional(readOnly = true) public DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID patternInstanceId) { @@ -92,63 +91,6 @@ public DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID pa } -// @Override -// @Transactional(readOnly = true) -// public PatternView getPatternViewByUri(String uri) { -// return this.patternViewRepository.findByUri(uri) -// .orElseThrow(() -> new PatternViewNotFoundException(String.format("PatternView with URI \"%s\" not found!", uri))); -// } -// -// @Override -// @Transactional -// public PatternView updatePatternView(PatternView patternView) { -// // We just support updating fields of PatternView but we don't support updates of sub resources such as pattern edges. -// // So we ignore patterns and edges. -// if (null == patternView) { -// throw new NullPatternViewException(); -// } -// -// if (!this.patternViewRepository.existsById(patternView.getId())) { -// throw new PatternViewNotFoundException(patternView); -// } -// -// PatternView oldPatternView = this.getPatternViewById(patternView.getId()); -// -// patternView.setPatterns(oldPatternView.getPatterns()); -// patternView.setDirectedEdges(oldPatternView.getDirectedEdges()); -// patternView.setUndirectedEdges(oldPatternView.getUndirectedEdges()); -// -// return this.patternViewRepository.save(patternView); -// } -// -// @Override -// @Transactional -// public void deletePatternView(UUID patternViewId) { -// PatternView patternView = this.getPatternViewById(patternViewId); -// -// // Remove edges that are just part of pattern view -// if (null != patternView.getDirectedEdges()) { -// patternView.getDirectedEdges().forEach(patternViewDirectedEdge -> { -// if (null == patternViewDirectedEdge.getDirectedEdge().getPatternLanguage()) { -// this.directedEdgeRepository.delete(patternViewDirectedEdge.getDirectedEdge()); -// } -// }); -// } -// -// if (null != patternView.getUndirectedEdges()) { -// patternView.getUndirectedEdges().forEach(patternViewUndirectedEdge -> { -// if (null == patternViewUndirectedEdge.getUndirectedEdge().getPatternLanguage()) { -// this.undirectedEdgeReository.delete(patternViewUndirectedEdge.getUndirectedEdge()); -// } -// }); -// } -// -// this.patternViewRepository.delete(patternView); -// } -// -// // Pattern Handling - - @Override @Transactional public void addPatternInstance(UUID patternViewId, UUID patternId) { @@ -194,36 +136,6 @@ public void updatePatternInstancePosition(UUID designModelId, UUID patternInstan } -// @Override -// @Transactional(readOnly = true) -// public List getPatternsOfPatternView(UUID patternViewId) { -// return this.patternViewPatternRepository.findAllByPatternViewId(patternViewId).stream() -// .map(PatternViewPattern::getPattern) -// .collect(Collectors.toList()); -// } -// -// @Override -// @Transactional(readOnly = true) -// public Pattern getPatternOfPatternViewById(UUID patternViewId, UUID patternId) { -// PatternViewPattern patternViewPattern = this.patternViewPatternRepository.findById(new PatternViewPatternId(patternViewId, patternId)) -// .orElseThrow(() -> new PatternNotFoundException(patternViewId, patternId, PatternGraphType.PATTERN_VIEW)); -// -// return patternViewPattern.getPattern(); -// } -// -// @Override -// @Transactional -// public void removePatternFromPatternView(UUID patternViewId, UUID patternId) { -// PatternViewPatternId id = new PatternViewPatternId(patternViewId, patternId); -// if (this.patternViewPatternRepository.existsById(id)) { -// this.patternViewPatternRepository.deleteById(id); -// } else { -// throw new PatternNotFoundException(patternViewId, patternId, PatternGraphType.PATTERN_VIEW); -// } -// } -// - - // DirectedEdge Handling @Override @Transactional(readOnly = true) @@ -271,169 +183,4 @@ public void deleteEdge(UUID designModelId, UUID patternInstanceId1, UUID pattern designModelId, patternInstanceId1, patternInstanceId2 ); } - - -// @Override -// @Transactional -// public DirectedEdge createDirectedEdgeAndAddToPatternView(UUID patternViewId, AddDirectedEdgeToViewRequest request) { -// PatternView patternView = this.getPatternViewById(patternViewId); -// -// DirectedEdge directedEdge = new DirectedEdge(); -// directedEdge.setSource(this.patternService.getPatternById(request.getSourcePatternId())); -// directedEdge.setTarget(this.patternService.getPatternById(request.getTargetPatternId())); -// directedEdge.setDescription(request.getDescription()); -// directedEdge.setType(request.getType()); -// directedEdge = this.patternRelationDescriptorService.createDirectedEdge(directedEdge); -// -// PatternViewDirectedEdge patternViewDirectedEdge = new PatternViewDirectedEdge(patternView, directedEdge); -// patternViewDirectedEdge = this.patternViewDirectedEdgeRepository.save(patternViewDirectedEdge); -// -// return patternViewDirectedEdge.getDirectedEdge(); -// } -// -// @Override -// @Transactional(readOnly = true) -// public List getDirectedEdgesByPatternViewId(UUID patternViewId) { -// return this.patternViewDirectedEdgeRepository.findByPatternViewId(patternViewId).stream() -// .map(PatternViewDirectedEdge::getDirectedEdge) -// .collect(Collectors.toList()); -// } -// -// @Override -// @Transactional(readOnly = true) -// public DirectedEdge getDirectedEdgeOfPatternViewById(UUID patternViewId, UUID directedEdgeId) { -// return this.patternViewDirectedEdgeRepository.findById(new PatternViewDirectedEdgeId(patternViewId, directedEdgeId)) -// .map(PatternViewDirectedEdge::getDirectedEdge) -// .orElseThrow(() -> new DirectedEdgeNotFoundException(patternViewId, directedEdgeId, PatternGraphType.PATTERN_VIEW)); -// } -// -// @Override -// @Transactional -// public DirectedEdge updateDirectedEdgeOfPatternView(UUID patternViewId, UpdateDirectedEdgeRequest request) { -// -// PatternViewDirectedEdge patternViewDirectedEdge = this.patternViewDirectedEdgeRepository -// .findById(new PatternViewDirectedEdgeId(patternViewId, request.getDirectedEdgeId())) -// .orElseThrow(() -> new DirectedEdgeNotFoundException(patternViewId, request.getDirectedEdgeId(), PatternGraphType.PATTERN_VIEW)); -// -// DirectedEdge directedEdge = patternViewDirectedEdge.getDirectedEdge(); -// directedEdge.setType(request.getType()); -// directedEdge.setDescription(request.getDescription()); -// -// Pattern source = this.patternService.getPatternById(request.getSourcePatternId()); -// directedEdge.setSource(source); -// -// Pattern target = this.patternService.getPatternById(request.getTargetPatternId()); -// directedEdge.setTarget(target); -// -// return this.patternRelationDescriptorService.updateDirectedEdge(directedEdge); -// } -// -// @Override -// @Transactional -// public void removeDirectedEdgeFromPatternView(UUID patternViewId, UUID directedEdgeId) throws DirectedEdgeNotFoundException { -// DirectedEdge directedEdge = this.patternRelationDescriptorService.getDirectedEdgeById(directedEdgeId); -// PatternView patternView = this.getPatternViewById(patternViewId); -// PatternViewDirectedEdge patternViewDirectedEdge = this.patternViewDirectedEdgeRepository.getOne(new PatternViewDirectedEdgeId(patternViewId, directedEdgeId)); -// -// if (null != patternViewDirectedEdge) { -// this.patternViewDirectedEdgeRepository.delete(patternViewDirectedEdge); -// } else { -// throw new DirectedEdgeNotFoundException(patternView, directedEdgeId); -// } -// -// if (null == directedEdge.getPatternLanguage()) { -// // directed edge is not part of pattern language, thus remove it if it is not part of other views -// if (!this.patternViewDirectedEdgeRepository.existsByDirectedEdgeId(directedEdgeId)) { -// this.directedEdgeRepository.delete(directedEdge); -// } -// } -// } -// -// // UndirectedEdge Handling -// -// @Override -// @Transactional -// public void addUndirectedEdgeToPatternView(UUID patternViewId, UUID undirectedEdgeId) { -// PatternView patternView = this.getPatternViewById(patternViewId); -// UndirectedEdge undirectedEdge = this.patternRelationDescriptorService.getUndirectedEdgeById(undirectedEdgeId); -// -// PatternViewUndirectedEdge patternViewUndirectedEdge = new PatternViewUndirectedEdge(patternView, undirectedEdge); -// this.patternViewUndirectedEdgeRepository.save(patternViewUndirectedEdge); -// } -// -// @Override -// @Transactional -// public UndirectedEdge createUndirectedEdgeAndAddToPatternView(UUID patternViewId, AddUndirectedEdgeToViewRequest request) { -// PatternView patternView = this.getPatternViewById(patternViewId); -// -// UndirectedEdge undirectedEdge = new UndirectedEdge(); -// undirectedEdge.setP1(this.patternService.getPatternById(request.getPattern1Id())); -// undirectedEdge.setP2(this.patternService.getPatternById(request.getPattern2Id())); -// undirectedEdge.setDescription(request.getDescription()); -// undirectedEdge.setType(request.getType()); -// undirectedEdge = this.patternRelationDescriptorService.createUndirectedEdge(undirectedEdge); -// -// PatternViewUndirectedEdge patternViewUndirectedEdge = new PatternViewUndirectedEdge(patternView, undirectedEdge); -// patternViewUndirectedEdge = this.patternViewUndirectedEdgeRepository.save(patternViewUndirectedEdge); -// -// return patternViewUndirectedEdge.getUndirectedEdge(); -// } -// -// @Override -// @Transactional(readOnly = true) -// public List getUndirectedEdgesByPatternViewId(UUID patternViewId) { -// return this.patternViewUndirectedEdgeRepository.findByPatternViewId(patternViewId).stream() -// .map(PatternViewUndirectedEdge::getUndirectedEdge) -// .collect(Collectors.toList()); -// } -// -// @Override -// @Transactional(readOnly = true) -// public UndirectedEdge getUndirectedEdgeOfPatternViewById(UUID patternViewId, UUID undirectedEdgeId) { -// return this.patternViewUndirectedEdgeRepository.findById(new PatternViewUndirectedEdgeId(patternViewId, undirectedEdgeId)) -// .map(PatternViewUndirectedEdge::getUndirectedEdge) -// .orElseThrow(() -> new UndirectedEdgeNotFoundException(patternViewId, undirectedEdgeId, PatternGraphType.PATTERN_VIEW)); -// } -// -// @Override -// @Transactional -// public UndirectedEdge updateUndirectedEdgeOfPatternView(UUID patternViewId, UpdateUndirectedEdgeRequest request) { -// PatternViewUndirectedEdge edge = this.patternViewUndirectedEdgeRepository -// .findById(new PatternViewUndirectedEdgeId(patternViewId, request.getUndirectedEdgeId())) -// .orElseThrow(() -> new UndirectedEdgeNotFoundException(patternViewId, request.getUndirectedEdgeId(), PatternGraphType.PATTERN_VIEW)); -// -// UndirectedEdge undirectedEdge = edge.getUndirectedEdge(); -// undirectedEdge.setType(request.getType()); -// undirectedEdge.setDescription(request.getDescription()); -// -// Pattern p1 = this.patternService.getPatternById(request.getPattern1Id()); -// undirectedEdge.setP1(p1); -// -// Pattern p2 = this.patternService.getPatternById(request.getPattern2Id()); -// undirectedEdge.setP2(p2); -// -// return this.patternRelationDescriptorService.updateUndirectedEdge(undirectedEdge); -// } -// -// @Override -// @Transactional -// public void removeUndirectedEdgeFromPatternView(UUID patternViewId, UUID undirectedEdgeId) { -// UndirectedEdge undirectedEdge = this.patternRelationDescriptorService.getUndirectedEdgeById(undirectedEdgeId); -// PatternView patternView = this.getPatternViewById(patternViewId); -// PatternViewUndirectedEdge patternViewUndirectedEdge = this.patternViewUndirectedEdgeRepository -// .getOne(new PatternViewUndirectedEdgeId(patternViewId, undirectedEdgeId)); -// -// if (null != patternViewUndirectedEdge) { -// this.patternViewUndirectedEdgeRepository.delete(patternViewUndirectedEdge); -// } else { -// throw new UndirectedEdgeNotFoundException(patternView, undirectedEdgeId); -// } -// -// if (null == undirectedEdge.getPatternLanguage()) { -// // directed edge is not part of pattern language, thus remove it if it is not part of other views -// if (!this.patternViewUndirectedEdgeRepository.existsByUndirectedEdgeId(undirectedEdgeId)) { -// this.undirectedEdgeReository.delete(undirectedEdge); -// } -// } -// } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java index f80a947..9a9180a 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/AWSCloudFormationJsonAggregator.java @@ -16,7 +16,7 @@ public class AWSCloudFormationJsonAggregator extends ActiveMQAggregator { private static final String FILENAME = "CloudFormation-Template.json"; private static final String MIME_TYPE = "application/json"; - private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/aws-cloudformation-json/cloudformation.st"; + private static final String WRAPPER_TEMPLATE = CONCRETE_SOLUTION_REPO + "aws-cloudformation-json/cloudformation.st"; @Override @@ -28,7 +28,7 @@ public void aggregate(AggregationData aggregationData) { String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); Map templateContext = aggregationData.getTemplateContext(); - String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateUri()); String cloudFormationTemplate = extendVariables(concreteSolutionTemplate, patternInstanceId) + "\n"; diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java index f4e72ae..a58a703 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQAggregator.java @@ -12,7 +12,6 @@ @CommonsLog public abstract class ActiveMQAggregator extends AggregatorImpl { - @Override public abstract void aggregate(AggregationData aggregationData); diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java index 766eeea..48f890e 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQJavaAggregator.java @@ -13,7 +13,7 @@ public class ActiveMQJavaAggregator extends ActiveMQAggregator { private static final String FILENAME = "PatternAtlasRouteBuilder.java"; private static final String MIME_TYPE = "text/x-java"; - private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-java/camel.st"; + private static final String WRAPPER_TEMPLATE = CONCRETE_SOLUTION_REPO + "eip-activemq-java/camel.st"; private static final String TEMPLATE_KEY = "-template-jdsl"; @@ -29,7 +29,7 @@ public void aggregate(AggregationData aggregationData) { camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + TEMPLATE_KEY, "")); - String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateUri()); String idComment = "/* " + getIdentifier(aggregationData.getSource()) + " */"; if (!camelContext.toString().contains(idComment)) { diff --git a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java index 1667a06..20306b9 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/ActiveMQXMLAggregator.java @@ -15,7 +15,7 @@ public class ActiveMQXMLAggregator extends ActiveMQAggregator { private static final String FILENAME = "camel.xml"; private static final String MIME_TYPE = "text/xml"; - private static final String WRAPPER_TEMPLATE = "file:///home/marcel/Dokumente/Studium Softwaretechnik/Vorlesungen/14. Semester/Masterthesis/Pattern Atlas/concrete-solutions/eip-activemq-xml/camel.st"; + private static final String WRAPPER_TEMPLATE = CONCRETE_SOLUTION_REPO + "eip-activemq-xml/camel.st"; private static final String TEMPLATE_KEY = "-template"; @@ -31,7 +31,7 @@ public void aggregate(AggregationData aggregationData) { camelContext.append(aggregationData.getTemplateContext().getOrDefault(patternInstanceId + TEMPLATE_KEY, "")); - String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateUri()); String idComment = ""; if (!camelContext.toString().contains(idComment)) { diff --git a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java index 20ab493..34c0da0 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/AggregatorImpl.java @@ -1,11 +1,12 @@ package com.patternpedia.api.util.aggregator; -import com.patternpedia.api.entities.designmodel.AggregationData; import com.patternpedia.api.entities.designmodel.DesignModelPatternInstance; +import com.patternpedia.api.exception.AggregationException; import lombok.extern.apachecommons.CommonsLog; import org.stringtemplate.v4.ST; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.Map; @@ -16,20 +17,21 @@ @CommonsLog public abstract class AggregatorImpl implements Aggregator { - protected static final Random RANDOM = new Random(); - + protected static final String CONCRETE_SOLUTION_REPO = "https://raw.githubusercontent.com/marzn/pattern-atlas-pattern-implementations/main/"; - public abstract void aggregate(AggregationData aggregationData); + protected static final Random RANDOM = new Random(); protected static String readFile(String url) { + log.info("Read file from " + url); try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) { return reader.lines().collect(Collectors.joining("\n")); - } catch (Exception e) { - log.error(e.getMessage(), e); + } catch (IOException e) { + String errorMsg = "Failed to read file from " + url; + log.error(errorMsg); + throw new AggregationException(errorMsg); } - return null; } @@ -52,6 +54,6 @@ protected static String extendVariables(String template, String id) { protected static String getIdentifier(DesignModelPatternInstance patternInstance) { - return patternInstance.getPattern().getName().replaceAll(" ", "-").toLowerCase() + "-" + patternInstance.getPatternInstanceId().toString(); + return patternInstance.getPattern().getName().replace(" ", "-").toLowerCase() + "-" + patternInstance.getPatternInstanceId().toString(); } } diff --git a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java index c2ec4ec..0e0a982 100644 --- a/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java +++ b/src/main/java/com/patternpedia/api/util/aggregator/MessageEndpointAggregator.java @@ -22,7 +22,7 @@ public void aggregate(AggregationData aggregationData) { String patternInstanceId = sourcePattern.getPatternInstanceId().toString(); Map templateContext = aggregationData.getTemplateContext(); - String concreteSolutionTemplate = readFile(concreteSolution.getTemplateRef()); + String concreteSolutionTemplate = readFile(concreteSolution.getTemplateUri()); concreteSolutionTemplate = extendVariables(concreteSolutionTemplate, patternInstanceId); boolean isProducer = aggregationData.getTarget() == null; From 7753d9035906a0623a26cb2582faed38317f06e1 Mon Sep 17 00:00:00 2001 From: Marcel <13757952+marzn@users.noreply.github.com> Date: Sun, 1 Nov 2020 03:02:29 +0100 Subject: [PATCH 10/10] Remove unused code --- .../com/patternpedia/api/service/DesignModelService.java | 3 --- .../patternpedia/api/service/DesignModelServiceImpl.java | 7 ------- 2 files changed, 10 deletions(-) diff --git a/src/main/java/com/patternpedia/api/service/DesignModelService.java b/src/main/java/com/patternpedia/api/service/DesignModelService.java index 3d9d12b..2fd527c 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelService.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelService.java @@ -1,6 +1,5 @@ package com.patternpedia.api.service; -import com.patternpedia.api.entities.Pattern; import com.patternpedia.api.entities.designmodel.DesignModel; import com.patternpedia.api.entities.designmodel.DesignModelEdgeType; import com.patternpedia.api.entities.designmodel.DesignModelPatternEdge; @@ -25,8 +24,6 @@ public interface DesignModelService { DesignModelPatternInstance getPatternInstance(UUID designModelId, UUID patternInstanceId); - void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern); - void updatePatternInstancePosition(UUID designModelId, UUID patternInstanceId, Double x, Double y); List getEdges(UUID designModelId); diff --git a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java index 9b2df74..301337f 100644 --- a/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/DesignModelServiceImpl.java @@ -112,13 +112,6 @@ public void deletePatternInstance(UUID designModelId, UUID patternInstanceId) { } - @Override - @Transactional - public void updatePatternInstance(UUID designModelId, UUID patternInstanceId, Pattern pattern) { -// List patternList = this.designModelPatternInstanceRepository.findTopByDesignModel_IdAndPatternInstanceId(patternInstanceId); - } - - @Override @Transactional public void updatePatternInstancePosition(UUID designModelId, UUID patternInstanceId, Double x, Double y) {