Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
Feat/multiple ldes websocket (#24)
Browse files Browse the repository at this point in the history
* feat: zoom buttons styled + knowledgegraph set right

* feat: slider + buttons styled + global header + right fonts used + margins added

* feat: wrong placed scoped placed on a styling block

* feat: init of modals and checkboxtiles

* feat: z-stack bug fixed + checkboxtile finished

* Feat: Add membercounter (#19)

Co-authored-by: WouterLefever <wouter.lefever@hotmail.com>

* fix: removal of member on map resolved + addition of styling of MemberCounter

* Feat: Add linechart

* Feat: minor

* feat: polygon styling

* feat: legend styled

* feat: minor update IngestedMemberDto

* feat: Add collection as field

* feat: add collection to member

* feat: add collection to in rectangle

* feat: fix tests

* WIP

* WIP

* WIP

* custom code

* fix: set broken test to disabled

* custom code

* custom code

* feat: markers styled with flanders icon + icon grows when clicked

* fix: broken tests repaired

* WIP: added logic to the checkbox tiles

* feat: layers are added/removed based on checkbox state

* chore: update page title and favicon

* WIP: custom icon for clusters

* feat: cluster icons customized

* feat: zoom buttons styled + knowledgegraph set right

* temp

* feat: unsubscribe websocket client on different ldes

* feat: add multiple stream logic for updates

* feat: add multiple stream logic for updates

* feat: first attempt to dockerize

* feat: fixes for dockerizing

---------

Co-authored-by: Wouter Lefever <wouter.lefever@cegeka.com>
Co-authored-by: WouterLefever <wouter.lefever@hotmail.com>
Co-authored-by: pj-cegeka <pieterjan.livens@cegeka.com>
Co-authored-by: Jan Robert <jan.robert@cegeka.com>
  • Loading branch information
5 people authored Oct 11, 2023
1 parent 8a8d990 commit 0d94d74
Show file tree
Hide file tree
Showing 105 changed files with 2,457 additions and 338 deletions.
10 changes: 10 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
Expand Down Expand Up @@ -117,6 +121,11 @@
<artifactId>rdf4j-client</artifactId>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.16.1</version>
</dependency>

<!-- TESTING -->
<dependency>
Expand Down Expand Up @@ -233,6 +242,7 @@
<directory>../frontend/target/dist</directory>
<includes>
<include>assets/</include>
<include>assets/svgs/</include>
<include>index.html</include>
<include>favicon.ico</include>
</includes>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class Application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@

@Configuration
public class EventStreamConfig {
private String name;
private String memberType;
private String timestampPath;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getMemberType() {
return memberType;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.exceptions;

public class MembertypeException extends RuntimeException{
private final String membertype;
private final String member;

public MembertypeException(String membertype, String member) {
this.membertype = membertype;
this.member = member;
}

@Override
public String getMessage() {
return "Member " + member + " was not of expected type " + membertype;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.exceptions;

public class MissingCollectionException extends RuntimeException{
private final String collectionName;

public MissingCollectionException(String collectionName) {
this.collectionName = collectionName;
}

@Override
public String getMessage() {
return "Eventstream with name " + collectionName + " could not be found.";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import be.informatievlaanderen.vsds.demonstrator.member.application.valueobjects.IngestedMemberDto;
import be.informatievlaanderen.vsds.demonstrator.member.application.valueobjects.MemberDto;
import be.informatievlaanderen.vsds.demonstrator.member.rest.dtos.LineChartDto;
import org.locationtech.jts.geom.Geometry;

import java.time.LocalDateTime;
Expand All @@ -10,7 +11,12 @@
public interface MemberService {
void ingestMember(IngestedMemberDto ingestedMemberDto);

List<MemberDto> getMembersInRectangle(Geometry rectangleGeometry, LocalDateTime timestamp, String timePeriod);
List<MemberDto> getMembersInRectangle(Geometry rectangleGeometry, String collectionName, LocalDateTime timestamp, String timePeriod);

MemberDto getMemberById(String memberId);

long getNumberOfMembers();
long getNumberOfMembersByCollection(String collection);

LineChartDto getLineChartDtos();
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.services;

import be.informatievlaanderen.vsds.demonstrator.member.application.config.EventStreamConfig;
import be.informatievlaanderen.vsds.demonstrator.member.application.config.StreamsConfig;
import be.informatievlaanderen.vsds.demonstrator.member.application.exceptions.InvalidGeometryProvidedException;
import be.informatievlaanderen.vsds.demonstrator.member.application.exceptions.ResourceNotFoundException;
import be.informatievlaanderen.vsds.demonstrator.member.application.valueobjects.IngestedMemberDto;
import be.informatievlaanderen.vsds.demonstrator.member.application.valueobjects.MemberDto;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.valueobjects.Dataset;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.valueobjects.HourCount;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.valueobjects.LineChart;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.entities.Member;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.repositories.MemberRepository;
import be.informatievlaanderen.vsds.demonstrator.member.rest.MemberExceptionHandler;
import be.informatievlaanderen.vsds.demonstrator.member.rest.websocket.WebSocketConfig;
import be.informatievlaanderen.vsds.demonstrator.member.rest.dtos.LineChartDto;
import be.informatievlaanderen.vsds.demonstrator.member.rest.websocket.MessageController;
import org.locationtech.jts.geom.Geometry;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.FactoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.wololo.jts2geojson.GeoJSONWriter;
import be.informatievlaanderen.vsds.demonstrator.member.rest.websocket.MessageController;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.NoSuchElementException;

@Service
public class MemberServiceImpl implements MemberService {
Expand All @@ -41,9 +43,9 @@ public MemberServiceImpl(MemberRepository repository, StreamsConfig streams, Mes
@Override
public void ingestMember(IngestedMemberDto ingestedMemberDto) {
try {
Member member = ingestedMemberDto.getMemberGeometry(streams.getStreams());
Member member = ingestedMemberDto.getMember(streams.getStreams());
repository.saveMember(member);
messageController.send(new MemberDto(member.getMemberId(), geoJSONWriter.write(member.getGeometry()), member.getTimestamp()));
messageController.send(new MemberDto(member.getMemberId(), geoJSONWriter.write(member.getGeometry()), member.getTimestamp()), ingestedMemberDto.getCollection());

log.info("new member ingested");
} catch (FactoryException | TransformException e) {
Expand All @@ -52,9 +54,9 @@ public void ingestMember(IngestedMemberDto ingestedMemberDto) {
}

@Override
public List<MemberDto> getMembersInRectangle(Geometry rectangleGeometry, LocalDateTime timestamp, String timePeriod) {
public List<MemberDto> getMembersInRectangle(Geometry rectangleGeometry, String collectionName, LocalDateTime timestamp, String timePeriod) {
var duration = Duration.parse(timePeriod).dividedBy(2);
return repository.getMembersByGeometry(rectangleGeometry, timestamp.minus(duration), timestamp.plus(duration))
return repository.getMembersByGeometry(rectangleGeometry, collectionName, timestamp.minus(duration), timestamp.plus(duration))
.stream()
.map(memberGeometry -> new MemberDto(memberGeometry.getMemberId(), geoJSONWriter.write(memberGeometry.getGeometry()), memberGeometry.getTimestamp()))
.toList();
Expand All @@ -66,4 +68,33 @@ public MemberDto getMemberById(String memberId) {
.map(memberGeometry -> new MemberDto(memberGeometry.getMemberId(), geoJSONWriter.write(memberGeometry.getGeometry()), memberGeometry.getTimestamp()))
.orElseThrow(() -> new ResourceNotFoundException("Member", memberId));
}

@Override
public long getNumberOfMembers() {
return repository.getNumberOfMembers();
}

@Override
public long getNumberOfMembersByCollection(String collection) {
return repository.getNumberOfMembersByCollection(collection);
}

@Override
public LineChartDto getLineChartDtos() {
LocalDateTime startDate = LocalDateTime.now().minusDays(7);
LineChart lineChart = new LineChart(startDate);

streams
.getStreams()
.stream()
.map(EventStreamConfig::getName)
.map(collection -> {
long numberOfMembers = getNumberOfMembersByCollection(collection);

List<Member> membersAfterLocalDateTime = repository.findMembersByCollectionAfterLocalDateTime(collection,startDate);
return new Dataset(collection, numberOfMembers - membersAfterLocalDateTime.size(), new HourCount(membersAfterLocalDateTime));
}).forEach(lineChart::addDataSet);

return new LineChartDto(lineChart.getLabels(), lineChart.getDatasetDtos());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.services;

import org.apache.jena.rdf.model.Model;

public interface MemberValidator {
void validate(Model member, String collectionName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.services;

import be.informatievlaanderen.vsds.demonstrator.member.application.config.EventStreamConfig;
import be.informatievlaanderen.vsds.demonstrator.member.application.config.StreamsConfig;
import be.informatievlaanderen.vsds.demonstrator.member.application.exceptions.MembertypeException;
import be.informatievlaanderen.vsds.demonstrator.member.application.exceptions.MissingCollectionException;
import org.apache.jena.rdf.model.Model;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;

@Service
public class MemberValidatorImpl implements MemberValidator {

private final StreamsConfig streams;

public MemberValidatorImpl(StreamsConfig streams) {
this.streams = streams;
}

@Override
public void validate(Model member, String collectionName) {
Optional<EventStreamConfig> streamConfig = streams.getStreams().stream().filter(streams -> Objects.equals(streams.getName(), collectionName)).findFirst();
if(streamConfig.isEmpty()) {
throw new MissingCollectionException(collectionName);
} else if (!testMembertype(member, streamConfig.get().getMemberType())) {
throw new MembertypeException("todo", streamConfig.get().getMemberType());
}

}

private boolean testMembertype(Model member, String memberType) {
//TODO
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,34 @@
import static org.apache.jena.rdf.model.ResourceFactory.createResource;

public class IngestedMemberDto {
private final String collection;
private final Model model;

public IngestedMemberDto(Model model) {
public IngestedMemberDto(String collection, Model model) {
this.collection = collection;
this.model = model;
}

public Model getModel() {
return model;
}

public Member getMemberGeometry(List<EventStreamConfig> streams) throws FactoryException, TransformException {
Geometry geometry = getMemberGeometry();
public Member getMember(List<EventStreamConfig> streams) throws FactoryException, TransformException {
Geometry geometry = getMember();
String memberId = getMemberId(streams);
String timestampString = (String) getTimestampPath(streams);
LocalDateTime timestamp;
if (timestampString.contains("Z")) {
if (timestampString.contains("Z") || timestampString.contains("+")) {
timestamp = ZonedDateTime.parse(timestampString).toLocalDateTime();
} else {
timestamp = LocalDateTime.parse(timestampString);
}
return new Member(memberId, geometry, timestamp);
return new Member(memberId, collection, geometry, timestamp);
}

private Geometry getMemberGeometry() throws FactoryException, TransformException {
private Geometry getMember() throws FactoryException, TransformException {
List<RDFNode> wktNodes = model.listObjectsOfProperty(model.createProperty("http://www.opengis.net/ont/geosparql#asWKT")).toList();
if(wktNodes.isEmpty()) {
if (wktNodes.isEmpty()) {
throw new NoGeometryProvidedException();
} else {
RDFNode wktObject = wktNodes.get(0);
Expand All @@ -58,6 +60,7 @@ private Geometry getMemberGeometry() throws FactoryException, TransformException
private Statement getMemberProperty(List<EventStreamConfig> streams, Function<EventStreamConfig, Selector> createSelector) {
return Iterables.getOnlyElement(streams
.stream()
.filter(stream -> stream.getName().equals(collection))
.map(stream -> model.listStatements(createSelector.apply(stream)))
.map(StmtIterator::nextStatement)
.toList());
Expand All @@ -75,4 +78,8 @@ private Object getTimestampPath(List<EventStreamConfig> streams) {
.asLiteral().getString();

}

public String getCollection() {
return collection;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package be.informatievlaanderen.vsds.demonstrator.member.custom;

import be.informatievlaanderen.vsds.demonstrator.member.application.valueobjects.IngestedMemberDto;
import jakarta.annotation.PostConstruct;
import org.apache.jena.datatypes.TypeMapper;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Statement;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.jena.rdf.model.ResourceFactory.*;

@Component
public class MeetPuntRepository {

private final Map<String, Statement> meetpuntLocaties;

public MeetPuntRepository() {
this.meetpuntLocaties = new HashMap<>();
}

@PostConstruct
private void initializeMeetpunten() {
final int size = 16 * 1024 * 1024;
final ExchangeStrategies strategies = ExchangeStrategies.builder()
.codecs(codecs -> codecs.defaultCodecs().maxInMemorySize(size))
.build();
String content = WebClient.builder().exchangeStrategies(strategies).baseUrl("http://miv.opendata.belfla.be/miv/configuratie/xml").build().get().retrieve()
.bodyToMono(String.class).block();
Document doc = Jsoup.parse(content, "", Parser.xmlParser());
for (Element e : doc.select("meetpunt")) {
String meetpuntId = e.attr("unieke_id");
String wkt = "POINT (" + e.select("lengtegraad_EPSG_4326").get(0).text().replace(",", ".") + " " + e.select("breedtegraad_EPSG_4326").get(0).text().replace(",", ".") + ")";

meetpuntLocaties.put(meetpuntId, createStatement(createResource("http://custom"), createProperty("http://www.opengis.net/ont/geosparql#asWKT"), createTypedLiteral(wkt, TypeMapper.getInstance().getTypeByName("http://www.opengis.net/ont/geosparql#wktLiteral"))));
}
}


public List<Statement> get(String s) {
return List.of(meetpuntLocaties.get(s));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

public class Member {
private final String memberId;
private final String collection;
private final Geometry geometry;
private final LocalDateTime timestamp;

public Member(String memberId, Geometry geometry, LocalDateTime timestamp) {
public Member(String memberId, String collection, Geometry geometry, LocalDateTime timestamp) {
this.memberId = memberId;
this.collection = collection;
this.geometry = geometry;
this.timestamp = timestamp;
}
Expand All @@ -28,6 +30,10 @@ public LocalDateTime getTimestamp() {
return timestamp;
}

public String getCollection() {
return collection;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -42,4 +48,5 @@ public boolean equals(Object o) {
public int hashCode() {
return memberId.hashCode();
}

}
Loading

0 comments on commit 0d94d74

Please sign in to comment.